大连的软件外包

前几天在大连和几个朋友和前同事聚了聚,都是做软件的自然话题少不了程序员和软件。大连这几年依靠语言和人才优势还有大连市政府的强有力支持和推进,在软件外包方面做的比较成功。有个朋友在 SAP,朝鲜族,生来就会韩语和汉语,然后上学学的是日语,大学修了英语并且过了六级,等毕业的时候就会了4门语言。东北在日语和韩语方面的优势是全国其他城市不具备的,而且东北有很多不错的高校提供了源源不断的生源,再加上大连得天独厚的自然环境和城市建设,这些都使得大连成为外包产业的领军城市。

很多人觉得做软件外包技术含量低、没前途、薪水低、体力活,VPSee 认为发展外包产业是非常符合中国国情的,巨大的外包市场帮助中国消耗了大量的人力,解决了很多人的就业,尤其是应届毕业生的就业问题。外包公司就像培训机构一样,把一群群刚出炉、没有实战经验的大学生锻造成一个个编程熟手。中国缺乏大型工程项目管理人才,大的外包公司在长期的项目实施过程中会积累很多大型项目开发的经验和培养出一批项目管理人才(尽管还是有很多程序员质疑自己上司的管理能力)。这些经验的积累和人才的培养对中国都是有利的。软件外包的技术核心不在软件,而是在正确的理解客户需求、良好的沟通、大型项目的管理以及随需而变的优质服务。

因为中国人口太多,人力成本太低,所以单纯发展高科技在中国是投资大收益小吃力不讨好的事情,无利可图就不会有商人和投资,没有商业运作就不会成气候。假如我现在要把一本书的内容输入到电脑,一种办法是购买文本识别软件,把书扫描后用文本识别软件把文字识别出来存入文本文档;一种办法是找个人打字,一个字一个字输入电脑;还有一种办法就是使用盗版软件。在国外,使用盗版软件行不通,请人打字成本非常高,所以一般选择使用文本识别软件或者干脆外包给其他国家的人打字,这促使了软件开发商和投资人积极投入到软件研发,开发出更好更准确的识别软件。在中国,首选盗版软件,如果没有盗版可用,雇佣几个人打字也不是很贵,在中国开发一套文本识别软件是没有市场的,软件没市场就没人愿意投资,金钱如果不往这个行业流动就无法带动起一个产业。严格的是说,中国没有软件产业,软件外包不能算软件产业。与软件形成鲜明对比的是硬件和互联网产业,这两个产业在中国都发展的很好,现在中国互联网、网游市场很发达,国外的互联网服务、网站几乎打不进来。

外包工作做长了以后程序员就会产生困惑,特别是对自己职业生涯、技术生涯产生疑问,这也是为什么外包企业流动量大的原因。听一个猎头朋友说因为金融危机今年很多外资公司缩减了招聘需求,他现在基本在接其他的活来维持公司运转,等到明年5、6月份左右再重返人力猎头市场。和几个朋友交谈了解到,HP 已经有两年没有涨工资,几个 IBM 朋友打算跳槽,松下的一个部门被撤了,剩下的优质员工被 OKI 吸收了一部分,为了节约成本 OKI 甚至还买了松下剩下的办公桌椅。小日本在控制成本方面很有一套。

提到软件外包就不得不提东软这家公司,现在拥有约2万员工,在大连软件园周围丢一块砖就会砸到一个东软人(或者曾经在东软工作)。东软在东北知名度很高,在程序员眼里不算太好,主要是因为薪水不高,加班没有加班费,不过东软在客户那里口碑还是不错的。东软的办公环境不错,很像大学校园,食堂宿舍都在一个园子里。东软的高流动率为大连的软件外包企业输送了大量人才,现在很多 IBM、HP、OKI、松下、埃森哲等在大连的外资软件企业都可以找到来自东软背景的员工。不夸张的说,在软件园区、数码广场周围吃饭,一桌子10个人可能一半都来自东软或者曾经在东软工作过。不过 VPSee 到现在都不明白为什么东软允许这么高的流动率,高的流动率对公司是不利的,招聘、培训新员工的成本很高,自己培养了员工却送给了竞争对手,就像中国培育了大量博士生然后跑到美国给美国做贡献一样,竞争对手反过来用这些员工和东软抢单子。不过东软能活到现在一定不简单,也许东软有一些大家都不知道的秘密武器吧。我猜测东软正是依靠这种低成本优势把中国制造业的代工模式成功复制到了软件行业。

在大连呆几天后就要去武汉,一个呆了四年就不想再回去的城市,一个换登机牌不排队的城市~~

