centos 7 安装HAproxy四层TCP负载均衡配置及测试

未分类

haproxy负载均衡166.110.110.100
后端服务器1 166.110.110.1
后端服务器2 166.110.110.2

--------------------------------------------------centos 7 处理----------------------------------------------------
关闭SELinux
vi /etc/selinux/config
#SELINUX=enforcing #注释掉
#SELINUXTYPE=targeted #注释掉
SELINUX=disabled #增加
:wq!  #保存退出
setenforce 0 #使配置立即生效

关闭centos 7的防火墙(仅在测试的时候)
systemctl stop firewalld.service
systemctl disable firewalld.service
--------------------------------------------------haproxy安装----------------------------------------------------
yum install wget gcc -y && wget -c --no-check-certificate https://src.fedoraproject.org/repo/pkgs/haproxy/haproxy-1.8.12.tar.gz && tar -xvf haproxy-1.8.12.tar.gz && cd haproxy-1.8.12

groupadd haproxy #添加haproxy组
useradd -g haproxy haproxy -s /bin/false #创建nginx运行账户haproxy并加入到haproxy组,不允许haproxy
--------------------------------------------------haproxy配置----------------------------------------------------
vi /etc/haproxy/haproxy.cfg

修改为以下配置
#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------

#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
listen admin_stats  
        bind 127.0.0.1:1080               #监听端口  
        mode http                       #http的7层模式  
        option httplog                  #采用http日志格式  
        #log 127.0.0.1 local0 err  
        maxconn 10  
        stats refresh 30s               #统计页面自动刷新时间  
        stats uri /stats                #统计页面url  
        stats realm Proxy Haproxy  #统计页面密码框上提示文本  
        stats auth admin:admin          #统计页面用户名和密码设置  
        stats hide-version              #隐藏统计页面上HAProxy的版本信息  


listen test1  
        bind 0.0.0.0:80  
        mode tcp
        balance leastconn
        #maxconn 40000  
        #log 127.0.0.1 local0 debug  
        server s1 166.110.110.1:80  
        server s2 166.110.110.2:80
------------------------------------------------------------------------------------------------------
centos7下haproxy启动停止重启重载状态等控制命令
systemctl (start, stop, restart, try-restart, reload, force-reload, status) haproxy.service

haproxy web监控信息166.110.110.100为haproxy安装所在服务器IP
http://166.110.110.100:1080/status
-----------------------------后端安装lighttpd 作为测试用----------------------------------------------
systemctl stop firewalld.service
systemctl disable firewalld.service
关闭SELinux
vi /etc/selinux/config
将SELINUX=enforcing改为SELINUX=disabled

安装
yum install -y epel-release gcc gcc-c++ autoconf automake  zlib zlib-devel pcre-devel zip unzip libtool bzip2-* && yum install -y lighttpd && systemctl enable lighttpd

编辑配置文件关闭ipv6
vi /etc/lighttpd/lighttpd.conf
注释掉ipv6

启动服务器
systemctl restart lighttpd.service

默认目录及首页
/var/www/lighttpd/index.html

对两个index.html进行修改进行区别
后端第一个服务器
echo "<h1>this is upstream server 1" >> /var/www/lighttpd/index.html

后端第二个服务器
echo "<h1>this is upstream server 2" >> /var/www/lighttpd/index.html

访问haproxy所在服务器IP或者解析的域名刷新试试

-----------------------------Haproxy 负载均衡的8种算法----------------------------------------
balance roundrobin # 轮询,软负载均衡基本都具备这种算法

balance static-rr # 根据权重,建议使用

balance leastconn # 最少连接者先处理,建议使用

balance source # 根据请求源IP,建议使用

balance uri # 根据请求的URI

balance url_param,# 根据请求的URl参数'balance url_param' requires an URL parameter name

balance hdr(name) # 根据HTTP请求头来锁定每一次HTTP请求

balance rdp-cookie(name) # 根据据cookie(name)来锁定并哈希每一次TCP请求

nginx端口映射tcp

添加到

/etc/nginx/nginx.conf

添加内容:

stream {
    upstream ssr {
        hash $remote_addr consistent;
        server 127.0.0.1:31905 weight=5 max_fails=3 fail_timeout=30s;
    }
    server {
       listen 4008;
       proxy_connect_timeout 1s;
       proxy_timeout 3s;
       proxy_pass ssr;
    }
}

监听4008,映射到127.0.0.1:31905,名字ssr。

haproxy TCP源端口耗尽问题

此文基本是翻译aloha的一篇文档,本人实际使用情况遇到的问题类似,但不是MySQL。

