上一节,我们一起学习了如何分析网络丢包的问题,特别是从链路层、网络层以及传输层等主要的协议栈中进行分析。
不过,通过前面这几层的分析,我们还是没有找出最终的性能瓶颈。看来,还是要继续深挖才可以。今天,我们就来继续分析这个未果的案例。
在开始下面的内容前,你可以先回忆一下上节课的内容,并且自己动脑想一想,除了我们提到的链路层、网络层以及传输层之外,还有哪些潜在问题可能会导致丢包呢?
首先我们要知道,除了网络层和传输层的各种协议,iptables 和内核的连接跟踪机制也可能会导致丢包。所以,这也是发生丢包问题时,我们必须要排查的一个因素。
我们先来看看连接跟踪,我已经在 如何优化 NAT 性能 文章中,给你讲过连接跟踪的优化思路。要确认是不是连接跟踪导致的问题,其实只需要对比当前的连接跟踪数和最大连接跟踪数即可。
不过,由于连接跟踪在 Linux 内核中是全局的(不属于网络命名空间),我们需要退出容器终端,回到主机中来查看。
你可以在容器终端中,执行 exit ;然后执行下面的命令,查看连接跟踪数:
1 2 3 4 5 6 7 8 9 |
|
实际测试代码如下:
1 2 3 4 |
|
从这儿你可以看到,连接跟踪数只有 182,而最大连接跟踪数则是 262144。显然,这里的丢包,不可能是连接跟踪导致的。
接着,再来看 iptables。回顾一下 iptables 的原理,它基于 Netfilter 框架,通过一系列的规则,对网络数据包进行过滤(如防火墙)和修改(如 NAT)。
这些 iptables 规则,统一管理在一系列的表中,包括 filter(用于过滤)、nat(用于 NAT)、mangle(用于修改分组数据) 和 raw(用于原始数据包)等。而每张表又可以包括一系列的
链,用于对 iptables 规则进行分组管理。
对于丢包问题来说,最大的可能就是被 filter 表中的规则给丢弃了。要弄清楚这一点,就需要我们确认,那些目标为 DROP 和 REJECT 等会弃包的规则,有没有被执行到。
你可以把所有的 iptables 规则列出来,根据收发包的特点,跟 iptables 规则进行匹配。不过显然,如果 iptables 规则比较多,这样做的效率就会很低。
当然,更简单的方法,就是直接查询 DROP 和 REJECT 等规则的统计信息,看看是否为 0。如果统计值不是 0 ,再把相关的规则拎出来进行分析。
我们可以通过 iptables -nvL 命令,查看各条规则的统计信息。比如,你可以执行下面的 dockerexec 命令,进入容器终端;然后再执行下面的 iptables 命令,就可以看到 filter 表的统计数据了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
实际测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
从 iptables 的输出中,你可以看到,两条 DROP 规则的统计数值不是 0,它们分别在 INPUT 和OUTPUT 链中。这两条规则实际上是一样的,指的是使用 statistic 模块,进行随机 30% 的丢包。
再观察一下它们的匹配规则。0.0.0.0/0 表示匹配所有的源 IP 和目的 IP,也就是会对所有包都进行随机 30% 的丢包。看起来,这应该就是导致部分丢包的“罪魁祸首”了。
既然找出了原因,接下来的优化就比较简单了。比如,把这两条规则直接删除就可以了。我们可以在容器终端中,执行下面的两条 iptables 命令,删除这两条 DROP 规则:
1 2 |
|
删除后,问题是否就被解决了呢?我们可以切换到终端二中,重新执行刚才的 hping3 命令,看看现在是否正常:
1 2 3 4 5 6 7 8 9 10 |
|
实际测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
这次输出你可以看到,现在已经没有丢包了,并且延迟的波动变化也很小。看来,丢包问题应该已经解决了。
不过,到目前为止,我们一直使用的 hping3 工具,只能验证案例 Nginx 的 80 端口处于正常监听状态,却还没有访问 Nginx 的 HTTP 服务。所以,不要匆忙下结论结束这次优化,我们还需
要进一步确认,Nginx 能不能正常响应 HTTP 请求。
我们继续在终端二中,执行如下的 curl 命令,检查 Nginx 对 HTTP 请求的响应:
1 2 |
|
实际测试代码如下:
1 2 |
|
从 curl 的输出中,你可以发现,这次连接超时了。可是,刚才我们明明用 hping3 验证了端口正常,现在却发现 HTTP 连接超时,是不是因为 Nginx 突然异常退出了呢?
不妨再次运行 hping3 来确认一下:
1 2 3 4 5 6 7 8 9 |
|
实际测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
奇怪,hping3 的结果显示,Nginx 的 80 端口确确实实还是正常状态。这该如何是好呢?别忘了,我们还有个大杀器——抓包操作。看来有必要抓包看看了。
接下来,我们切换回终端一,在容器终端中,执行下面的 tcpdump 命令,抓取 80 端口的包:
1 2 3 |
|
然后,切换到终端二中,再次执行前面的 curl 命令:
1 2 |
|
实际测试代码如下:
1 2 |
|
等到 curl 命令结束后,再次切换回终端一,查看 tcpdump 的输出:
1 2 3 4 5 |
|
实际测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
经过这么一系列的操作,从 tcpdump 的输出中,我们就可以看到:
我想,根据 curl 设置的 3 秒超时选项,你应该能猜到,这是因为 curl 命令超时后退出了。我把这一过程,用 TCP 交互的流程图(实际上来自 Wireshark 的 Flow Graph)来表示,你可
以更清楚地看到上面这个问题:
这里比较奇怪的是,我们并没有抓取到 curl 发来的 HTTP GET 请求。那么,究竟是网卡丢包了,还是客户端压根儿就没发过来呢?
我们可以重新执行 netstat -i 命令,确认一下网卡有没有丢包问题:
1 2 3 4 5 |
|
从 netstat 的输出中,你可以看到,接收丢包数(RX-DRP)是 344,果然是在网卡接收时丢包了。不过问题也来了,为什么刚才用 hping3 时不丢包,现在换成 GET 就收不到了呢?
还是那句话,遇到搞不懂的现象,不妨先去查查工具和方法的原理。我们可以对比一下这两个工具:
HTTP GET ,本质上也是一个 TCP 包,但跟 SYN 包相比,它还携带了 HTTP GET 的数据。那么,通过这个对比,你应该想到了,这可能是 MTU 配置错误导致的。为什么呢?
其实,仔细观察上面 netstat 的输出界面,第二列正是每个网卡的 MTU 值。eth0 的 MTU 只有100,而以太网的 MTU 默认值是 1500,这个 100 就显得太小了。
当然,MTU 问题是很好解决的,把它改成 1500 就可以了。我们继续在容器终端中,执行下面的命令,把容器 eth0 的 MTU 改成 1500:
1 |
|
修改完成后,再切换到终端二中,再次执行 curl 命令,确认问题是否真的解决了:
1 2 3 4 5 6 7 |
|
实际测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
非常不容易呀,这次终于看到了熟悉的 Nginx 响应,说明丢包的问题终于彻底解决了。
当然,案例结束前,不要忘记停止今天的 Nginx 应用。你可以切换回终端一,在容器终端中执行exit 命令,退出容器终端:
1 2 |
|
最后,再执行下面的 docker 命令,停止并删除 Nginx 容器:
1 |
|
今天,我继续带你分析了网络丢包的问题。特别是在时不时丢包的情况下,定位和优化都需要我们花心思重点投入。
网络丢包问题的严重性不言而喻。碰到丢包问题时,我们还是要从 Linux 网络收发的流程入手,结合 TCP/IP 协议栈的原理来逐层分析。
作者:罗阿红 出处:http://www.cnblogs.com/luoahong/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
1. HashSet底层通过包装HashMap来实现,HashSet在添加一个值的时候,实际上是将此值作为HashMap中的key来进行保存。2. HashMap的底层实现是通过初始化化一个Entry数组来实现key、value的保存。3. 在HashMap的Entry中有四个变量,key、value、hash、next,其中next用于在hash方法添加值冲突时候,所指向的下一个
用链表实现栈:其实就只是换了个名字,包装起来而已,没什么新的东西。注:这里插入结点的方法应为在头部插入结点(与输入的值逆置),这样构成的才是栈关于定义链表可以查看我的另一篇博文https://blog.csdn.net/szlg510027010/article/details/82862965/** * 用链表实现栈 * @author Administrator *...
目录一、缓存穿透解决方案:1. 缓存空对象2.布隆过滤器拦截二、缓存雪崩解决方案:三、缓存击穿解决方案:1. 分布式互斥锁2.永不过期在生产环境中,会因为很多的原因造成访问请求绕过了缓存,都需要访问数据库持久层,虽然对Redsi缓存服务器不会造成影响,但是数据库的负载就会增大,使缓存的作用降低一、缓存穿透缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存...
前言缘是美丽的邂逅,爱是心跳的感觉,情是心灵的交会,恋是甜蜜的思念,走在爱与被爱的边缘,你见或者不见,爱你的心始终不改变!C语言诠释爱——为TA写下心中情,生成程序传给TA,TA点开程序就懂你。(整个程序最重要的部分就是烟花,为了做出真正符合实际的烟花,我加入了重力效果,空气阻力效果)开发环境VC++6.0/vs && easyx.效果展示:开始效果:展示表白女孩的名字(在这里希望大家顶起来,给个
aws iam 介绍 (Intro)The Salesforce Security Assurance team would like to share a tool that we recently published called Policy Sentry, which helps to automate the creation of least privilege IAM polici...
1、NER(Named Entity Recognition, NER)NER 是 NLP 的基础任务,指从文本中识别出命名性指称项,为关系抽取等任务做铺垫。狭义上,是识别出人名、地名和组织结构名这三类命名实体。当然,在特定领域中,会相应地定义领域内地各种实体类型。2、常见地公开的数据集CoNLL 2003(https://www.clips.uantwerpen.be/conll2003/ner/)CoNLL2003 中,实体被标注为四种类型:①LOC(Location,地名)②O
**【转载】**https://blog.csdn.net/qq_16687863/article/details/100243007文章目录前端实战小案例--炫酷动态登录按钮知识点1、js中this的指代问题2、justify-content的用法3、align-items4、animation-delay5、svg-polyline 的用法6、@keyframes 逐帧的动画效果图代码前端实战小案例–炫酷动态登录按钮知识点这篇比较多css3的语法,以及css动画的知识点1、js中this的指代
正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。re模块的使用#导入re模块import re#使用match方法匹配出以xxx开头的字符串#pattern:自己编写的正则表达式#string:要匹配的字符串result = re.match(pattern, string)#若匹配成功,则match方法返回匹配对象(Ma...
[color=darkblue] 以下是常用软件及一些设置:1.河南网通pppoe认证在linux下上网问题解决 由于河南网通用的认证方法与别的地方不同,所以用普通方法不起效。出现的问题在于, 用原始账号认证无效,是因为网通公司用自己的客户端认证,而在认证之前就已经将原账号经过 MD5 CHAP...
大型血液分析仪行业:医疗器械方案描述:血液分析仪是国内医疗器械行业比较热门的一种医疗分析仪器。因为普及程度较高,所以市场需求量也比较大。大型血液分析仪硬件构成相对复杂,需要ARM加FPGA的方式实现。本方案可以实现ARM层的相关硬件功能,帮助医疗器械客户快速开发出整机方案。方案实现:基于信迈XM5728-IDK-V3进行模块开发和定制。功能介绍:基于 TI AM5728 浮点双 DSP C66x +双 ARM Cortex-A15 工业控制及高性能音...
python一边大量接收数据,一边对采集数据进行实时处理。如果开线程会导致,接收数据大量丢失问题。此时应开进程对数据进行抓取。这样既可边采集数据,边对数据进行实时处理。
在讲这个问题之前,先来补充几个知识点,如果对此已经比较了解可以直接跳过。 大多数浏览器的组件构成如图在最底层的三个组件分别是网络,UI后端和js解释器。作用如下:网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作。UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口。JS解释器-