Google Chrome OS 想干嘛?

在机场转机的时候从网上下了一个 Chrome OS 的 VMware 镜像,很惊讶机场居然没有限制 Wi-Fi 上网的流量和时间。把下载后的镜像解开后直接在 VMware Fusion 下启动,用 Gmail 账号登陆后就可以看到界面了,界面非常类似 Chrome 浏览器。

chrome

玩了玩 Chrome OS 后,谈谈个人对 Chrome OS 的一些想法。表面上看 Google 在同一个市场(上网本、上网终端)推出了两个类似的产品:Android 和 Chrome,注意 Android 也可以移植到上网本上。有人可能会认为同时存在 Android 和 Chrome OS 增加了市场混乱,而且在开发人员眼里增加了开发多平台的难度,多一个平台就多了一套 SDK/API,实际上没有那么复杂,Chrome OS 上的一切程序都是 web app,能在浏览器上运行就能在 Chrome OS 上运行,所以不用特别为 Chrome OS 开发应用程序。Chrome OS 就目前看来就是一个浏览器,Chrome OS 有的功能现在任何带浏览器的操作系统都有,显然 Chrome OS 的竞争对手不是现有的 PC 操作系统。考虑到手机的特殊性,Chrome OS 目前也不能替代 Android,竞争对手也不是 Android. 现在的问题是为什么 Google 要推出另一个操作系统?

VPSee 大胆猜测一下,Google 对 Chrome OS 的期望和未来的计划不仅仅是上网本这么简单。Google 的目标是统一通信和网络,使用任何装置都可以上网、打电话、使用 web app,推出 Chrome OS 这一系统是想加速这一转变过程。Google 想依靠自己强大的数据中心和网络建立和提供统一的通信基础设施和网络,把互联网和电话网络连在一起。从用户角度看就是可以通过浏览器使用低廉甚至免费的电话、语音信箱、电话会议等服务。

Google 最近又收购了一家基于 SIP 的 VoIP 公司 Gizmo5,Google 本身拥有基于 XMPP 的 VoIP 软件 Gtalk,并且 Gtalk 的功能包括视频在内都已经被移植到了 Gmail 上,Google 还推了 Google Voice,上个星期还收购了一家手机广告商 AdMob. 可以看出 Google 正在一步一步的把 VoIP 和手机移植到 web app. Chrome OS 现在不能替代 Android 是因为 Chrome OS 不能打电话,如果 Google 推出 web app 并改善 Chrome OS 使得 Chrome OS 能通过 Google Voice 或其他服务访问到全球电话网络的话,那么我们就不需要电话、手机了,任何带浏览器的装置,比如:上网本、手机、电脑等各种终端都可以当做电话使用并且在 Google 有一个唯一的电话号码。这个时候受打击的应该是 Nokia 等手机制造商,所以现在手机制造商也在推出类似的上网终端向互联网靠拢,比如 Nokia N900,基于 Maemo 开源平台的 mobile computer.

如果 Chrome OS 能成功的话,那未来将是 web app 的天下,现在一般都在云上部署 web app,计算方式也正在从个人计算向云计算转变,所以这就是为什么现在云计算这么火的原因。

开始休假,博客不定期更新

holiday

忙了一年,终于到了放长假的时候,下午收拾行李准备回家。今年很幸运争取到了六个礼拜的假期。假期没有安排什么内容,主要是回家看看父母、陪父母到处玩玩。然后就是跟一些同学、朋友腐败一下,可惜他们不在假期,那 VPSee 只能主动去骚扰他们了:)

回家是愉快的,旅途是遥远的,准备了一本 Founders at Work 可以在等机和机场转机的时候打发时间(在没有 MM 可以看的时候)。

博客更新将不会很频繁,估计一、两个星期会有一篇吧。

适合阅读的 Terminal.app 配色方案

记得很久以前在 Slashdot 看过的一篇关于颜色对比的文章和一些评论,有人建议浅黄色字体深蓝色背景是 terminal 的最好的配色方案,容易阅读而且不易疲劳。这种配色方案也适合程序员长时间使用编辑器阅读代码,或者系统管理员编辑系统配置文件。不过也有人说黑色字体浅黄色背景最容易阅读。建议多试几种,看看哪种配色方案最适合自己。

周末在网上闲逛的时候发现一个很不错的 Mac OSX 10.5 下的 Terminal 模版 giovanni_style,采用的就是浅黄色字体深蓝色背景方案,下载 giovanni_style 后打开 Terminal.app,在 Shell->Import… 导入即可。
giovanni style for mac os x terminal

Wired9:£3.49 128MB OpenVZ VPS