[2017.01.12 增补] 1.7版的haproxy开启了IP_BIND_ADDRESS_NO_PORT支持 ,即可以复用source port,这样可以从更基础的内核层面解决这个问题,唯一不足是需要将内核升级到4.2以上版本才可以。
参考:
http://www.haproxy.org/download/1.7/src/CHANGELOG
https://kernelnewbies.org/Linux_4.2#head-8ccffc90738ffcb0c20caa96bae6799694b8ba3a

环境描述

小公司,一个比较繁忙的PHP/MySQL构建的站点。
前端使用haproxy做负载均衡,后端web server连接MySQL数据库。
MySQL做了主从复制,前端PHP代码做了读写分离。
MySQL Master负责写入请求和一小部分读请求,MySQL Slave负责响应读请求。
另一个haproxy作为MySQL的反向代理。

拓扑图

未分类

问题描述

在请求很少的时候,工作得非常好。但当MySQL上的请求压力增大(2~3K次/秒)的时候,haproxy的本地端口耗尽。日志中报大量health check SOCKERR错误。

原因分析

haproxy作为反向代理,会使用自己的IP地址作为源地址连接后端的MySQL服务器。
根据TCP协议,无论任何类型操作系统都只能拥有64K个左右的源TCP端口,用于向外发起TCP连接。
一旦”srcIP:port => dstIP:port”建立,这个源端口将不能被重用于其它连接。
当前的MySQL Client Lib关闭连接时的操作序列如下:

Mysql Client ==> "QUIT" sequence ==> Mysql Server 
Mysql Client ==> FIN ==> MySQL Server 
Mysql Client <== FIN ACK <== MySQL Server 
Mysql Client ==> ACK ==> MySQL Server

这时候MySQL Client会进入2MSL状态,时间2分钟。
那么什么是2MSL状态呢?请看下图,这是关于TCP关闭连接时的握手序列:

未分类

上边TCP状态图中有一个TIME_WAIT状态,就是所谓的2MSL状态。
MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。
MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒。
因而,TIME_WAIT状态一般维持在1-4分钟。
该状态是为了可靠地实现TCP全双工连接的终止,保证在tcp客户端发给tcp服务端的最后一个ACK能顺利到达。
若没有TIME_WAIT状态,tcp客户端将直接进入CLOSED状态。
如果tcp客户端直接进入CLOSED状态,那么由于IP协议的不可靠性或者是其它网络原因,导致tcp服务端没有收到tcp客户端最后回复的ACK。那么tcp服务端就会在超时之后继续发送FIN,此时由于tcp客户端已经CLOSED了,就找不到与重发的FIN对应的连接,最后tcp服务端就会收到 RST而不是ACK,tcp服务端就会以为是连接错误把问题报告给高层协议。
这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。
所以,tcp客户端不是直接进入CLOSED状态,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。

这里有2点需要强调一下:

1、对于tcp请求来说,tcp的客户端服务端概念和http的不同,请求双方,哪边关闭请求,哪边就是tcp客户端,另一边就为服务端。请不要与MySQL Client和MySQL Server混淆起来。
2、tcp的一个链接由4个值确定,源ip、源端口、目标ip、目标地址。

参考:http://omnitraining.net/networking-101/98-networking-101-understanding-tcp-part-2
“There is no way for the person who sent the first FIN to get an ACK back for that last ACK. You might want to reread that now. The person that initially closed the connection enters the TIME_WAIT state; in case the other person didn’t really get the ACK and thinks the connection is still open. Typically, this lasts one to two minutes.”

根据上述的论述,如果一个源端口在2分钟内不能再次使用,则超过534个/秒的MySQL Client请求将会耗尽其本地TCP源端口。
64000 (可用端口) / 120 (2分钟,即120秒) = 533.333.

因为haproxy作为反向代理,会将所有MySQL请求转发给MySQL Server,因此haproxy会比MySQL Client更快的耗尽本地TCP源端口!!

但是如果MySQL Client和MySQL Server在同一台主机上,使用looback接口通信,则MySQL关闭序列是一个相对”干净”的序列:

Mysql Client ==> "QUIT" sequence ==> Mysql Server
Mysql Client <== FIN <== MySQL Server 
Mysql Client ==> FIN ACK ==> MySQL Server 
Mysql Client <== ACK <== MySQL Server

但在非loopback接口上则不是!因此如果要解决这个问题,需要MySQL的开发者修改他们的代码……
那么是不是完全没有办法呢?也不是,请向下看。

解决方案

1、增加本地端口范围
对于单一的dstIP:port,可用的源端口默认是28K左右,可以用如下命令查看当前值:

[haproxy ~]# sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768 61000

增加到64K个源端口

[haproxy ~]# vi /etc/sysctl.conf
net.ipv4.ip_local_port_range = 1025 65000

2、允许处于TIME_WAIT状态的源端口重用

[haproxy ~]# vi /etc/sysctl.conf
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1

3、使用多个IP连接单一dstIP:port,并让haproxy来管理源端口
配置示例:

....
server mysql1     10.0.0.1:3306 check source 10.0.0.100:1025-65000
server mysql1_bis 10.0.0.1:3306 check source 10.0.0.101:1025-65000
....

经过测试,如果不让haproxy管理源端口,则4个源IP地址最多管理不超过80K个TIME_WAIT连接。
但是haproxy管理源端口可以达到170K+个TIME_WAIT连接!!!

4、使用memcached和MySQL persistant connections

参考文档:
http://blog.exceliance.fr/2012/12/12/haproxy-high-mysql-request-rate-and-tcp-source-port-exhaustion/
http://go12345.iteye.com/blog/1798119
http://ganquan.org/blog/2009/09/tcp协议的time_wait状态详解/
http://kerry.blog.51cto.com/172631/105233/

TCP三次握手wireshark抓包分析

本文内容有以下三个部分:

  • wireshark过滤规则
  • osi模型简述
  • tcp三次握手

一、wireshark过滤规则

wireshark只是一个抓包工具,用其他抓包工具同样能够分析tcp三次握手协议。以下这张图片完整地展现了wireshark的面板。

未分类

使用好wireshark一个关键是如何从抓到的众多的包中找到我们想要的那一个。这里就要说filter过滤规则了。如上图,在过滤器方框,我们加上了ip.src==192.168.1.102 or ip.dst==192.168.1.102的过滤规则,意思是在封包列表中,只显示源ip地址为192.168.1.102或者目的ip地址为192.168.1.102的包。
下面列举一些常用的过滤规则:

  1. 过滤IP,如来源IP或者目标IP等于某个IP
    如前面说的例子: ip.src==192.168.1.102 or ip.dst==192.168.1.102
    比如TCP,只显示TCP协议。

  2. 过滤端口
    tcp.dstport == 80 // 只显tcp协议的目标端口80
    tcp.srcport == 80 // 只显tcp协议的来源端口80
    也可以写成tcp.port eq 80 or udp.port eq 80 这样的模式

  3. 过滤协议
    单独写上tcp、udp、xml、http就可以过滤出具体协议的报文。你也可以用tcp or xml这样格式来过滤。
    我们还可以更加具体过滤协议的内容,如tcp.flags.syn == 0x02 表示显示包含TCP SYN标志的封包。

  4. 过滤mac地址
    eth.src eq A0:00:00:04:C5:84 // 过滤来源mac地址
    eth.dst==A0:00:00:04:C5:84 // 过滤目的mac地址

  5. http模式过滤
    http.request.method == “GET”
    http.request.method == “POST”
    http.request.uri == “/img/logo-edu.gif”
    http contains “GET”
    http contains “HTTP/1.”
    // GET包
    http.request.method == “GET” && http contains “Host: ”
    http.request.method == “GET” && http contains “User-Agent: ”
    // POST包
    http.request.method == “POST” && http contains “Host: ”
    http.request.method == “POST” && http contains “User-Agent: ”
    // 响应包
    http contains “HTTP/1.1 200 OK” && http contains “Content-Type: ”
    http contains “HTTP/1.0 200 OK” && http contains “Content-Type: “

  6. 过滤内容
    contains:包含某字符串
    ip.src==192.168.1.107 and udp contains 02:12:21:00:22
    ip.src==192.168.1.107 and tcp contains “GET”
    前面也有例子,http contains “HTTP/1.0 200 OK” && http contains “Content-Type: “

更加高级的用法就不讨论了,读者有兴趣可以查阅wireshark官网用户手册。

二、osi模型简述

OSI定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层),即ISO开放互连系统参考模型。如下图左边部分。在每个分层中,都会对所发送的数据附加一个首部,在这个首部中包含了该层必要的信息,如源ip地址和目的ip地址等。

未分类

osi模型中,在下一层的角度看,当收到上一层的包时,全部会被认为是本层的数据,然后在本层中加上自己本层的首部,继续往下传递。一个数据包格式如下:

未分类

