开始贴老blog
以前在cu上的blog,虽然整体写的比较乱。不过也算是自己以前折腾了好久写的,准备慢慢迁移过来。。
以前在cu上的blog,虽然整体写的比较乱。不过也算是自己以前折腾了好久写的,准备慢慢迁移过来。。
这两天看了下TCP/IP详解的第二卷,买了很久把第一卷和第三卷大概都看了下,但是第二卷一直没有怎么看过。实际上在第一卷里就经常提到这个定时器的概念,在第二卷里25章是专门介绍定时器的。7种定时器分别是1.连接建立定时器。在发送每个SYN的时候会启动,如果在75s内没有收到对方的ACK,那么连接终止。2.保活定时器。在新建socket的时候如果指定了SO_KEEPALIVE才会生效。链接超过设置的时候就会连续发几次探测包,如果对几次尝试都没有收到回复就减低对方已经崩溃。这个两个定时器的实现: 3.重传定时器。在发送数据的时候,如果指定时间内没有收到对放的回复就会启动重传。如果一次重传后对方还是没有回应,那么这个重转时限每次都会进行调整,越来越长。4.persist定时器。在连接的对端通告窗口为0 的时候会启动一个定时器,在指定的时间内不像对方发送数据。当定时器超时后才会向对方发送1字节的数据。5.延迟ACK定时器。当收到对方的确认请求后,这个请求虽然是必须要确认的,但是不是太急,那么就启动定时器200ms,如果在这个定时器超时之前又收到对方的数据,那么就把最新的ACK发回去就行了。这个主要是持续传输数据的时候使用,比如A向B先发出了N-N+1000报文段,这个时候A就期望收到ACK是N+1001,如果A接着继续发了N+1001-N+2001,那么只需要把ACK的序号设置为N+2002就能对前面的2个报文一起做确认了。6.FIN_WAIT2定时器。A与B是ESTABLISHED的时候,如果A主动发起关闭,调用了close,那么就A会主动对B发送FIN,这个时候A就进入了FIN_WAIT1状态,而B在收到FIN后回复ACK时就变成了CLOSE_WAIT,在A发出FIN和收到ACK的这段时间内A处于FIN_WAIT1,A收到ACK后状态变化为FIN_WAIT2。但是如果B始终不给A发FIN包,岂不是A就一直得在FIN_WAIT2状态?所以有了FIN_WAIT2定时器,linux下默认是60s,其实就是内核参数tcp_fin_timeout 设置的那个参数。当定时器超时后就会把FIN_WAIT2会自动转换到TIME_WIAT状态。7.TIME_WAIT定时器。这个就是2MSL的时间了,链接主动关闭后等待回收的一段时间,2MSL称为平静时间,就是为了防止如果这个socket被马上重新使用了,之前的那个链接有迟到(后者重传过来的包)到了的话会被新socket直接接收到。linux对这个的定义是写死在头文件的。定义在net/tcp.h #define TCP_TIMEWAIT_LEN (60*HZ) 约为60s 可能每个系统具体的实现和书上的不一样,不过从概念上还是好理解的。
很久很久以前,nginx的upstream还不支持HTTP 1.1的时候,nginx做反响代理时只能使用短链接。设想以下的结构中CLient–http 1.1 keepalive —>Nginx(proxy)—http 1.1 connection: close–>APP 经常会看到后端APP上有大量的TIME_WAIT状态的链接。这几天又重新读了一下TCP详解和UNP。状态变迁图如下 根据上图如果是客户端先发FIN包主动关闭,服务端其实是不会进入TIME_WAIT状态的 如果是客户端和服务端同时关闭的话,客户端和服务端都会出现TIME_WAIT的状态 apache设置keepalive Off的时候每次都会主动关闭掉,所以TIME_wait的数量非常多。 主要不是客户端完全主动关闭,那么服务端都是会出现这个TIME_WAIT的。 针对apache的keepalive on和off都单独抓包了。 On Off 以上2图中的客户端都是10.253.85.156可以清楚的看到当时keepalive设置为on的时候都是客户端先发FIN包,而设置为Off的时候都是服务器端先发FIN包去关闭。 在TCP/IP详解第三卷其实也有说明 今天又发现线上的机器有很多CLOSE_WAIT状态的链接,接近1W个。。又反复看了下TCP/IP详解的内容。基本定位为本地发起链接去连接远程的8080端口, 远程的服务端在完成了一个调用后主动发起链接关闭发了一个FIN包给本地服务器,然后就没有下文了,就产生了CLOSE_WAIT。。正常情况下本地服务器需要回一个ACK后再向对远程服务器发一个FIN包,再等到对方回复ACK后才能CLOSE。为了证实我的猜测我也到这里的“远程服务器“去查看了一下,发现很多链接处于FIN_WAIT2的状态。对于FIN_WAIT2的链接默认会在60s后进行回收,加入特别多的话可以降低tcp_fin_timeout。其实产生CLOSE_WAIT的原因也就是自己没有去调用close来关闭连接。比如connfd = accept(listenfd,xxx,xx)后对这个connfd进行操作完就直接不管了,而对方在完成操作后自己调用了close关闭了链接,这个时候自己就一直处于CLOSE_WAIT的状态,网上有很多说法说这个状态2小时后会被回收,但是实际测试linux根本不会回收的。叔度的这个blog也提到了类似的问题,这种情况基本都是软件有bug。。 [blog](http://blog.zhuzhaoyuan.com/2009/03/a-word-on-time_wait-and-close_wait/)
用了个老的RHEL 4.X的机器,蛋疼无比。。bash不支持hash,自带的很多perl的库bug一堆。今天准备写个脚本又遇到个问题。自带的LWP库太老了,搞出段错误了。。 后来把IO::Socket::SSL升级完才算能用 不过现在跑个脚本多会跑出一端报警,LWP Agent里面好像又没有参数可以传进去设置这个,而且以前的很多脚本还地改,然后我就直接把这段警告消息给注释了。实在不想折腾这个老东西。/usr/lib/perl5/site_perl/5.8.5/IO/Socket/SSL.pm
使用一个nginx做全局的代理负载均衡集群时遇到了一点问题。主要是前面的nginx集群机器很多(M个),每个nginx机器的进程也很多(N个),然后设置的keepalive数量和upstream里的机器数量相同。 这个时候如果后端机器的连接数限制比较小就杯具了,平时每个后端机器的长链接数差不多是MN +XX ,因此链接的利用率(XX)/(MN+XX) 。当前面的机器和单机进程数很多的时候链接的利用率就会非常低。造成健康检测时后端的机器检查失败,直接被踢掉了,引发雪崩效应。 这个时候如果后端的应用不改,那么唯一的2种方案: 1、改成短链接。可能整体的响应时间有所增加。2、适当降低keepalive的值,但是降低的太多会使得和短链接差不多的效果。很难定量的衡量这个值的最佳性,只能不断测试。 其实在apache的mod_jk模块里也是统一存在这样的问题``` Timeout 180KeepAlive OnMaxKeepAliveRequests 1000KeepAliveTimeout 360 StartServers 10ServerLimit 50MaxClients 1500MinSpareThreads 50MaxSpareThreads 200ThreadsPerChild 50MaxRequestsPerChild 10000 如果前面的很容易造成的情况是apache的jk把后端tomcat的链接数(400)撑爆了,但是实际上很多链接又闲着。主要是每个进程的信息是独立的,每个进程最多能有100个连接,整体的量就很难控制,尤其是上面这个空闲连接的回收时间设置的不合理。实际测试就是把这个回收的时间缩短,改成1,然后把cachesize降低到50 效果就好了很多。
今天主要是还原一个线上的问题,自己搞了几个机器配置了一下nginx模拟做代理时后端服务器速度跟不上的问题。基本的结构如下 client —->nginx(proxy)—nginx server(limit rps 400/s) 因为我总的就3个机器,所以后端的nginx server里面配置的是 limit_conn_zone $binary_remote_addr zone=connzone:10m; limit_req_zone $binary_remote_addr zone=reqzone:10m rate=400r/s; server {listen 1081; server_name localhost; keepalive_requests 1000; 简单的对比测试了一下后端限速和不限速的情况。当后端不限速的时候压测时代理proxy 的load非常高,单个核的机器CPU使用率能到100%,usr,sys,soft各占了30%左右,但是后端服务器的load比较低,只有20%左右。当后端机器限速的时候proxy上会出现大量的503,并且load还是很高,基本和前面的相同,但是后端的服务器load也会比较高,在30%–80%间波动。检查后端服务器的日志可以发现很多健康检测的请求被置为了503,也就是存在服务器被踢掉的情况。 另外顺便测试了一下apache的配置,之前的woker的配置``` Timeout 180KeepAlive OnMaxKeepAliveRequests 100KeepAliveTimeout 360 StartServers 10ServerLimit 50MaxClients 1500MinSpareThreads 50MaxSpareThreads 200ThreadsPerChild 50MaxRequestsPerChild 10000
由于代理服务器上开启了长连接后,可以减少每次与后端服务器的三次握手,提高后端服务器的效率。所以nginx在1.1.4版本中终于增加了upstream对keepalive的支持,而haproxy原本对后端是支持长连接的(但是这个时候由于不能把client的IP加到header转发给后端服务器造成会丢失客户端的IP)。今天简单测试了一下。基本的结构是A:Client –> nginx(proxy) –>nginx(server)B:Client –> haproxy(proxy) –>nginx(server) 对比的结构 Client –>nginx(server) 先测试一下client直接和server端能否保持住长连接,我是直接在server端抓包观察,确定OK后再进行nginx和haproxy的测试。 nginx proxy的配置如下: server { location / {root html; proxy_set_header Connection ""; proxy_http_version 1.1; proxy_intercept_errors on; proxy_set_header Host $http_host; proxy_set_header ORIG_CLIENT_IP $remote_addr; index index.html,index.htm; proxy_pass http://httpd; } 0172.189.085.161.50970-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50970: HTTP/1.1 304 Not Modified0172.189.085.161.50971-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50971: HTTP/1.1 404 Not Found0172.189.085.161.50972-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50972: HTTP/1.1 304 Not Modified0172.189.085.161.50973-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50973: HTTP/1.1 404 Not Found0172.189.085.161.50974-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50974: HTTP/1.1 304 Not Modified0172.189.085.161.50975-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50975: HTTP/1.1 404 Not Found0172.189.085.161.50976-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50976: HTTP/1.1 304 Not Modified0172.189.085.161.50977-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50977: HTTP/1.1 404 Not Found0172.189.085.161.50978-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50978: HTTP/1.1 304 Not Modified0172.189.085.161.50979-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50979: HTTP/1.1 404 Not Found0172.189.085.161.50980-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50980: HTTP/1.1 304 Not Modified0172.189.085.161.50981-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50981: HTTP/1.1 404 Not Found0172.189.085.161.50982-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50982: HTTP/1.1 304 Not Modified0172.189.085.161.50983-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50983: HTTP/1.1 404 Not Found0172.189.085.161.50984-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50984: HTTP/1.1 304 Not Modified0172.189.085.161.50985-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50985: HTTP/1.1 404 Not Found0172.189.085.161.50986-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50986: HTTP/1.1 304 Not Modified0172.189.085.161.50987-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50987: HTTP/1.1 404 Not Found0172.189.085.161.50988-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50988: HTTP/1.1 304 Not Modified0172.189.085.161.50989-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50989: HTTP/1.1 404 Not Found0172.189.085.161.50990-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50990: HTTP/1.1 304 Not Modified0172.189.085.161.50991-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50991: HTTP/1.1 404 Not Found0172.189.085.161.50992-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50992: HTTP/1.1 304 Not Modified0172.189.085.161.50993-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50993: HTTP/1.1 404 Not Found0172.189.085.161.50994-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50994: HTTP/1.1 304 Not Modified0172.189.085.161.50995-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50995: HTTP/1.1 404 Not Found0172.189.085.161.50996-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50996: HTTP/1.1 304 Not Modified0172.189.085.161.50997-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50997: HTTP/1.1 404 Not Found server { ```bash location / {root html;proxy_set_header Connection "";proxy_http_version 1.1;proxy_intercept_errors on;proxy_set_header Host $http_host;proxy_set_header ORIG_CLIENT_IP $remote_addr;index index.html,index.htm;proxy_pass http://httpd;} 0172.189.085.161.50998-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 304 Not Modified0172.189.085.161.50998-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 404 Not Found0172.189.085.161.50998-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 304 Not Modified0172.189.085.161.50998-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 404 Not Found0172.189.085.161.50998-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 304 Not Modified0172.189.085.161.50998-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 404 Not Found0172.189.085.161.50998-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 304 Not Modified0172.189.085.161.50998-0172.189.085.156.01080: GET /favicon.ico HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 404 Not Found0172.189.085.161.50998-0172.189.085.156.01080: GET /index.html HTTP/1.10172.189.085.156.01080-0172.189.085.161.50998: HTTP/1.1 304 Not Modified 然后我又测试了一下haproxy。主要是之前对haproxy的理解有点误区。一方面doc里面说了 ```bash A last improvement in the communications is the pipelining mode. It still useskeep-alive, but the client does not wait for the first response to send thesecond request. This is useful for fetching large number of images composing apage : [CON] [REQ1] [REQ2] … [RESP1] [RESP2] [CLO] … ...
在淘宝上买了个而20来块钱包邮的USB 声卡,芯片是CM108的(CM108比CM109好一点的)。之前一直以为没有驱动起来搞的还单独安装了CM109的驱动,后来发现DB120是只有下面的那个USB接口能识别声卡,上面的那个虽然能接U盘,但是不能挂一些设备(比如U盾)。需要安装的软件其实也不多#安装 USB驱动,文件系统模块,和自动挂载工具opkg install kmod-usb2 kmod-nls-utf8 kmod-usb-storage kmod-usb-ohci block-mount kmod-fs-ext4#安装声卡驱动 和alsa工具opkg install alsa-utils kmod-usb-audio#安装播放器opkg install madplay 需要注意声卡默认音量是最大声,Openwrt下保存不了配置文件,我就在rc.local里加了一句/usr/sbin/alsactl init把音乐拷到U盘,然后就能播放了 madplay -v –tty-control -r /mnt/usb/music/*.mp3
鉴于google在国内不是太稳定,平时很多简单的问题还是习惯直接baidu一把。但是发现到了加入百度推广联盟的网站上时自动跳出来的广告非常精准,广告的都是自己想要的东西,突然想到是不是自己在用百度的时候被追踪了。看了下cookie信息确实如次。当用户访问百度的时候,百度会创建一个30才过期的BAIDUID,然后当你搜索一个关键词的时候实际就百度记录下来了。幸好chrome有个配置恰好可以设置把单个域的cookie在退出的时候清理掉。设置–高级设置–内容设置–管理例外情况,然后添加主机名是“baidu.com” 后面选上关闭浏览器删除。
今天突然想起把自己之前写的一个脚本换成多线程的模式改写一下,因为之前的模式很多时间都阻塞住了,每次批量搞几千个机器太费时。先是使用老的Thread模块把脚本改写的一遍,都把脚本写好了验证OK才发现这个是老的模块,不推荐使用,肺都气炸了。还好新的threads模块也类似,简单修改了一下也OK,而且新模块的功能强大很多,可靠性也好。测试一下 #!/usr/bin/perl use strict; use warnings; use threads; my @test=(1...988); srand(); &muti_work; sub muti_work(){ my $JOBN=30; my $jobs=0; while(@test){ if($jobs<$JOBN && $jobs>=0) { my $pid=threads->create(\&echon,shift @test); $jobs++; } elsif($jobs>=$JOBN) { my @actlist=threads->list(threads::joinable); foreach my $t (@actlist) { $t->join; $jobs--; } sleep 0.1; } } while($jobs>0) { my @actlist=threads->list(threads::joinable); foreach my $t(@actlist){ $t->join; $jobs--; } sleep 0.5; } } sub echon(){ my $num=shift; my $t=int(rand(8)); sleep $t; my $thr = threads->self(); print "i am working $num sleep $t\n"; threads->exit(0); } print "ok\n"; 如果涉及到每个线程都有一个返回值的话,可以在函数里面直接运行return就行。使用my $vat=$t->join的形式进行返回值的获取。如果返回的是一个数组,也是可以直接return @list的,但是thread->create的时候需要加参数。详细的看cpan的文档。 ...