wired9

Wired9 一家刚创立不久的英国 VPS provider,服务器租用的是 Hivelocity 的设备。因为域名是这个月初才注册的,所以没有多少信息可以挖掘,甚至 Google 搜索 wired9 关键字都找不到他们家的网站。大家随便看看吧。VPS 配置如下:

服务器在 UK、US
SolusVM 控制面板
10GB 硬盘
128MB Ram,256MB Burst
30GB 带宽
3.49英镑(约5.76美元)

没有服务器和网络等信息。

Linux 性能监测:Network

网络的监测是所有 Linux 子系统里面最复杂的,有太多的因素在里面,比如:延迟、阻塞、冲突、丢包等,更糟的是与 Linux 主机相连的路由器、交换机、无线信号都会影响到整体网络并且很难判断是因为 Linux 网络子系统的问题还是别的设备的问题,增加了监测和判断的复杂度。现在我们使用的所有网卡都称为自适应网卡,意思是说能根据网络上的不同网络设备导致的不同网络速度和工作模式进行自动调整。我们可以通过 ethtool 工具来查看网卡的配置和工作模式:

# /sbin/ethtool eth0
Settings for eth0:
	Supported ports: [ TP ]
	Supported link modes:   10baseT/Half 10baseT/Full 
	                        100baseT/Half 100baseT/Full 
	                        1000baseT/Half 1000baseT/Full 
	Supports auto-negotiation: Yes
	Advertised link modes:  10baseT/Half 10baseT/Full 
	                        100baseT/Half 100baseT/Full 
	                        1000baseT/Half 1000baseT/Full 
	Advertised auto-negotiation: Yes
	Speed: 100Mb/s
	Duplex: Full
	Port: Twisted Pair
	PHYAD: 1
	Transceiver: internal
	Auto-negotiation: on
	Supports Wake-on: g
	Wake-on: g
	Current message level: 0x000000ff (255)
	Link detected: yes

上面给出的例子说明网卡有 10baseT,100baseT 和 1000baseT 三种选择,目前正自适应为 100baseT(Speed: 100Mb/s)。可以通过 ethtool 工具强制网卡工作在 1000baseT 下:

# /sbin/ethtool -s eth0 speed 1000 duplex full autoneg off

iptraf

两台主机之间有网线(或无线)、路由器、交换机等设备,测试两台主机之间的网络性能的一个办法就是在这两个系统之间互发数据并统计结果,看看吞吐量、延迟、速率如何。iptraf 就是一个很好的查看本机网络吞吐量的好工具,支持文字图形界面,很直观。下面图片显示在 100 mbps 速率的网络下这个 Linux 系统的发送传输率有点慢,Outgoing rates 只有 66 mbps.

# iptraf -d eth0

linux system performance monitoring: network

netperf

netperf 运行在 client/server 模式下,比 iptraf 能更多样化的测试终端的吞吐量。先在服务器端启动 netserver:

# netserver 
Starting netserver at port 12865
Starting netserver at hostname 0.0.0.0 port 12865 and family AF_UNSPEC

然后在客户端测试服务器,执行一次持续10秒的 TCP 测试:

# netperf -H 172.16.38.36 -l 10
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.32      93.68

从以上输出可以看出,网络吞吐量在 94mbps 左右,对于 100mbps 的网络来说这个性能算的上很不错。上面的测试是在服务器和客户端位于同一个局域网,并且局域网是有线网的情况,你也可以试试不同结构、不同速率的网络,比如:网络之间中间多几个路由器、客户端在 wi-fi、VPN 等情况。

netperf 还可以通过建立一个 TCP 连接并顺序地发送数据包来测试每秒有多少 TCP 请求和响应。下面的输出显示在 TCP requests 使用 2K 大小,responses 使用 32K 的情况下处理速率为每秒243:

# netperf -t TCP_RR -H 172.16.38.36 -l 10 -- -r 2048,32768
TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INET
Local /Remote
Socket Size   Request  Resp.   Elapsed  Trans.
Send   Recv   Size     Size    Time     Rate         
bytes  Bytes  bytes    bytes   secs.    per sec   

16384  87380  2048     32768   10.00     243.03   
16384  87380 

iperf

iperf 和 netperf 运行方式类似,也是 server/client 模式,先在服务器端启动 iperf:

# iperf -s -D
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
Running Iperf Server as a daemon
The Iperf daemon process ID : 5695

然后在客户端对服务器进行测试,客户端先连接到服务器端(172.16.38.36),并在30秒内每隔5秒对服务器和客户端之间的网络进行一次带宽测试和采样:

# iperf -c 172.16.38.36 -t 30 -i 5
------------------------------------------------------------
Client connecting to 172.16.38.36, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  3] local 172.16.39.100 port 49515 connected with 172.16.38.36 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0- 5.0 sec  58.8 MBytes  98.6 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3]  5.0-10.0 sec  55.0 MBytes  92.3 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 10.0-15.0 sec  55.1 MBytes  92.4 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 15.0-20.0 sec  55.9 MBytes  93.8 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 20.0-25.0 sec  55.4 MBytes  92.9 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 25.0-30.0 sec  55.3 MBytes  92.8 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-30.0 sec    335 MBytes  93.7 Mbits/sec

tcpdump 和 tcptrace

tcmdump 和 tcptrace 提供了一种更细致的分析方法,先用 tcpdump 按要求捕获数据包把结果输出到某一文件,然后再用 tcptrace 分析其文件格式。这个工具组合可以提供一些难以用其他工具发现的信息:

# /usr/sbin/tcpdump -w network.dmp
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
511942 packets captured
511942 packets received by filter
0 packets dropped by kernel

# tcptrace network.dmp 
1 arg remaining, starting with 'network.dmp'
Ostermann's tcptrace -- version 6.6.7 -- Thu Nov  4, 2004

511677 packets seen, 511487 TCP packets traced
elapsed wallclock time: 0:00:00.510291, 1002714 pkts/sec analyzed
trace file elapsed time: 0:02:35.836372
TCP connection info:
  1: zaber:54581 - boulder:111 (a2b)                   6>    5<  (complete)
  2: zaber:833 - boulder:32774 (c2d)                   6>    5<  (complete)
  3: zaber:pcanywherestat - 172.16.39.5:53086 (e2f)    2>    3<
  4: zaber:716 - boulder:2049 (g2h)                  347>  257<
  5: 172.16.39.100:58029 - zaber:12865 (i2j)           7>    5<  (complete)
  6: 172.16.39.100:47592 - zaber:36814 (k2l)        255380> 255378<  (reset)
  7: breakpoint:45510 - zaber:7012 (m2n)               9>    5<  (complete)
  8: zaber:35813 - boulder:111 (o2p)                   6>    5<  (complete)
  9: zaber:837 - boulder:32774 (q2r)                   6>    5<  (complete)
 10: breakpoint:45511 - zaber:7012 (s2t)               9>    5<  (complete)
 11: zaber:59362 - boulder:111 (u2v)                   6>    5<  (complete)
 12: zaber:841 - boulder:32774 (w2x)                   6>    5<  (complete)
 13: breakpoint:45512 - zaber:7012 (y2z)               9>    5<  (complete)

tcptrace 功能很强大,还可以通过过滤和布尔表达式来找出有问题的连接,比如,找出转播大于100 segments 的连接:

# tcptrace -f'rexmit_segs>100' network.dmp

如果发现连接 #10 有问题,可以查看关于这个连接的其他信息:

# tcptrace -o10 network.dmp

下面的命令使用 tcptrace 的 slice 模式,程序自动在当前目录创建了一个 slice.dat 文件,这个文件包含了每隔15秒的转播信息:

# tcptrace -xslice network.dmp

# cat slice.dat 
date                segs    bytes  rexsegs rexbytes      new   active
--------------- -------- -------- -------- -------- -------- --------
16:58:50.244708    85055  4513418        0        0        6        6
16:59:05.244708   110921  5882896        0        0        0        2
16:59:20.244708   126107  6697827        0        0        1        3
16:59:35.244708   151719  8043597        0        0        0        2
16:59:50.244708    37296  1980557        0        0        0        3
17:00:05.244708       67     8828        0        0        2        3
17:00:20.244708      149    22053        0        0        1        2
17:00:35.244708       30     4080        0        0        0        1
17:00:50.244708       39     5688        0        0        0        1
17:01:05.244708       67     8828        0        0        2        3
17:01:11.081080       37     4121        0        0        1        3

Linux 性能监测:介绍
Linux 性能监测:CPU
Linux 性能监测:Memory
Linux 性能监测:IO
Linux 性能监测:工具

Sun Fire V440 的风扇坏了

持续了一个多月的服务器升级终于接近尾声,硬盘内存都已到位。今天顺便对服务器做了一些检查和清理,干了一天体力活,把一个个笨重的服务器抬进抬出,然后逐个开箱用吸尘器清理,主要是灰尘很多,现在明白了为什么有人说 IT 其实是体力活。