举一个例子,比如客户端应用程序A向远端服务器应用程序B发送“早上好”的数据,那么大致流程是这样的:

  1. 应用程序A把数据发送给下一层的TCP模块。

  2. TCP模块属于传输层。TCP在应用层数据的前端加上一个TCP首部。TCP首部中包含源端口号和目标端口号等信息。然后将包发送给IP模块。

  3. IP模块属于网络层。IP将TCP传过来的TCP首部和TCP数据合起来当做自己的数据,并且在TCP首部的前面加上自己的IP首部。IP首部包含了源ip地址和目的ip地址。然后,IP包将被发送给数据链路层,也就是以太网驱动程序。

  4. 从IP传过来的包,对于以太网驱动程序来说不过就是数据。给这些数据加上以太网首部,里面包含了源MAC地址和目的MAC地址。然后再通过物理层把数据发送给目的MAC地址。

  5. 服务器物理层接收到来自客户端的数据包时,首先从以太网的包首部找到MAC地址,判断是否为发给自己的包,如果不是就丢弃,如果是就向上转移给IP模块解析。

  6. IP模块收到IP包首部和后面的数据以后,判断包首部的目的ip地址与自己的ip地址是否匹配,如果匹配,就接收数据并传给TCP模块处理。

  7. TCP模块会检查端口号确定接收数据的应用程序是哪一个。

  8. 应用程序接收到数据包之后也会根据自己的规则判断做出一系列的处理。

通过上面例子大致的过程,可以体会到从上而下发包再到从下而上收包的过程。

三、tcp三次握手

未分类

上图为tcp三次握手,很多书籍都能看到。TCP提供面向有连接的通信传输,在数据通信开始之前先做好通信两端之间的准备工作。也就是说必须握手成功之后,才能进行通信。 接下来,用wireshark来抓取tcp三次握手报文。打开浏览器输入 http://blog.csdn.net/u014530704/article/。运用我们再前面介绍的过滤规则,在过滤框中输入http contains u014530704,找到如下包:

未分类

可以发现我们向服务器请求的包,其中目的ip地址是47.95.165.112。这个地址是blog.csdn.net的ip地址。
然后我们找 ip.src==47.95.165.112 or ip.dst==47.95.165.112 的包,找到了如下:

未分类

红色方框为本机192.168.1.101和服务器47.95.165.112之间的三次握手协议。三次握手协议的过程为:

客户端通过TCP首部发送一个SYN包作为建立连接的请求等待确认应答。
服务器发送ACK包确认应答,发送SYN包请求连接。
客户端针对SYN包发送ACK包确认应答。
最后,讲述一下看懂报文的方法。想要读懂tcp报文,头部至关重要,对着下图去看wireshark tcp报文,并且找到tcp首部各个字段代表的意思,你就能读懂tcp报文了。其他像以太网报文、ip报文、http报文等同样如此。

未分类

反向代理之haproxy安装及简单配置tcp代理

一、简介

HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且
可靠的一种解决方案。

HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。

HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单
安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。

