文章归档

tc: htb分层令牌桶

分层令牌桶是tc中最强大的工具,没有之一,htb使用令牌桶的原理,结合分类、过滤器,可以实现非常复杂的流控,更重要的是,htb支持流量租借,当孩子节点流量不足或者也叫带宽不足但是父亲节点流量仍有冗余的情况下,孩子节点通过超发模式使用父亲的带宽资源

1. 令牌桶

令牌桶是HTB的基础,HTB主要是在令牌桶的原理之上支持了分层机制

令牌桶算法是网络流量整形和速率限制中最常使用的一种算法,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送

»» 继续阅读全文

使用tc实现container级别的流控

关于tc的用法:http://pipul.org/2015/07/queueing-disciplines-for-bandwidth-management/

流控需要解决两个非常核心的问题:

  • 资源配额
  • 超发

超发和配额的区别在于,配额是分配给你能够保证你真实拥有的资源,当你需要使用就能立即能用的资源,能够完全独立支配而不受其他container的干扰。但是配额的问题在于很容易造成资源浪费或者无法应对峰值负载。因为流量是很容易具备时段性的

超发当你资源不足而别人资源冗余的时候,你能够使用别人的空闲资源

从业务方角度来看,这是一个成本控制的问题,从平台方的角度来看,这是一个提升整体的资源利用率的问题。

»» 继续阅读全文

基于veth的网络虚拟化

关于Network Namespace的原理不再详解,请直接移步:Namespaces in operation, part 7: Network namespaces 

但是需要注意的,这个文章里network namespace操作所使用的是最新内核&操作系统提供的非常便利的ip netns工具,不过这些工具在低版本的操作系统上都是不提供的。如果真的需要使用network namespace,最好通过netlink编程的方式来实现,直接基于操作系统调用来完成所有设备的虚拟化工作 我们知道在clone进程的时候使用CLONE_NEWNET参数可以创建一个新的独立的network namespace,但是光有这个还是远远不够的,所有网络设备都没有初始化、没启动,这个时候的容器就是一个完全的离线的容器,不在任何网络里,也访问不了任何网络。 

为了让容器独立能够与外网接通,我们需要创建并初始化一些设备,让容器内的网络和外网互通,veth是一种比较简单的方案

»» 继续阅读全文

一种更快速的本地端口存活检测方法

本地端口存活检测通常有两种做法:

  1. netstat
  2. nmap & telnet

netstat的问题在于,它的原理是扫描整个/proc/net/tcp、/proc/net/tcp6文件,如果本机链接数非常多(不一定是正常的连接,也可能是异常连接,例如处于TIME_WAIT状态或者FIN状态)的情况下,/proc/net/tcp文件会非常大,扫描几个小时也扫不完,而且扫描/proc/net/tcp文件这个过程是属于内核态的,可能会hang住

另外nmap虽然是一个很成熟标准的端口存活检测机制,nmap的方式是通过连接端口来判断的,这种侵入式方法的问题在于,对于一些实现的不是很健壮的程序,可能会因此挂掉。

»» 继续阅读全文

tc:linux流量控制

http://lartc.org

1. Simple, classless Queueing Disciplines 1.1 pfifo_fast

This queue is, as the name says, First In, First Out, which means that no packet receives special treatment. At least, not quite. This queue has 3 so called ’bands’. Within each band, FIFO rules apply. However, as long as there are packets waiting in band 0, band 1 won’t be processed. Same goes for band 1 and band 2.

The kernel honors the so called Type of Service flag of packets, and takes care to insert ’minimum delay’ packets in band 0.

Do not

»» 继续阅读全文

tcp hangle算法

默认socket是开启nagle特性的,该特性主要用于提升网卡的吞吐量,但会增加小包的传输时延。对于一些时延敏感的通信,需要关闭nagle算法:

int flags = 1; rc = setsockopt (rs->ss_fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags));

内核会通过以下调用栈来设置socket的nagle特性:

setsockopt()    // net/socket.c tcp_setsockopt() // net/ipv4/tcp.c