还发现有台 Sun 服务器的风扇坏了,打电话给 Sun 的代理,报价把我吓了一跳,换一个风扇要1000美金,是在抢钱不?还好这台 Sun Fire V440 有两个风扇,在一个风扇的情况下系统仍然能启动,但是运行一段时间系统就自动关机。VPSee 手上有一堆废 PC,正认真考虑用 PC 风扇 DIY 一个装在这台服务器上,可能还需要去扒一个电源。如果仅仅因为风扇把这台机器仍在一边不用就太可惜了,这台老机器性能还是不错的,4个 UltraSPARC 处理器,32GB 内存,就是硬盘小了一点 4个 10000 RPM 73.4GB SCSI 硬盘。在 Solaris 下查看硬件相关信息:

$ /usr/platform/`uname -i`/sbin/prtdiag
System Configuration: Sun Microsystems  sun4u Sun Fire V440
System clock frequency: 177 MHZ
Memory size: 32GB        

==================================== CPUs ====================================
               E$          CPU                    CPU
CPU  Freq      Size        Implementation         Mask    Status      Location
---  --------  ----------  ---------------------  -----   ------      --------
0    1062 MHz  1MB         SUNW,UltraSPARC-IIIi    2.4    on-line      -      
1    1062 MHz  1MB         SUNW,UltraSPARC-IIIi    2.4    on-line      -      
2    1062 MHz  1MB         SUNW,UltraSPARC-IIIi    2.4    on-line      -      
3    1062 MHz  1MB         SUNW,UltraSPARC-IIIi    2.4    on-line      -      

难得把服务器从机柜里面抬出来一次,上几张图片吧,Sun Fire V440 外观:

sun fire v440

风扇和硬盘都是热插拔的:

sun fire v440

内部:

sun fire v440

Linux 性能监测:IO

磁盘通常是计算机最慢的子系统,也是最容易出现性能瓶颈的地方,因为磁盘离 CPU 距离最远而且 CPU 访问磁盘要涉及到机械操作,比如转轴、寻轨等。访问硬盘和访问内存之间的速度差别是以数量级来计算的,就像1天和1分钟的差别一样。要监测 IO 性能,有必要了解一下基本原理和 Linux 是如何处理硬盘和内存之间的 IO 的。

内存页

上一篇 Linux 性能监测:Memory 提到了内存和硬盘之间的 IO 是以页为单位来进行的,在 Linux 系统上1页的大小为 4K。可以用以下命令查看系统默认的页面大小:

$ /usr/bin/time -v date
	...
	Page size (bytes): 4096
	...

缺页中断

Linux 利用虚拟内存极大的扩展了程序地址空间,使得原来物理内存不能容下的程序也可以通过内存和硬盘之间的不断交换(把暂时不用的内存页交换到硬盘,把需要的内存页从硬盘读到内存)来赢得更多的内存,看起来就像物理内存被扩大了一样。事实上这个过程对程序是完全透明的,程序完全不用理会自己哪一部分、什么时候被交换进内存,一切都有内核的虚拟内存管理来完成。当程序启动的时候,Linux 内核首先检查 CPU 的缓存和物理内存,如果数据已经在内存里就忽略,如果数据不在内存里就引起一个缺页中断(Page Fault),然后从硬盘读取缺页,并把缺页缓存到物理内存里。缺页中断可分为主缺页中断(Major Page Fault)和次缺页中断(Minor Page Fault),要从磁盘读取数据而产生的中断是主缺页中断;数据已经被读入内存并被缓存起来,从内存缓存区中而不是直接从硬盘中读取数据而产生的中断是次缺页中断。

上面的内存缓存区起到了预读硬盘的作用,内核先在物理内存里寻找缺页,没有的话产生次缺页中断从内存缓存里找,如果还没有发现的话就从硬盘读取。很显然,把多余的内存拿出来做成内存缓存区提高了访问速度,这里还有一个命中率的问题,运气好的话如果每次缺页都能从内存缓存区读取的话将会极大提高性能。要提高命中率的一个简单方法就是增大内存缓存区面积,缓存区越大预存的页面就越多,命中率也会越高。下面的 time 命令可以用来查看某程序第一次启动的时候产生了多少主缺页中断和次缺页中断:

$ /usr/bin/time -v date
	...
	Major (requiring I/O) page faults: 1
	Minor (reclaiming a frame) page faults: 260
	...

File Buffer Cache