HAProxy实现了一种事件驱动, 单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接
事件驱动模型因为在有更好的资源和时间管理的用户空间(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。

这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。

二、安装

1. 环境准备

环境设置:

web-node1:
[root@web-node1 src]# uname -r
3.10.0-229.el7.x86_64
[root@web-node1 src]# uname -m
x86_64
[root@web-node1 src]# cat /etc/hostname 
web-node1
[root@web-node1 src]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.64    zabbix_master
10.0.0.65    web-node1
10.0.0.66    web-node2
web-node2:
[root@web-node2 src]# uname -r
3.10.0-229.el7.x86_64
[root@web-node2 src]# uname -m
x86_64
[root@web-node2 src]# cat /etc/hostname 
web-node2
[root@web-node2 src]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.64    zabbix_master
10.0.0.65    web-node1
10.0.0.66    web-node2

2. 安装haproxy

目前haproxy最高版本是1.7.8,本次实验使用1.7.5

下载地址:http://www.haproxy.org/download/1.7/

web-node1:

[root@web-node1 haproxy-1.7.5]#    cd /usr/local/src
[root@web-node1 ]# wget http://www.haproxy.org/download/1.7/src/haproxy-1.7.5.tar.gz
[root@web-node1 haproxy-1.7.5]#  tar -zxf  haproxy-1.7.5.tar.gz 
[root@web-node1 haproxy-1.7.5]#  cd haproxy-1.7.5
[root@web-node1 haproxy-1.7.5]#   make TARGET=linux2628 PREFIX=/usr/local/haproxy-1.7.5
[root@web-node1 haproxy-1.7.5]# make install PREFIX=/usr/local/haproxy-1.7.5
[root@web-node1 haproxy-1.7.5]# cp /usr/local/sbin/haproxy /usr/sbin/
[root@web-node1 local]# ln -s /usr/local/haproxy-1.7.5 /usr/local/haproxy
[root@web-node1 haproxy-1.7.5]# haproxy -v
HA-Proxy version 1.7.5 2017/04/03
Copyright 2000-2017 Willy Tarreau <[email protected]>
#参数说明
TARGET=linux26 #内核版本,使用uname -r查看内核,如:2.6.18-371.el5,此时该参数就为linux26;kernel 大于2.6.28的用:TARGET=linux2628
PREFIX=/usr/local/haprpxy #/usr/local/haprpxy为haprpxy安装路径

3. 编辑Haproxy启动脚本

[root@web-node1 haproxy-1.7.5]# cp /usr/local/src/haproxy-1.7.5/examples/haproxy.init /etc/init.d/haproxy
[root@web-node1 haproxy-1.7.5]# chmod +x /etc/init.d/haproxy

4. 创建haproxy相关目录

[root@web-node1 haproxy-1.7.5]# useradd -r haproxy  ##创建系统用户
[root@web-node1 haproxy-1.7.5]# mkdir /etc/haproxy
[root@web-node1 haproxy-1.7.5]# mkdir /var/lib/haproxy
[root@web-node1 haproxy-1.7.5]# mkdir /var/run/haproxy

5. 修改配置文件

[root@web-node1 haproxy-1.7.5]# cat /etc/haproxy/haproxy.cfg 
global
   log 127.0.0.1 local3 warning
   chroot /var/lib/haproxy
   user haproxy
   group haproxy
   nbproc  1
   maxconn 65535 
   daemon
defaults
   log global
   option dontlognull
   timeout connect 5000
   timeout client 50000
   timeout server 50000
listen test
 bind 10.0.0.65:8080
 mode tcp
 #balance roundrobin
 timeout server 15s
 timeout connect 15s
 server web01 10.0.0.66:22 check port 22 inter 5000 fall 5 

6. 启动haproxy

检查语法:
/usr/sbin/haproxy  -f /etc/haproxy/haproxy.cfg -c
[root@web-node1 haproxy-1.7.5]# /etc/init.d/haproxy start
查看进程:
[root@web-node1 haproxy-1.7.5]# ps -ef|grep haproxy
haproxy   11126      1  0 16:20 ?        00:00:00 /usr/sbin/haproxy -D -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid
root      11183   2633  0 16:32 pts/1    00:00:00 grep --color=auto haproxy

三、测试tcp代理是否成功

未分类

上述可以看出已经成功了。

Debian/Ubuntu 更新内核开启 TCP BBR 拥塞控制算法

BBR (Bottleneck Bandwidth and RTT) 是 Google 提供的 TCP 拥塞控制算法,适用于复杂网络环境下的 TCP 加速。

首先需要准备的条件

  • Debian 8.x 或者 Debian 9.x 系统,当然也适合 Ubuntu 14.04 或 Ubuntu 16.04
  • 如果是虚拟机,那么得使用 KVM 或 Xen 等可以修改内核的平台
  • 如果不是新的机器,请事先做好备份,因为内核万一挂了机器启动不起来是一件及其麻烦的事情

升级内核

BBR 只支持 4.9.x 以上的内核,所以我们需要更新升级以下

如果你使用的是 Debian 9.x,那么这一步可以直接跳过,其他三个内核版本较旧的系统,我们可以使用 Ubuntu 打包好的内核安装包

首先,找到 4.9.x 以上版本的稳定内核,这里我们推荐使用 LTS 版本,目前最新的是 4.9.40 下载安装即可

mkdir kernel-tmp && cd kernel-tmp
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.40/linux-headers-4.9.40-040940_4.9.40-040940.201707271932_all.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.40/linux-headers-4.9.40-040940-generic_4.9.40-040940.201707271932_amd64.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9.40/linux-image-4.9.40-040940-generic_4.9.40-040940.201707271932_amd64.deb
sudo dpkg -i *.deb

安装完以后直接 reboot 重启,一切顺利的话请检查以下当前的内核版本

root@debian ~ # uname -r
4.9.0-3-amd64

写入配置文件

直接修改 /etc/sysctl.conf 文件即可

cat >> /etc/sysctl.conf << EOF
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF

然后使用 sysctl -p 命令让内核配置生效,不出意外,应该会提示

root@debian ~ # sysctl -p
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

此时可以使用 lsmod | grep bbr 命令检查 BBR 是否已正确开启

root@debian ~ # lsmod | grep bbr
tcp_bbr                16384  61

如果出现 tcp_bbr 字样则说明没有问题。