ftp如何做到精确限速?

发布于 2022-09-06 22:09:00 字数 1731 浏览 21 评论 0

需求:在线上集群的某一台机器部署ftp服务端,其他机器通过ftp客户端每天定时get数据,由于集群上跑了很多服务,为了不影响其他服务需要对ftp进行限速

现方案:使用python的pyftplib搭建了简单的ftp服务端,客户端使用Linux NetKit的ftp,python的限速代码片段:

    # limit for bandwidth
    dtp_handler = ThrottledDTPHandler
    dtp_handler.read_limit = 30 * 1024 * 1024  # 30 MB/s
    dtp_handler.write_limit = 30 * 1024 * 1024  # 30 MB/s

    # Instantiate FTP handler class
    handler = FTPHandler
    handler.authorizer = authorizer
    handler.dtp_handler = dtp_handler

目前问题:通过网络监控并没有发现把网卡打满的情况(CPU、内存、磁盘IO也都远没有达到报警阈值),但集群上部署的其他服务却出现了大量的延时报警,分析了一下原因,可能是由于ftp限速和网络监控都是基于秒级的,但服务监控是基于毫秒级的,ftp服务端在1秒内达到了限速阈值就不再处理了,但在达到阈值的这短时间内却已经占用了大量带宽,从而影响了其他进程,pyftplib实现限速的代码片段:

def _throttle_bandwidth(self, len_chunk, max_speed):
        """A method which counts data transmitted so that you burst to
        no more than x Kb/sec average.
        """
        self._datacount += len_chunk
        if self._datacount >= max_speed:
            self._datacount = 0
            now = timer()
            sleepfor = (self._timenext - now) * 2
            if sleepfor > 0:
                # we've passed bandwidth limits
                def unsleep():
                    if self.receive:
                        event = self.ioloop.READ
                    else:
                        event = self.ioloop.WRITE
                    self.add_channel(events=event)

                self.del_channel()
                self._cancel_throttler()
                self._throttler = self.ioloop.call_later(
                    sleepfor, unsleep, _errback=self.handle_error)
            self._timenext = now + 1

请问:
1、我分析的原因是否正确?如果不正确问题还可能出在哪?
2、如果正确,有没有简单的方式或成熟的解决方案可实现更精确的限速?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

瞎闹 2022-09-13 22:09:00

对比了一下scp,可以做到更精细的限速(使用了nanosleep),但由于集群上用了kerberos做认证,ssh比较麻烦,不知道有没有人了解过其他ftp的框架或开源产品,可以做到nanosec级限速(不限语言)?要是没有就只能改改开源产品的源码了,以下是scp的限速源码片段:

void
bandwidth_limit(struct bwlimit *bw, size_t read_len)
{
    u_int64_t waitlen;
    struct timespec ts, rm;

    if (!timerisset(&bw->bwstart)) {
        gettimeofday(&bw->bwstart, NULL);
        return;
    }

    bw->lamt += read_len;
    if (bw->lamt < bw->thresh)
        return;

    gettimeofday(&bw->bwend, NULL);
    timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
    if (!timerisset(&bw->bwend))
        return;

    bw->lamt *= 8;
    waitlen = (double)1000000L * bw->lamt / bw->rate;

    bw->bwstart.tv_sec = waitlen / 1000000L;
    bw->bwstart.tv_usec = waitlen % 1000000L;

    if (timercmp(&bw->bwstart, &bw->bwend, >)) {
        timersub(&bw->bwstart, &bw->bwend, &bw->bwend);

        /* Adjust the wait time */
        if (bw->bwend.tv_sec) {
            bw->thresh /= 2;
            if (bw->thresh < bw->buflen / 4)
                bw->thresh = bw->buflen / 4;
        } else if (bw->bwend.tv_usec < 10000) {
            bw->thresh *= 2;
            if (bw->thresh > bw->buflen * 8)
                bw->thresh = bw->buflen * 8;
        }

        TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
        while (nanosleep(&ts, &rm) == -1) {
            if (errno != EINTR)
                break;
            ts = rm;
        }
    }

    bw->lamt = 0;
    gettimeofday(&bw->bwstart, NULL);
}

最终使用了vsftpd,看过源码用的是nanosleep

电影里的梦 2022-09-13 22:09:00

有可能你的方向找错了,你可以尝试一下限制某个IP(你获取数据的服务器IP)访问你服务器的下载速度
可以使用iptables,参考
https://blog.csdn.net/dszgf57...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文