从上面的内存缓存区(也叫文件缓存区 File Buffer Cache)读取页比从硬盘读取页要快得多,所以 Linux 内核希望能尽可能产生次缺页中断(从文件缓存区读),并且能尽可能避免主缺页中断(从硬盘读),这样随着次缺页中断的增多,文件缓存区也逐步增大,直到系统只有少量可用物理内存的时候 Linux 才开始释放一些不用的页。我们运行 Linux 一段时间后会发现虽然系统上运行的程序不多,但是可用内存总是很少,这样给大家造成了 Linux 对内存管理很低效的假象,事实上 Linux 把那些暂时不用的物理内存高效的利用起来做预存(内存缓存区)呢。下面打印的是 VPSee 的一台 Sun 服务器上的物理内存和文件缓存区的情况:

$ cat /proc/meminfo
MemTotal:      8182776 kB
MemFree:       3053808 kB
Buffers:        342704 kB
Cached:        3972748 kB

这台服务器总共有 8GB 物理内存(MemTotal),3GB 左右可用内存(MemFree),343MB 左右用来做磁盘缓存(Buffers),4GB 左右用来做文件缓存区(Cached),可见 Linux 真的用了很多物理内存做 Cache,而且这个缓存区还可以不断增长。

页面类型

Linux 中内存页面有三种类型:

  • Read pages,只读页(或代码页),那些通过主缺页中断从硬盘读取的页面,包括不能修改的静态文件、可执行文件、库文件等。当内核需要它们的时候把它们读到内存中,当内存不足的时候,内核就释放它们到空闲列表,当程序再次需要它们的时候需要通过缺页中断再次读到内存。
  • Dirty pages,脏页,指那些在内存中被修改过的数据页,比如文本文件等。这些文件由 pdflush 负责同步到硬盘,内存不足的时候由 kswapd 和 pdflush 把数据写回硬盘并释放内存。
  • Anonymous pages,匿名页,那些属于某个进程但是又和任何文件无关联,不能被同步到硬盘上,内存不足的时候由 kswapd 负责将它们写到交换分区并释放内存。

IO’s Per Second(IOPS)

每次磁盘 IO 请求都需要一定的时间,和访问内存比起来这个等待时间简直难以忍受。在一台 2001 年的典型 1GHz PC 上,磁盘随机访问一个 word 需要 8,000,000 nanosec = 8 millisec,顺序访问一个 word 需要 200 nanosec;而从内存访问一个 word 只需要 10 nanosec.(数据来自:Teach Yourself Programming in Ten Years)这个硬盘可以提供 125 次 IOPS(1000 ms / 8 ms)。

顺序 IO 和 随机 IO

IO 可分为顺序 IO 和 随机 IO 两种,性能监测前需要弄清楚系统偏向顺序 IO 的应用还是随机 IO 应用。顺序 IO 是指同时顺序请求大量数据,比如数据库执行大量的查询、流媒体服务等,顺序 IO 可以同时很快的移动大量数据。可以这样来评估 IOPS 的性能,用每秒读写 IO 字节数除以每秒读写 IOPS 数,rkB/s 除以 r/s,wkB/s 除以 w/s. 下面显示的是连续2秒的 IO 情况,可见每次 IO 写的数据是增加的(45060.00 / 99.00 = 455.15 KB per IO,54272.00 / 112.00 = 484.57 KB per IO)。相对随机 IO 而言,顺序 IO 更应该重视每次 IO 的吞吐能力(KB per IO):

$ iostat -kx 1
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    2.50   25.25    0.00   72.25

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb       24.00 19995.00 29.00 99.00  4228.00 45060.00   770.12    45.01  539.65   7.80  99.80

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    1.00   30.67    0.00   68.33

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb        3.00 12235.00  3.00 112.00   768.00 54272.00   957.22   144.85  576.44   8.70 100.10

随机 IO 是指随机请求数据,其 IO 速度不依赖于数据的大小和排列,依赖于磁盘的每秒能 IO 的次数,比如 Web 服务、Mail 服务等每次请求的数据都很小,随机 IO 每秒同时会有更多的请求数产生,所以磁盘的每秒能 IO 多少次是关键。

$ iostat -kx 1
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.75    0.00    0.75    0.25    0.00   97.26

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb        0.00    52.00  0.00 57.00     0.00   436.00    15.30     0.03    0.54   0.23   1.30

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.75    0.00    0.75    0.25    0.00   97.24

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb        0.00    56.44  0.00 66.34     0.00   491.09    14.81     0.04    0.54   0.19   1.29

按照上面的公式得出:436.00 / 57.00 = 7.65 KB per IO,491.09 / 66.34 = 7.40 KB per IO. 与顺序 IO 比较发现,随机 IO 的 KB per IO 小到可以忽略不计,可见对于随机 IO 而言重要的是每秒能 IOPS 的次数,而不是每次 IO 的吞吐能力(KB per IO)。

SWAP

