fasionchan

读万卷书,行万里路,品万味肴,撸万行码。

Mac下Ruby安装小结

| Comments

最近,重新拿起博客,发现已有一年多没有动过的Octopress跑不起来了,囧。并不意外,每次Mac一升级,总有一些东西会挂掉,久而久之习惯了。

如何让Octopress重新跑起来呢?重新看安装文档,大头只是安装一个ruby而已。但是,由于对ruby并不熟悉,中间还是踩了个大坑。因此,有必要记一下,免得以后再犯。

使用gdb调试Python程序

| Comments

最近在为一个监控系统开发agent,需要支持LinuxFreeBSDWindows等操作系统。复杂的线上环境,带来了一系列诡异的问题,尽管代码上线前在为数不少的测试机器验证过。

Python程序吐coredump文件怎么办?很多人都会想到gdb加载coredump文件,然后查看信号及堆栈信息,以此分析原因。堆栈信息在调试中非常有用,但是别忘了,你写的是Python代码,但是gdb给你的是C堆栈信息!似乎没啥鸟用!难道要撸Python源码然后分析各种核心数据结构吗?有什么方式可以查看到Python堆栈信息吗?

还遇到过另一个问题,一个Python进程突然间陷入死循环,所有其他线程都调度不到。遇到这种情况,首先可能需要知道死循环到底在干什么。如何获悉呢?可能用strace跟一下系统调用可以看出一点端倪。但是一个堆栈信息更为具体更有说服力,就算是只有C堆栈信息有时也是足以说明问题的。

gdb就可以解决以上难题(其实远不止),接下来,我们一起看看具体要怎么操作吧~

Linux文件描述符

| Comments

Linux通用I/O模型中,I/O操作系列函数(系统调用)都是围绕一个叫做文件描述符的整数展开。这不禁让人产生疑问:这个整数代表什么?一个数值代表一个文件吗?随便传一个整数进去调用可以吗?

解答以上疑问,需要更深入学习——文件描述符(File Descriptor)。

Linux通用IO模型

| Comments

学习Linux系统编程,文件I/O是一个不错的切入点。首先,日常操作中或多或少都使用过文件,有一定的概念;其次,文件I/O可以由几个最最基础的系统调用完成,降低入门理解难度。

基础系统调用

LinuxI/O操作是通用化的,不仅仅可以用来操作文件输入输出,还可以用来操作管道、FIFOsocket、终端设备等。将设备抽象成一个文件,用I/O操作控制设备是类Unix系统一大特色。

使用Python获取金融数据

| Comments

俗话说,“巧媳妇难为无米之炊”。做金融数据研究,首先要有可用的数据源。 Python下,pandas_datareader模块可以用于获取研究数据。例子如下:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
>>> from pandas_datareader.data import DataReader
>>>
>>> datas = DataReader(name='AAPL', data_source='yahoo', start='2018-01-01')
>>>
>>> type(datas)
<class 'pandas.core.frame.DataFrame'>
>>> datas
                  Open        High         Low       Close   Adj Close  \
Date
2018-01-02  170.160004  172.300003  169.259995  172.259995  172.259995
2018-01-03  172.529999  174.550003  171.960007  172.229996  172.229996
2018-01-04  172.539993  173.470001  172.080002  173.029999  173.029999
2018-01-05  173.440002  175.369995  173.050003  175.000000  175.000000
2018-01-08  174.350006  175.610001  173.929993  174.350006  174.350006
2018-01-09  174.550003  175.059998  173.410004  174.330002  174.330002
2018-01-10  173.160004  174.300003  173.000000  174.289993  174.289993
2018-01-11  174.589996  175.490005  174.490005  175.279999  175.279999
2018-01-12  176.179993  177.360001  175.649994  177.089996  177.089996

              Volume
Date
2018-01-02  25555900
2018-01-03  29517900
2018-01-04  22434600
2018-01-05  23660000
2018-01-08  20567800
2018-01-09  21584000
2018-01-10  23959900
2018-01-11  18667700
2018-01-12  25226000
>>>
>>> print(datas.to_csv())
Date,Open,High,Low,Close,Adj Close,Volume
2018-01-02,170.160004,172.300003,169.259995,172.259995,172.259995,25555900
2018-01-03,172.529999,174.550003,171.960007,172.229996,172.229996,29517900
2018-01-04,172.539993,173.470001,172.080002,173.029999,173.029999,22434600
2018-01-05,173.440002,175.369995,173.050003,175.0,175.0,23660000
2018-01-08,174.350006,175.610001,173.929993,174.350006,174.350006,20567800
2018-01-09,174.550003,175.059998,173.410004,174.330002,174.330002,21584000
2018-01-10,173.160004,174.300003,173.0,174.289993,174.289993,23959900
2018-01-11,174.589996,175.490005,174.490005,175.279999,175.279999,18667700
2018-01-12,176.179993,177.360001,175.649994,177.089996,177.089996,25226000

>>>

首先,引入DataReader方法; 然后,以股票代码(name)、数据源(data_source)以及开始日期(start)为参数,调用DataReader获取数据; 获取到的数据(datas)是一个DataFrame,以日期(Date)为索引,包含OpenHighLowClose等多列指标。 DataFrame数据也可以非常方便地转换成csv格式并输出。

