<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Ops运维 | Mr`kang Blog｜小豆子]]></title> 
<link>https://www.cnmysql.com/index.php</link> 
<description><![CDATA[关注服务器运维技术、DB优化、Docker虚拟化、自动化运维、工作积累]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Ops运维 | Mr`kang Blog｜小豆子]]></copyright>
<item>
<link>https://www.cnmysql.com/post/138/</link>
<title><![CDATA[linux下php添加pdo_mysql扩展]]></title> 
<author>kangyang &lt;kangyang315@qq.com&gt;</author>
<category><![CDATA[WEB技术]]></category>
<pubDate>Tue, 06 Jan 2015 07:09:53 +0000</pubDate> 
<guid>https://www.cnmysql.com/post/138/</guid> 
<description>
<![CDATA[ 
	<span style="font-family: 宋体;"><span style="font-size: 12px;"><br/>pdo_mysql模块安装<br/><br/>如果没有安装pdo模块的需要先安装pdo模块，不然在编译pdo_mysql模块的时候会报如下错误：<br/>configure: error: Cannot find php_pdo_driver.h.<br/><br/>1、进入源码模块目录编译pdo模块<br/>cd /home/soft/nginx/php-5.5.14/ext/pdo<br/>/usr/local/php/bin/phpize<br/> ./configure --with-php-config=/usr/local/php/bin/php-config --with-pdo-mysql=/usr/local/mysql<br/><br/>2、编译pdo_mysql<br/>cd /home/soft/nginx/php-5.5.14/ext/pdo_mysql<br/>/usr/local/php/bin/phpize<br/>./configure --with-php-config=/usr/local/php/bin/php-config --with-pdo-mysql=/usr/local/mysql<br/><br/><br/>编译完后vi php.ini<br/>extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20121212/pdo_mysql.so<br/>extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20121212/pdo.so<br/><br/>重启php-fpm<br/>/etc/init.d/php-fpm restart<br/><br/>php -m&nbsp;&nbsp;查看php的模块<br/>或者：/usr/local/webserver/php/bin/php -r "phpinfo();"&#124;grep -i pdo_mysql<br/></span><br/></span><br/>Tags - <a href="https://www.cnmysql.com/tags/php/" rel="tag">php</a> , <a href="https://www.cnmysql.com/tags/pdo/" rel="tag">pdo</a> , <a href="https://www.cnmysql.com/tags/pdo_mysql/" rel="tag">pdo mysql</a>
]]>
</description>
</item><item>
<link>https://www.cnmysql.com/post/135/</link>
<title><![CDATA[网站日志统计分析shell]]></title> 
<author>kangyang &lt;kangyang315@qq.com&gt;</author>
<category><![CDATA[WEB技术]]></category>
<pubDate>Mon, 05 Jan 2015 07:27:57 +0000</pubDate> 
<guid>https://www.cnmysql.com/post/135/</guid> 
<description>
<![CDATA[ 
	<span style="font-family: 宋体;"><span style="font-size: 12px;"><br/>状态码统计<br/>cat access.log &#124; cut -d '"' -f3 &#124; cut -d ' ' -f2 &#124; sort &#124; uniq -c &#124; sort -r<br/><br/>1、查看独立IP访问<br/>cat&nbsp;&nbsp;access.log &#124; awk -F'-' '&#123; print $1 &#125;'&#124; uniq -c &#124; wc -l<br/>netstat -nat &#124;awk '&#123;print $6&#125;'&#124;sort&#124;uniq -c&#124;sort -rn <br/>netstat -anlp&#124;grep 80&#124;grep tcp&#124;awk '&#123;print $5&#125;'&#124;awk -F: '&#123;print $1&#125;'&#124;sort&#124;uniq -c&#124;sort -nr&#124;head -n20<br/><br/>4.查找较多time_wait连接<br/>netstat -n&#124;grep TIME_WAIT&#124;awk '&#123;print $5&#125;'&#124;sort&#124;uniq -c&#124;sort -rn&#124;head -n20<br/><br/>5.找查较多的SYN连接<br/>netstat -an &#124; grep SYN &#124; awk '&#123;print $5&#125;' &#124; awk -F: '&#123;print $1&#125;' &#124; sort &#124; uniq -c &#124; sort -nr &#124; more<br/><br/>查看当前ip 0点时段访问最高的页面<br/>cat access_log &#124; grep "19/Dec/2014:00" &#124; grep "119.5.89.181" &#124; awk '&#123;print $13&#125;' &#124; sort &#124; uniq -c &#124; sort -nr &#124; head -n 10<br/><br/>网站日志分析篇1（Apache）：<br/><br/>1.获得访问前10位的ip地址<br/>cat access.log&#124;awk '&#123;print $1&#125;'&#124;sort&#124;uniq -c&#124;sort -nr&#124;head -10<br/>cat access.log&#124;awk '&#123;counts[$(11)]+=1&#125;; END &#123;for(url in counts) print counts[url], url&#125;'<br/><br/>2.访问次数最多的文件或页面,取前20<br/>cat access.log&#124;awk '&#123;print $11&#125;'&#124;sort&#124;uniq -c&#124;sort -nr&#124;head -20<br/><br/>3.列出传输最大的几个exe文件（分析下载站的时候常用）<br/>cat access.log &#124;awk '($7~/&#92;.exe/)&#123;print $10 " " $1 " " $4 " " $7&#125;'&#124;sort -nr&#124;head -20<br/><br/>4.列出输出大于200000byte(约200kb)的exe文件以及对应文件发生次数<br/>cat access.log &#124;awk '($10 > 200000 && $7~/&#92;.exe/)&#123;print $7&#125;'&#124;sort -n&#124;uniq -c&#124;sort -nr&#124;head -100<br/><br/>5.如果日志最后一列记录的是页面文件传输时间，则有列出到客户端最耗时的页面<br/>cat access.log &#124;awk&nbsp;&nbsp;'($7~/&#92;.php/)&#123;print $NF " " $1 " " $4 " " $7&#125;'&#124;sort -nr&#124;head -100<br/><br/>6.列出最最耗时的页面(超过60秒的)的以及对应页面发生次数<br/>cat access.log &#124;awk '($NF > 60 && $7~/&#92;.php/)&#123;print $7&#125;'&#124;sort -n&#124;uniq -c&#124;sort -nr&#124;head -100<br/><br/>7.列出传输时间超过 30 秒的文件<br/>cat access.log &#124;awk '($NF > 30)&#123;print $7&#125;'&#124;sort -n&#124;uniq -c&#124;sort -nr&#124;head -20<br/><br/>8.统计网站流量（G)<br/>cat access.log &#124;awk '&#123;sum+=$10&#125; END &#123;print sum/1024/1024/1024&#125;'<br/><br/>9.统计404的连接<br/>awk '($9 ~/404/)' access.log &#124; awk '&#123;print $9,$7&#125;' &#124; sort<br/><br/>10. 统计http status.<br/>cat access.log &#124;awk '&#123;counts[$(9)]+=1&#125;; END &#123;for(code in counts) print code, counts[code]&#125;'<br/>cat access.log &#124;awk '&#123;print $9&#125;'&#124;sort&#124;uniq -c&#124;sort -rn<br/><br/>10.蜘蛛分析<br/>查看是哪些蜘蛛在抓取内容。<br/>/usr/sbin/tcpdump -i eth0 -l -s 0 -w - dst port 80 &#124; strings &#124; grep -i user-agent &#124; grep -i -E 'bot&#124;crawler&#124;slurp&#124;spider'<br/><br/>SHELL短语<br/>1、查看当天有多少个IP访问：<br/>awk '&#123;print $1&#125;' log_file&#124;sort&#124;uniq&#124;wc -l<br/><br/>2、查看某一个页面被访问的次数：<br/>grep "/index.php" log_file &#124; wc -l<br/><br/>3、查看每一个IP访问了多少个页面：<br/>awk '&#123;++S[$1]&#125; END &#123;for (a in S) print a,S[a]&#125;' log_file<br/><br/>4、将每个IP访问的页面数进行从小到大排序：<br/>awk '&#123;++S[$1]&#125; END &#123;for (a in S) print S[a],a&#125;' log_file &#124; sort -n<br/><br/>5、查看某一个IP访问了哪些页面：<br/>grep ^111.111.111.111 log_file&#124; awk '&#123;print $1,$7&#125;'<br/><br/>6、去掉搜索引擎统计当天的页面：<br/>awk '&#123;print $12,$1&#125;' log_file &#124; grep ^&#92;"Mozilla &#124; awk '&#123;print $2&#125;' &#124;sort &#124; uniq &#124; wc -l<br/><br/>7、查看2009年6月21日14时这一个小时内有多少IP访问:<br/>awk '&#123;print $4,$1&#125;' log_file &#124; grep 21/Jun/2009:14 &#124; awk '&#123;print $2&#125;'&#124; sort &#124; uniq &#124; wc -l<br/><br/>8,查看apache进程:<br/>ps aux &#124; grep httpd &#124; grep -v grep &#124; wc -l<br/><br/>9,查看80端口的tcp连接:<br/>netstat -tan &#124; grep "ESTABLISHED" &#124; grep ":80" &#124; wc -l<br/><br/>10,通过日志查看当天ip连接数，过滤重复:<br/>cat access_log &#124; grep "20/Oct/2008" &#124; awk '&#123;print $2&#125;' &#124; sort &#124; uniq -c &#124; sort -nr<br/><br/>11,当天ip连接数最高的ip都在干些什么(原来是蜘蛛):<br/>cat access_log &#124; grep "20/Oct/2008:00" &#124; grep "122.102.7.212" &#124; awk '&#123;print $8&#125;' &#124; sort &#124; uniq -c &#124; sort -nr &#124; head -n 10<br/><br/>12,当天访问页面排前10的url:<br/>cat access_log &#124; grep "20/Oct/2008:00" &#124; awk '&#123;print $8&#125;' &#124; sort &#124; uniq -c &#124; sort -nr &#124; head -n 10<br/><br/>13,用tcpdump嗅探80端口的访问看看谁最高<br/>tcpdump -i eth0 -tnn dst port 80 -c 1000 &#124; awk -F"." '&#123;print $1"."$2"."$3"."$4&#125;' &#124; sort &#124; uniq -c &#124; sort -nr<br/><br/>接着从日志里查看该ip在干嘛:<br/>cat access_log &#124; grep 122.102.7.212&#124; awk '&#123;print $1"&#92;t"$8&#125;' &#124; sort &#124; uniq -c &#124; sort -nr &#124; less<br/><br/>14,查看某一时间段的ip连接数:<br/>grep "2006:0[7-8]" www20060723.log &#124; awk '&#123;print $2&#125;' &#124; sort &#124; uniq -c&#124; sort -nr &#124; wc -l<br/><br/></span><br/></span>
]]>
</description>
</item><item>
<link>https://www.cnmysql.com/post/130/</link>
<title><![CDATA[redis监控利器redis-live]]></title> 
<author>kangyang &lt;kangyang315@qq.com&gt;</author>
<category><![CDATA[WEB技术]]></category>
<pubDate>Tue, 23 Sep 2014 07:44:46 +0000</pubDate> 
<guid>https://www.cnmysql.com/post/130/</guid> 
<description>
<![CDATA[ 
	<span style="font-family: 宋体;"><span style="font-size: 12px;"><br/>安装redis-live：<br/>因为redis-live是基于python开发的，所以首先要部署所需要的python环境<br/>1、安装epel源<br/><div class="code">wget http://download.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm<br/>rpm -ivh epel-release-5-4.noarch.rpm</div><br/>2、安装python依赖环境<br/><div class="code">yum install python-pip<br/>pip-python install tornado<br/>pip-python install argparse<br/>pip-python install python-dateutil<br/>或者<br/>yum install tornado<br/>yum install python-dateutil<br/>yum install argparse</div><br/><br/>3、获取redis-live版本<br/><div class="code">git clone https://github.com/kumarnitin/RedisLive.git<br/>cd RedisLive/src<br/>vi redis-live.conf <br/>&#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;RedisServers&quot;:&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#91;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;server&quot; : &quot;127.0.0.1&quot;,&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;port&quot;&nbsp;&nbsp;: 6379<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#93;,&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;DataStoreType&quot; : &quot;redis&quot;,&nbsp;&nbsp;<br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;RedisStatsServer&quot;:&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;server&quot; : &quot;127.0.0.1&quot;,&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;port&quot; : 6379&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;<br/>&#125; </div><br/>RedisServers :redis服务器的配置。<br/>DataStoreType :选择是存储到redis还是sqlite里面<br/>RedisStatsServer：是redis服务器的监控信息可以存放在其他的redis服务器中.也就是RedisStatsServe.<br/><br/>配置好之后，就可以启动服务了。<br/><div class="code">chmod 777 www&nbsp;&nbsp; 修改web页面权限<br/>./redis-monitor.py –duration 120 &amp;<br/>./redis-live.py &amp;</div><br/>注：启动服务之后，如果访问web页面的话，会在当前终端输出日志，如果不想在终端输出，可以查看redis-live.py的参数<br/>访问：<a href="http://ip:8888/index.html" target="_blank">http://ip:8888/index.html</a><br/>监控效果图<br/><a href="https://www.cnmysql.com/attachment.php?fid=37" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=37" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>安装报错信息：<br/>1、not found redis module<br/>解决办法<br/>下载：<a href="https://codeload.github.com/andymccurdy/redis-py/zip/master" target="_blank">https://codeload.github.com/andymccurdy/redis-py/zip/master</a><br/><div class="code">unzip redis-py-master.zip<br/>cd redis-py-master<br/>python setup.py install</div><br/><br/>2、pip-python安装tornado和python-dateutil失败解决办法<br/><div class="code">https://cloud.github.com/downloads/tornadoweb/tornado/tornado-1.2.1.tar.gz<br/>tar zxvf tornado-1.2.1.tar.gz<br/>cd tornado-1.2.1<br/>python setup.py build<br/>python setup.py install<br/><br/>wget http://labix.org/download/python-dateutil/python-dateutil-1.5.tar.gz<br/>tar zxvf python-dateutil-1.5.tar.gz<br/>cd python-dateutil-1.5<br/>python setup.py install</div><br/><br/><br/></span><br/></span><br/>Tags - <a href="https://www.cnmysql.com/tags/redis-live/" rel="tag">redis-live</a> , <a href="https://www.cnmysql.com/tags/redis/" rel="tag">redis</a>
]]>
</description>
</item><item>
<link>https://www.cnmysql.com/post/116/</link>
<title><![CDATA[三张图看遍Linux 性能监控、测试、优化工具]]></title> 
<author>kangyang &lt;kangyang315@qq.com&gt;</author>
<category><![CDATA[WEB技术]]></category>
<pubDate>Mon, 15 Sep 2014 06:15:39 +0000</pubDate> 
<guid>https://www.cnmysql.com/post/116/</guid> 
<description>
<![CDATA[ 
	<span style="font-family: 宋体;"><span style="font-size: 12px;"><br/>Linux 平台上的性能工具有很多，眼花缭乱，长期的摸索和经验发现最好用的还是那些久经考验的、简单的小工具。系统性能专家 Brendan D. Gregg 在最近的 LinuxCon NA 2014 大会上更新了他那个有名的关于 Linux 性能方面的 talk (Linux Performance Tools) 和幻灯片。<br/>和 Brendan 去年的 talk 比较，今年增加了测试和优化两部分。下面的三张图片分别总结了 Linux 各个子系统以及监控、测试、优化这些子系统所用到的工具。<br/><strong>监控</strong><br/><a href="https://www.cnmysql.com/attachment.php?fid=32" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=32" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><strong>测试</strong><br/><a href="https://www.cnmysql.com/attachment.php?fid=33" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=33" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><strong>优化</strong><br/><a href="https://www.cnmysql.com/attachment.php?fid=34" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=34" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/></span><br/></span><br/>Tags - <a href="https://www.cnmysql.com/tags/%25E6%25B5%258B%25E8%25AF%2595/" rel="tag">测试</a> , <a href="https://www.cnmysql.com/tags/%25E4%25BC%2598%25E5%258C%2596/" rel="tag">优化</a> , <a href="https://www.cnmysql.com/tags/%25E6%2580%25A7%25E8%2583%25BD%25E7%259B%2591%25E6%258E%25A7/" rel="tag">性能监控</a> , <a href="https://www.cnmysql.com/tags/linux/" rel="tag">linux</a>
]]>
</description>
</item><item>
<link>https://www.cnmysql.com/post/113/</link>
<title><![CDATA[又见KeepAlive]]></title> 
<author>kangyang &lt;kangyang315@qq.com&gt;</author>
<category><![CDATA[WEB技术]]></category>
<pubDate>Tue, 09 Sep 2014 03:09:12 +0000</pubDate> 
<guid>https://www.cnmysql.com/post/113/</guid> 
<description>
<![CDATA[ 
	<span style="font-family: 宋体;"><span style="font-size: 12px;"><br/>我为什么要谈KeepAlive<br/>最近工作中遇到一个问题，想把它记录下来，场景是这样的：<br/><a href="https://www.cnmysql.com/attachment.php?fid=25" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=25" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>从上图可以看出，用户通过Client访问的是LVS的VIP， VIP后端挂载的RealServer是Nginx服务器。 Client可以是浏览器也可以是一个客户端程序。一般情况下，这种架构不会出现问题，但是如果Client端把请求发送给Nginx，Nginx的后端需要一段时间才能返回结果，超过1分30秒就会有问题，使用LVS作为负载均衡设备看到的现象就是1分30秒之后， Client和Nginx链接被断开，没有数据返回。原因是LVS默认保持TCP的Session为90s，超过90s没有TCP报文在链接上传输，LVS就会给两端发送RESET报文断开链接。LVS这么做的原因相信大家都知道一二，我所知道的原因主要有两点：<br/><div class="code"><br/>1.节省负载均衡设备资源，每一个TCP/UDP的链接都会在负载均衡设备上创建一个Session的结构， 链接如果一直不断开，这种Session结构信息最终会消耗掉所有的资源，所以必须释放掉。 <br/>2.另外释放掉能保护后端的资源，如果攻击者通过空链接，链接到Nginx上，如果Nginx没有做合适 的保护，Nginx会因为链接数过多而无法提供服务。<br/></div><br/>这种问题不只是在LVS上有，之前在商用负载均衡设备F5上遇到过同样的问题，F5的Session断开方式和LVS有点区别，F5不会主动发送RESET给链接的两端，Session消失之后，当链接中一方再次发送报文时会接收到F5的RESET, 之后的现象是再次发送报文的一端TCP链接状态已经断开，而另外一端却还是ESTABLISH状态。 <br/>知道是负载均衡设备原因之后，第一反应就是通过开启KeepAlive来解决。到此这个问题应该是结束了，但是我发现过一段时间总又有人提起KeepAlive的问题，甚至发现由于KeepAlive的理解不正确浪费了很多资源，原本能使用LVS的应用放在了公网下沉区，或者换成了商用F5设备(F5设备的Session断开时间要长一点，默认应该是5分钟)。所以我决定把我知道的KeepAlive知识点写篇博客分享出来。<br/><br/>为什么要有KeepAlive？<br/>在谈KeepAlive之前，我们先来了解下简单TCP知识(知识很简单，高手直接忽略)。首先要明确的是在TCP层是没有“请求”一说的，经常听到在TCP层发送一个请求，这种说法是错误的。TCP是一种通信的方式，“请求”一词是事务上的概念，HTTP协议是一种事务协议，如果说发送一个HTTP请求，这种说法就没有问题。也经常听到面试官反馈有些面试运维的同学，基本的TCP三次握手的概念不清楚，面试官问TCP是如何建立链接，面试者上来就说，假如我是客户端我发送一个请求给服务端，服务端发送一个请求给我。。。这种一听就知道对TCP基本概念不清楚。下面是我通过wireshark抓取的一个TCP建立握手的过程。（命令行基本上用TCPdump,后面我们还会用这张图说明问题）:<br/><a href="https://www.cnmysql.com/attachment.php?fid=26" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=26" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>现在我看只要看前3行，这就是TCP三次握手的完整建立过程，第一个报文SYN从发起方发出，第二个报文SYN,ACK是从被连接方发出，第三个报文ACK确认对方的SYN，ACK已经收到，如下图：<br/><a href="https://www.cnmysql.com/attachment.php?fid=27" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=27" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>但是数据实际上并没有传输，请求是有数据的，第四个报文才是数据传输开始的过程，细心的读者应该能够发现wireshark把第四个报文解析成HTTP协议，HTTP协议的GET方法和URI也解析出来，所以说TCP层是没有请求的概念，HTTP协议是事务性协议才有请求的概念，TCP报文承载HTTP协议的请求(Request)和响应(Response)。<br/>现在才是开始说明为什么要有KeepAlive。链接建立之后，如果应用程序或者上层协议一直不发送数据，或者隔很长时间才发送一次数据，当链接很久没有数据报文传输时如何去确定对方还在线，到底是掉线了还是确实没有数据传输，链接还需不需要保持，这种情况在TCP协议设计中是需要考虑到的。TCP协议通过一种巧妙的方式去解决这个问题，当超过一段时间之后，TCP自动发送一个数据为空的报文给对方，如果对方回应了这个报文，说明对方还在线，链接可以继续保持，如果对方没有报文返回，并且重试了多次之后则认为链接丢失，没有必要保持链接。<br/><br/>如何开启KeepAlive<br/>KeepAlive并不是默认开启的，在Linux系统上没有一个全局的选项去开启TCP的KeepAlive。需要开启KeepAlive的应用必须在TCP的socket中单独开启。Linux Kernel有三个选项影响到KeepAlive的行为：<br/><br/>net.ipv4.tcpkeepaliveintvl = 75<br/>net.ipv4.tcpkeepaliveprobes = 9<br/>net.ipv4.tcpkeepalivetime = 7200<br/>tcpkeepalivetime的单位是秒，表示TCP链接在多少秒之后没有数据报文传输启动探测报文; tcpkeepaliveintvl单位是也秒,表示前一个探测报文和后一个探测报文之间的时间间隔，tcpkeepaliveprobes表示探测的次数。<br/><br/>TCP socket也有三个选项和内核对应，通过setsockopt系统调用针对单独的socket进行设置：<br/><br/>TCPKEEPCNT: 覆盖 tcpkeepaliveprobes<br/>TCPKEEPIDLE: 覆盖 tcpkeepalivetime<br/>TCPKEEPINTVL: 覆盖 tcpkeepalive_intvl <br/>举个例子，以我的系统默认设置为例，kernel默认设置的tcpkeepalivetime是7200s, 如果我在应用程序中针对socket开启了KeepAlive,然后设置的TCP_KEEPIDLE为60，那么TCP协议栈在发现TCP链接空闲了60s没有数据传输的时候就会发送第一个探测报文。<br/><br/>TCP KeepAlive和HTTP的Keep-Alive是一样的吗？<br/>估计很多人乍看下这个问题才发现其实经常说的KeepAlive不是这么回事，实际上在没有特指是TCP还是HTTP层的KeepAlive，不能混为一谈。TCP的KeepAlive和HTTP的Keep-Alive是完全不同的概念。TCP层的KeepAlive上面已经解释过了。 HTTP层的Keep-Alive是什么概念呢？ 在讲述TCP链接建立的时候，我画了一张三次握手的示意图，TCP在建立链接之后， HTTP协议使用TCP传输HTTP协议的请求(Request)和响应(Response)数据，一次完整的HTTP事务如下图：<br/><a href="https://www.cnmysql.com/attachment.php?fid=28" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=28" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>各位看官请注意，这张图我简化了HTTP(Req)和HTTP(Resp)，实际上的请求和响应需要多个TCP报文。从图中可以发现一个完整的HTTP事务，有链接的建立，请求的发送，响应接收，断开链接这四个过程,早期通过HTTP协议传输的数据以文本为主，一个请求可能就把所有要返回的数据取到，但是，现在要展现一张完整的页面需要很多个请求才能完成，如图片,JS,CSS等，如果每一个HTTP请求都需要新建并断开一个TCP，这个开销是完全没有必要的，开启HTTP Keep-Alive之后，能复用已有的TCP链接，当前一个请求已经响应完毕，服务器端没有立即关闭TCP链接，而是等待一段时间接收浏览器端可能发送过来的第二个请求，通常浏览器在第一个请求返回之后会立即发送第二个请求，如果某一时刻只能有一个链接，同一个TCP链接处理的请求越多，开启KeepAlive能节省的TCP建立和关闭的消耗就越多。当然通常会启用多个链接去从服务器器上请求资源，但是开启了Keep-Alive之后，仍然能加快资源的加载速度。HTTP/1.1之后默认开启Keep-Alive, 在HTTP的头域中增加Connection选项。当设置为Connection:keep-alive表示开启，设置为Connection:close表示关闭。实际上HTTP的KeepAlive写法是Keep-Alive，跟TCP的KeepAlive写法上也有不同。所以TCP KeepAlive和HTTP的Keep-Alive不是同一回事情。<br/><br/>Nginx的TCP KeepAlive如何设置<br/>开篇提到我最近遇到的问题，Client发送一个请求到Nginx服务端，服务端需要经过一段时间的计算才会返回， 时间超过了LVS Session保持的90s,在服务端使用Tcpdump抓包,本地通过wireshark分析显示的结果如第二副图所示，第5条报文和最后一条报文之间的时间戳大概差了90s。在确定是LVS的Session保持时间到期的问题之后，我开始在寻找Nginx的TCP KeepAlive如何设置，最先找到的选项是keepalivetimeout,从同事那里得知keepalivetimeout的用法是当keepalivetimeout的值为0时表示关闭keepalive,当keepalivetimeout的值为一个正整数值时表示链接保持多少秒，于是把keepalivetimeout设置成75s,但是实际的测试结果表明并不生效。显然keepalivetimeout不能解决TCP层面的KeepAlive问题，实际上Nginx涉及到keepalive的选项还不少，Nginx通常的使用方式如下：<br/><a href="https://www.cnmysql.com/attachment.php?fid=29" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=29" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>从TCP层面Nginx不仅要和Client关心KeepAlive,而且还要和Upstream关心KeepAlive, 同时从HTTP协议层面，Nginx需要和Client关心Keep-Alive,如果Upstream使用的HTTP协议，还要关心和Upstream的Keep-Alive，总而言之，还比较复杂。所以搞清楚TCP层的KeepAlive和HTTP的Keep-Alive之后，就不会对于Nginx的KeepAlive设置错。我当时解决这个问题时候不确定Nginx有配置TCP keepAlive的选项，于是我打开Ngnix的源代码，在源代码里面搜索TCP_KEEPIDLE,相关的代码如下：<br/><a href="https://www.cnmysql.com/attachment.php?fid=30" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=30" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>从代码的上下文我发现TCP KeepAlive可以配置，所以我接着查找通过哪个选项配置，最后发现listen指令的so_keepalive选项能对TCP socket进行KeepAlive的配置。<br/><a href="https://www.cnmysql.com/attachment.php?fid=31" target="_blank"><img src="https://www.cnmysql.com/attachment.php?fid=31" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>以上三个参数只能使用一个，不能同时使用， 比如so_keepalive=on, so_keepalive=off或者so_keepalive=30s::(表示等待30s没有数据报文发送探测报文)。通过设置listen 80,so_keepalive=60s::之后成功解决Nginx在LVS保持长链接的问题，避免了使用其他高成本的方案。在商用负载设备上如果遇到类似的问题同样也可以通过这种方式解决。<br/><br/>参考资料<br/>《TCP/IP协议详解VOL1》--强烈建议对于网络基本知识不清楚同学有空去看下。<br/><a href="http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#overview" target="_blank">http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#overview</a><br/><a href="http://nginx.org/en/docs/http/ngx_http_core_module.html" target="_blank">http://nginx.org/en/docs/http/ngx_http_core_module.html</a><br/>Nginx Source code: <a href="https://github.com/alibaba/tengine" target="_blank">https://github.com/alibaba/tengine</a><br/>作者：李成栋阿里技术保障 架构工具资深工程师 <br/><br/></span><br/></span>
]]>
</description>
</item>
</channel>
</rss>