当系统没有足够物理内存来应付所有请求的时候就会用到 swap 设备,swap 设备可以是一个文件,也可以是一个磁盘分区。不过要小心的是,使用 swap 的代价非常大。如果系统没有物理内存可用,就会频繁 swapping,如果 swap 设备和程序正要访问的数据在同一个文件系统上,那会碰到严重的 IO 问题,最终导致整个系统迟缓,甚至崩溃。swap 设备和内存之间的 swapping 状况是判断 Linux 系统性能的重要参考,我们已经有很多工具可以用来监测 swap 和 swapping 情况,比如:top、cat /proc/meminfo、vmstat 等:

$ cat /proc/meminfo 
MemTotal:      8182776 kB
MemFree:       2125476 kB
Buffers:        347952 kB
Cached:        4892024 kB
SwapCached:        112 kB
...
SwapTotal:     4096564 kB
SwapFree:      4096424 kB
...

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  2 260008   2188    144   6824 11824 2584 12664  2584 1347 1174 14  0  0 86  0
 2  1 262140   2964    128   5852 24912 17304 24952 17304 4737 2341 86 10  0  0  4

Linux 性能监测:介绍
Linux 性能监测:CPU
Linux 性能监测:Memory
Linux 性能监测:Network
Linux 性能监测:工具

libMSRP for Windows

MSRP (Message Session Relay Protocol) 是一个基于 SIP,用于文本、消息交换的协议,主要用来在一个 session 里进行文本交换、消息传递、文件传输等,是开发基于 SIP/SIMPLE 方面应用的重要协议。我们知道用 SIP/SIMPLE 协议写的文字聊天工具只能支持无 session 的会话,也就是说 A 发一条消息,B 收到一条消息,A 和 B 之间没有 session(会话)。如果语音聊天就是有 session 的,A 打语音给 B,A 和 B 之间保持会话,保持一个连接状态的 session. 有 session 的文字聊天会带来什么好处呢?一个好处就是在保持连接的同时能互相传递文件,还有就是可以共享桌面、白板什么的。

2007年 VPSee 在一个 VoIP 开发项目中需要用到文件传输,我们的 VoIP 项目基于 SIP 协议而且要求支持 Mac 和 Windows 跨平台,所以要做文件传输自然而然就想到 MSRP,不幸的是当时只有一个 Linux C 版本的 Open Source MSRP 实现 libMSRP,Mac 天生就是 BSD 系统,libMSRP 可以直接在 Mac 上编译,我们还需要一个 Windows 版本的 libMSRP 库,就这样 VPSee 花了点时间把 libMSRP 移植到了 Windows 平台,特别是大家比较熟悉的 Visual Studio 开发环境下,当然我也针对 Window 上的 Unix 开发环境(MinGW)写了 Makefile,你也可以在 Window 平台上通过 make/gcc 编译通过。补充一句,现在又多了一个选择,一个 Python 版本的 MSRP 实现和库(http://msrprelay.org/)。

在移植过程中遇到很多小问题和 libMSRP 本身的 bug,不过总的说来 libMSRP 的代码量很小,移植还是比较顺利的,最麻烦的几个问题是:

  1. gcc 有一个很方便的扩展就是 typeof 宏,可以方便的得到数据的类型,但是 vc 不支持;
  2. Windows 里面没有 pthread 相关系统调用,需要用类似的 API 替换相关函数,为了不大量改动原 libMSRP 的代码保持源代码的清晰,我用了大量宏定义来做替换 ,比如:
    #define pthread_mutex_lock(pobject) WaitForSingleObject(*pobject,INFINITE)
    #define pthread_mutex_unlock(pobject) ReleaseMutex(*pobject)
    ⋯⋯
  3. Windows API 里没有 socketpair,需要自己写个函数模拟 Linux 下的 socketpair 函数的功能。

libMSRP 遵循 GNU General Public License (GPL) 协议,libMSRP for Windows 也遵循同样的开放版权协议。详细的编译方法和源代码下载在这里:http://www.vpsee.com/projects,projects 使用英文页面,希望对更多的人会有帮助。

Linux 性能监测:Memory

这里的讲到的 “内存” 包括物理内存和虚拟内存,虚拟内存(Virtual Memory)把计算机的内存空间扩展到硬盘,物理内存(RAM)和硬盘的一部分空间(SWAP)组合在一起作为虚拟内存为计算机提供了一个连贯的虚拟内存空间,好处是我们拥有的内存 ”变多了“,可以运行更多、更大的程序,坏处是把部分硬盘当内存用整体性能受到影响,硬盘读写速度要比内存慢几个数量级,并且 RAM 和 SWAP 之间的交换增加了系统的负担。

在操作系统里,虚拟内存被分成页,在 x86 系统上每个页大小是 4KB。Linux 内核读写虚拟内存是以 “页” 为单位操作的,把内存转移到硬盘交换空间(SWAP)和从交换空间读取到内存的时候都是按页来读写的。内存和 SWAP 的这种交换过程称为页面交换(Paging),值得注意的是 paging 和 swapping 是两个完全不同的概念,国内很多参考书把这两个概念混为一谈,swapping 也翻译成交换,在操作系统里是指把某程序完全交换到硬盘以腾出内存给新程序使用,和 paging 只交换程序的部分(页面)是两个不同的概念。纯粹的 swapping 在现代操作系统中已经很难看到了,因为把整个程序交换到硬盘的办法既耗时又费力而且没必要,现代操作系统基本都是 paging 或者 paging/swapping 混合,swapping 最初是在 Unix system V 上实现的。

虚拟内存管理是 Linux 内核里面最复杂的部分,要弄懂这部分内容可能需要一整本书的讲解。VPSee 在这里只介绍和性能监测有关的两个内核进程:kswapd 和 pdflush。

  • kswapd daemon 用来检查 pages_high 和 pages_low,如果可用内存少于 pages_low,kswapd 就开始扫描并试图释放 32个页面,并且重复扫描释放的过程直到可用内存大于 pages_high 为止。扫描的时候检查3件事:1)如果页面没有修改,把页放到可用内存列表里;2)如果页面被文件系统修改,把页面内容写到磁盘上;3)如果页面被修改了,但不是被文件系统修改的,把页面写到交换空间。
  • pdflush daemon 用来同步文件相关的内存页面,把内存页面及时同步到硬盘上。比如打开一个文件,文件被导入到内存里,对文件做了修改后并保存后,内核并不马上保存文件到硬盘,由 pdflush 决定什么时候把相应页面写入硬盘,这由一个内核参数 vm.dirty_background_ratio 来控制,比如下面的参数显示脏页面(dirty pages)达到所有内存页面10%的时候开始写入硬盘。