注意到,pandas_datareader还可以使用其他数据源,比如Google Finance。 更多关于pandas_datareader使用方式,请参考:pandas-datareader文档

谈谈TCP TIME_WAIT状态

| Comments

学过TCP协议的童鞋对以下状态变迁图应该不陌生,本文着重讨论TIME_WAIT状态。

从图中可以清楚看到:主动关闭的一端最终会进入TIME_WAIT状态,并维持2*MSL时间,一般情况下为240秒。 那么,为什么需要TIME_WAIT状态呢?为什么需要持续2*MSL时长呢?其中有什么特别的考虑吗?

作用

从上图可以看到,进入TIME_WAIT状态前,收到对端FIN包并且回复ACK包。 网络是不可靠的,也就是说最后这个ACK包可能被中间链路丢掉了。 对端协议栈在还有收到ACK包的情况下,将重传FIN包,本端需要对FIN包进行相应。 如果此时连接资源已经回收,系统只能响应RST包,这时对端就会认为是异常退出。 因此,保留TIME_WAIT状态套接字并维持一段时间,就可以正确响应对端重传的FIN包,让TCP连接优雅关闭。

另一场景是,对端可能还有FIN包还在网络逗留(延迟)。 如果新连接复用旧连接的所有要素(包括地址-端口对、TCP序列号),旧连接迟到的FIN终止新连接! 当然了,这个场景出现的概率比较低,但还是存在。

问题

当一个系统主动关闭大量TCP连接时,由于2MSL存在,将产生大量的TIME_WAIT状态连接。 TCP连接需要消耗一定的系统资源,因此,极端情况下将导致活跃连接响应速度下降甚至停止服务

发起主动关闭的一端一般是客户端,这时候意味着服务端可以高枕无忧呢?

肯定不是的。服务端也有很多场景会发起主动关闭,最常见的应该是类似nginx之类的反向代理了。

如上图,Web服务经常按照业务逻辑进行划分并独立部署,前端采用Nginx做统一接入以及负载均衡。 对Web服务器来说(黄色部分),Nginx服务器为客户端。在Nginx转发请求完成后,主动关闭不可避免。 这样,当系统存在高并发短连接请求时,Nginx服务器上有大量TIME WAIT状态连接存在也就不奇怪了。

解决方案

开启SYN Cookies

SYN队列溢出时,采用Cookie来处理,继续接受新连接。 SYN Cookie可以在一定程度防范SYN Flood攻击,详情请参看这里。 配置选项为net.ipv4.tcp_syncookies,可以采用sysctl或者proc伪文件系统两种方式设置。

sysctl方式。编辑文件/etc/sysctl.conf,调整或增加以下行:

1
net.ipv4.tcp_syncookies = 1

调整完成后,运行命令sysctl -p即可生效。

proc伪文件系统方式

1
2
3
4
5
6
7
8
9
# 查看当前值
$ cat /proc/sys/net/ipv4/tcp_syncookies
0

# 开启
$ echo 1 > /proc/sys/net/ipv4/tcp_syncookies

# 关闭
$ echo 0 > /proc/sys/net/ipv4/tcp_syncookies

开启TIME_WAIT重用

开启net.ipv4.tcp_tw_reuse选项,将允许将TIME_WAIT状态socket重新用于新的TCP连接。 设置方式也可用通过sysctlproc伪文件系统方式,请参考上节,下文不在赘述。

开启TIME_WAIT快速回收

开启net.ipv4.tcp_tw_recycle选项,快速回收处于TIME_WAIT状态的socket

修改FIN超时时间

修改net.ipv4.tcp_fin_timeout选项。

扩大外连端口范围

修改net.ipv4.ip_local_port_range选项。这个选项表示向外连接的端口范围。 当然了,扩大范围只能缓解问题,无法彻底解决,另外端口也存在最大值65000左右。

net.ipv4.tcp_max_syn_backlognet.ipv4.tcp_max_tw_bucketsnet.ipv4.tcp_keepalive_time

设置SO_LINGER选项

围观Scrapy爬虫框架

| Comments

对于Scrapy这个爬虫框架,先前也是知道有这么个东西存在,仅此而已。最近在面试时,发现很多人写过Python爬虫采集数据,所用的框架几乎都是Scrapy。今天刚好闲着没事做,就来玩玩Scrapy呗。

简介

框架

HTTP压力测试潜在问题若干

| Comments

首先,用ulimit -n看看是不是文件描述符设置过小而被打满:发现设置值是65536,这是10000个并发不可能用满的。当然,大部分服务器上都是采用默认配置1024,这时就是罪魁祸首了。

backlog太小

各种可能的原因都查了查了,最后发现是由于底层套接字调用listenbacklog参数太小造成的!listen系统调用的作用是使TCP套接字进行监听状态,backlog是内核维持请求连接队列的个数限制(不包括已经被accept的连接)。我要测试的WEB接口是用基于tornado框架的,绑定端口时backlog默认参数是128,很快就被10000个请求给压满了,这就是ab各种超时的主要原因!调大这个参数后问题就解决了~