/* * Socket option code for TCP. */ static int do_tcp_setsockopt(struct sock *sk, int level, // net/ipv4/tcp.c int optname, char __user *optval, unsigned int optlen) { //... switch (optname) { case TCP_NODELAY: if (val) { /* TCP_NODELAY is weaker than TCP_CORK, so that * this option on corked socket is remembered, but * it is not activated until cork is cleared. * * However, when TCP_NODELAY is set we make * an explicit push, which

»» 继续阅读全文

select的正确用法

在linux平台上主要头文件如下: /usr/include/sys/select.h /usr/include/bits/select.h

select 相关的几个API如下:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set);

参考man-pages,其中nfds的解释是:

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

这里的nfds不表示fd_set的大小(实际上表示不了),而是指 the highest-numbered file descriptor + 1, the highest-numbered file descriptor也就是fd_set里fd的最大值。而且这个最大值不能超过 FD_SETSIZE

An fd_set is a fixed size buffer. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in undefined behavior.

至于为什么不能超过FD_SETSIZE,主要是因为fd_set是一个大小固定的bitmap,而这个bitmap的大小是通过FD_SETSIZE计算出来的。对于大于或者等于FD_SETSIZE的fd,FD_SET非法修改了不属于自己的内存。

所以每次FD_SET的时候都应该检查fd是否合法。

tcp缓冲区大小不对称

今天写单元测试时发现setsockopt/getsockopt在设置SO_SNDBUF/SO_RCVBUF参数时不对应,getsockopt拿到的并不是setsockopt时的值 下面代码可以说明这个问题:

on = 1024; BUG_ON(tcp_setopt(sfd, TP_NOBLOCK, &on, sizeof(on))); BUG_ON(tcp_getopt(sfd, TP_NOBLOCK, &on, &optlen)); BUG_ON(on != 1024);

内核最终设置的值会发生变化,例如可能double,等等,redhat上的BUG反映:https://bugzilla.redhat.com/show_bug.cgi?id=170694 我的内核版本是:Centos 6.5 2.6.32-431.5.1.el6.x86_64 #1 SMP 翻了一下内核源码,linux-2.6.32-358.6.2.el6/net/core/

/* * This is meant for all protocols to use and covers goings on * at the socket level. Everything here is generic. */ int sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { // ... case SO_SNDBUF: /* Don't error on this BSD doesn't and if you think about it this is right. Otherwise apps have to play 'guess the biggest size'

»» 继续阅读全文

多进程共享socket之close调用

当父子进程共享一个socket描述符时,如果其中一个进程执行close调用,那会不会发送FIN包,进而影响另一个进程的其他相关操作?只会减少引用计数,没什么其他的操作。

看下源码,可以顺着以下的调用栈看:

close ------------ open.c __close_fd ---- fs/file.c filp_close ---------- fs/open.c fput ------ fs/file_table.c __fput ---------- fs/file_table.c (the last op)

首先socket描述符本身也属于Unix文件的一种,其文件相关的file_operations实现在net/socket.c源文件,如下:

/* * Socket files have a set of 'special' operations as well as the generic file ones. * These don't appear in the operation structures but are done directly via the socketcall() * multiplexor. */ static const struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, .aio_write = sock_aio_write, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_sock_ioctl, #endif .mmap = sock_mmap, .open = sock_no_open, /* special open code to disallow open

»» 继续阅读全文

tcp拥塞控制

Transmission of packets from TCP sender is restricted by the congestion window. On reception of Ack TCP sender may increase the congestion window. At the start of TCP connection sender is in slow start wherein congestion window starts growing exponentially from a small value (typically 2) till a threshold is reached. After reaching the threshold TCP enters congestion avoidance phase and increments the congestion window linearly.

Congestion avoidance state machine

Event such as arrival of dupack, SACK and Explicit congestion notification indicate a possibility of congestion due to excess transmission of packets by the sender. These events are processed through

»» 继续阅读全文

第 1 页,共 2 页12