# /sbin/sysctl -n vm.dirty_background_ratio
10

vmstat

继续 vmstat 一些参数的介绍,上一篇 Linux 性能监测:CPU 介绍了 vmstat 的部分参数,这里介绍另外一部分。以下数据来自 VPSee 的一个 256MB RAM,512MB SWAP 的 Xen VPS:

# vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  3 252696   2432    268   7148 3604 2368  3608  2372  288  288  0  0 21 78  1
 0  2 253484   2216    228   7104 5368 2976  5372  3036  930  519  0  0  0 100  0
 0  1 259252   2616    128   6148 19784 18712 19784 18712 3821 1853  0  1  3 95  1
 1  2 260008   2188    144   6824 11824 2584 12664  2584 1347 1174 14  0  0 86  0
 2  1 262140   2964    128   5852 24912 17304 24952 17304 4737 2341 86 10  0  0  4
  • swpd,已使用的 SWAP 空间大小,KB 为单位;
  • free,可用的物理内存大小,KB 为单位;
  • buff,物理内存用来缓存读写操作的 buffer 大小,KB 为单位;
  • cache,物理内存用来缓存进程地址空间的 cache 大小,KB 为单位;
  • si,数据从 SWAP 读取到 RAM(swap in)的大小,KB 为单位;
  • so,数据从 RAM 写到 SWAP(swap out)的大小,KB 为单位;
  • bi,磁盘块从文件系统或 SWAP 读取到 RAM(blocks in)的大小,block 为单位;
  • bo,磁盘块从 RAM 写到文件系统或 SWAP(blocks out)的大小,block 为单位;

上面是一个频繁读写交换区的例子,可以观察到以下几点:

  • 物理可用内存 free 基本没什么显著变化,swapd 逐步增加,说明最小可用的内存始终保持在 256MB X 10% = 2.56MB 左右,当脏页达到10%的时候(vm.dirty_background_ratio = 10)就开始大量使用 swap;
  • buff 稳步减少说明系统知道内存不够了,kwapd 正在从 buff 那里借用部分内存;
  • kswapd 持续把脏页面写到 swap 交换区(so),并且从 swapd 逐渐增加看出确实如此。根据上面讲的 kswapd 扫描时检查的三件事,如果页面被修改了,但不是被文件系统修改的,把页面写到 swap,所以这里 swapd 持续增加。

Linux 性能监测:介绍
Linux 性能监测:CPU
Linux 性能监测:IO
Linux 性能监测:Network
Linux 性能监测:工具