technology

我们是如何搞定 600+ 设备的初创公司办公室网络环境的

(本文已投稿 36kr :http://www.36kr.com/p/208007.html

 

笔者于日前看了一下豌豆荚的办公室 WiFi 环境的文章(http://www.36kr.com/p/207783.html),文中提到的无线环境与自己的做法相似,然后想扩展一下,分享一下整个办公室网络环境构建的经验。
笔者参与并主导建设了知乎和陌陌办公室的网络环境,非专业人士,也是边做边学,但对于 startup 的网络环境建设还是有一定发言权的。

 

笔者屈指一算,原来陌陌已经两岁多了。一个两岁的小屁孩也已经背起书包上学背英文单词了,两岁的陌陌也正在创业的路上越走越顺。回头看看这一路,不容易啊。
遥想当年那只有四五台电脑,60 平米左右的办公室,再对比现在一人手持四五个移动设备,1000 平的高上大 CBD 写字楼,些许感慨。
当年那个 60 平米的小办公室,大家上网办公依赖的是一条 4M 的不对称企业 ADSL。所谓的不对称,指的是上行下行速率的不相等,也就是,我下载能达到 4Mbps,但上传只有 512Kbps。很多人认为上传不重要,设想一下,一个 10M 的陌陌 app,要上传到服务器去,只能以 64K/秒 的速度上传,这个还是理论一个人单独只用整条线的最快值,需要时间两分半。相信现在家庭用的 xx 光纤入户都比这个要快了,当时整个陌陌的所有员工都在使用这条小水管。
后来,我们的办公室搬到了环境宜人的别墅。同样是 ADSL (当然,带宽是扩大了)陪我们度过了这段温馨的时光。
再后来,也就是现在的办公室,急速增长的员工和比之前大十倍以上的办公室,终于让我们正视这些问题了。我们需要一个能满足数百设备的有线无线办公室网络环境。
我们首先看看一个初创移动互联网公司所面临的问题:
1)众多设备的有线无线上网
2)各类下载加速
3)爬篱笆

然后我们一个一个问题来解决。
1)
陌陌的办公室上网使用的是大厦提供的宽带上网,从大厦端给我们的就是一根普通的网线,我们只要插上网关服务器(关键角色,将在第二部分详细介绍),配置上大厦分配的 ip 即可使用了。
关于有线上网,都是实打实的东西了,有多少个网线口,就得有相应数量的交换机端口。我们选购了一款性价比超高的 N 家的交换机,24 口千兆,只要不到 1000 的价格。这些交换机以级联的方式连起来,然后扩展也比较方便,办公室需要扩工位时,就继续买交换机来级联。

好了,说完有线,我们来说说比较关键的无线。
作为一家有态度的移动互联网公司,一个员工的桌子不放上那么五六个移动设备,都不好意思说在陌陌工作。

笔者作为一个脑残果粉,在这里就不选择 C 家的瘦 AP 了,而是直接选择了 Apple 的 Airport Extreme 。Apple 的 AE 其实是一个路由器,但是笔者将其当做一个 AP 来使用,只是负责建立无线网络,关闭 DHCP ,以 bridge 的方式与网关相连。而之所以不选用 C 家的 AP ,则是考虑到 C 家的 AP 其实也不便宜,能达到和 AE 宣称的理论最多 50 个同时接入的 AP ,甚至比 AE 还贵。

陌陌的办公室并不是一个大开间,而是一个类似“回”字的形状(中间是电梯)。办公室的布局,与路由器的摆放有直接关系。我们当前布置了 11 个 AE ,平均每个 AE 连接了 30+ 个用户。只广播一个 SSID ,2.4G 和 5G 网络都用同一个 SSID ,不让用户选择就是最好的选择。整个办公室就一个 SSID,无缝漫游,即使用户的位置移动了,也会自动寻找最近的接入。用户的设备支持 2.4 的就连接到 2.4,支持 5 的就连接到 5。众所周知,大部分的 PC 和除了 iPhone5 以上的手机,都只支持 2.4G,而 2.4G 基本已经拥挤得无法使用了。所以我们在 Android team 的附近,布置了 3 – 4 个路由,以保证它们还能顺利上网,但速度已经无法保证了。另外,也不能太相信 AE 的自动分配,必须手动指定每个路由广播的信道,以保证相邻的两个路由的信道不要重叠。

Apple 新款的 Airport Extreme ,支持 802.11ac ,理论上可达到 1.3Gbps 的吞吐,比一般配备的有线千兆网卡更快。最近,我们终于也入手了新款 Airport Extreme ,豪华的外型背后,却是一个无奈的事实:英雄无用武之地。现在支持 802.11ac 的设备真是少之又少,连去年的 retina MacBook Pro 都不支持 ac。

在这里稍微吐槽一下 Apple 的无线管理工具 Airport Utility 。6.0 版本不好用吧,Apple 自己也知道,让 5.6 版本可以与 6.0 共存。但新款 AE 不能通过 5.6 进行管理,而且系统升级 Mavericks 以后,5.6 就已经不能用了。Airport Utility 6.0 + 新款 AE 缺少了很多可监控的选项。而 Airport 5.6 + 旧款 AE 是可以通过 snmpd 和 syslog 获取一些信息的。
2)
接着就是加速的事情。
我们这里,有请一位关键角色出场,墨迹。墨迹是陌陌的第十五号员工,我们的卖萌总监。
我们用退役下来的黑苹果,装了一个 Linux 作为我们的办公室网关。为了纪念墨迹,这个机器的名字叫墨迹。

墨迹在我们创业的初期,一路用卖萌来陪伴着我们加班的日子。
终于在某一天遇到了一生中所爱,从此离家出走去追寻自己的幸福了,再也没有回来了。我们没有怪她的不辞而别,而是祝福她,终于找到了一生的归宿。
我们也为此特别做了一个版本来纪念这位永远的卖萌总监。下图就是陌陌 1.9 的开机载入画面:

moji
墨迹上安装了 smokeping, cacti, ntop 等软件,smokeping 可以检测办公网到各个地方的网络情况,cacti 用于监控整个办公室的带宽情况,ntop 用于监控办公室每个人的网络使用情况。

说回来加速。我们主要加速的内容是,iTunes 的 app 更新,和 testflight ipa 的下载。
方法都是,在网关上面安装一个 squid ,用于缓存 ipa,然后用 iptables 把下载的地址,指向 squid,让 squid 缓存住 ipa。只要第一次下载成功后,就会缓存到 squid 上面,办公室的其他人就因此受益了。更新速度都是唰唰的。

iTunes 的更新一直没有使用 CDN ,直到今年初,App Store 的 ipa 下载使用了国内的 CDN ,办公室的 iTunes 加速的作用才没那么大了。
再到后来 iOS 7 发布后,这个就更不是问题了,因为 iOS 的新功能自动下载更新,iOS app 基本所有的更新都可以在大家睡觉时完成了。

但 testflight 的下载仍然没有 CDN 的,而且慢得令人发指,如果没有加速,难以想象还有谁会去使用它。
3)笔者作为一个从来不会使用百度的装逼犯,表示绝对不能忍受一天不能使用 Google 。于是,爬篱笆成为办公室上网的一个必备因素。

同样,网关是一个 Linux 实在太方便了,我们仍然利用它来做这个事情。
原理就是,中国的 ip 走默认的出口,而非中国的 ip 则走 vpn 的出口。
而中国的 ip 怎么获取呢?从 APNIC 下载一份 ip 列表回来,把属于中国的 ip 过滤出来。正如大家所知,全球的 ipv4 地址已经早就分批完毕,所以这份列表的变动性其实已经不大了。即使经常变动,一天更新一次也是没什么问题的。

 

Log bash history to syslog on CentOS 6

I think you should notice the new feature of Bash 4.1: log the bash history to syslog.

If you don’t, try to find it yourself in the official change logs here: http://tiswww.case.edu/php/chet/bash/CHANGES

There is a new configuration option (in config-top.h) that forces bash to
forward all history entries to syslog.

There is little information about it, you may not know how to use the fancy feature. This post will show you how to enable it.

There is no configurable option to enable it, and it is disable by default on CentOS 6, so, we must recompile the BASH to make it work. In order to take the less change to the system, we are going to recompile the BASH with the src rpm package.

1) Download the SRPM package, and verify the file.

From here: http://vault.centos.org/6.4/os/Source/SPackages/bash-4.1.2-14.el6.src.rpm

And always keep a good behavior habit to verify the file download from internet, especially this one, it’s your SHELL !

$ sha1sum bash-4.1.2-14.el6.src.rpm
da020835947d7098cf8c07d49b61dd2e6c482f6b bash-4.1.2-14.el6.src.rpm

If the sha1 checksum of the srpm file shows you “da020835947d7098cf8c07d49b61dd2e6c482f6b” , you get the correct file. The strings comes from the file: http://vault.centos.org/6.4/os/Source/repodata/primary.xml.gz 

2) Prepare your rpmbuild environment

Remember this rule [1] :

Building RPMs should NEVER be done with the root user. It should ALWAYS be done with an unprivileged user

$ sudo yum install -y rpm-build make gcc
 
$ mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
 
$ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros

3) Install the SRPM package

$ rpm -i bash-4.1.2-14.el6.src.rpm

So many warnings like:

warning: user mockbuild does not exist – using root
warning: group mockbuild does not exist – using root
warning: user mockbuild does not exist – using root
warning: group mockbuild does not exist – using root
warning: user mockbuild does not exist – using root
warning: group mockbuild does not exist – using root
warning: user mockbuild does not exist – using root
warning: group mockbuild does not exist – using root
warning: user mockbuild does not exist – using root
warning: group mockbuild does not exist – using root

….

As you did before, just ignore the warnings. :-)

The command will unpacke some files from SRPM and put them into the directory “rpmbuid” you created just now.

4) Rebuild the SRPM

You will follow this instruction [2]:

  1. cd ~/rpmbuild/SPECS/
  2. rpmbuild -bp mypackage.spec
  3. cd ~/rpmbuild/BUILD/
  4. cp existing_directory existing_directory.orig
  5. cd existing_directory
  6. find the file you wish to change, modify it.
  7. cd ~/rpmbuild/BUILD/
  8. diff -Npru existing_directory.orig exiting_directory > name_of_your_patch_file.patch
  9. cp name_of_your_patch_file.patch ~/rpmbuild/SOURCES/
  10. cd ~/rpmbuild/SPECS/
  11. edit the mypackage.spec file to add the definition of name_of_your_patch_file.patch and the application of your_patch_file — please look in the file to see how that is done.
  12. rpmbuild -ba mypackage.spec

 

$ cd ~/rpmbuild/SPECS/
 
$ rpmbuild -bp bash.spec
 
$ cd ~/rpmbuild/BUILD/
 
$ cp -r bash-4.1 bash-4.1.orig
 
$ cd bash-4.1

Now, it’s hack time !

$ vim config-top.h

Find the following comment out line:

/* #define SYSLOG_HISTORY */

Uncomment it:

#define SYSLOG_HISTORY

And make the next few lines:

#if defined (SYSLOG_HISTORY)
# define SYSLOG_FACILITY LOG_USER
# define SYSLOG_LEVEL LOG_INFO
#endif

Change to:

#if defined (SYSLOG_HISTORY)
# define SYSLOG_FACILITY LOG_LOCAL1
# define SYSLOG_LEVEL LOG_DEBUG
#endif

LOG_USER and LOG_INFO means that bash history will use the “user” facility and “info” level. By default, if we don’t change the facility and level of syslog, the bash history will fill with the /var/log/messages …

Available facility: kern, user, info, mail, daemon, auth, syslog, news, uucp, lpr, ftp, cron, local0-7

Available level: emerg, alert, crit, err, notice, info, debug

So I choose the unusual facility “local1″ and level “debug”.

The bash history has the same effect like this command: logger -p local1.debug “helloworld” .

$ vim bashhist.c
void
bash_syslog_history (line)
const char *line;
{
char trunc[SYSLOG_MAXLEN];
 
if (strlen(line) < SYSLOG_MAXLEN)
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line);
else
{
strncpy (trunc, line, SYSLOG_MAXLEN);
trunc[SYSLOG_MAXLEN - 1] = '\0';
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc);
}
}

Change to:

void
bash_syslog_history (line)
const char *line;
{
char trunc[SYSLOG_MAXLEN];
 
if (strlen(line) < SYSLOG_MAXLEN)
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PPID=%d PID=%d SID=%d UID=%d User=%s %s", getppid(), getpid(), getsid(getpid()), current_user.uid, current_user.user_name, line);
else
{
strncpy (trunc, line, SYSLOG_MAXLEN);
trunc[SYSLOG_MAXLEN - 1] = '\0';
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PPID=%d PID=%d SID=%d UID=%d User=%s %s", getppid(), getpid(), getsid(getpid()), current_user.uid, current_user.user_name, trunc);
}
}

Because we want to know the current user’s name not hist uid. SID and PPID is for more information about the command.

When you finish the above hacking, let’s continue the recompiling.

diff -Npru bash-4.1.orig bash-4.1 > bash_history_syslog.patch
 
$ cp bash_history_syslog.patch ~/rpmbuild/SOURCES/
 
$ cd ~/rpmbuild/SPECS/
 
$ vim bash.spec

edit the spec file, add these 2 lines to the right place:

Patch117: bash-setlocale.patch
Patch118: bash-tty-tests.patch
Patch119: bash_history_syslog.patch

%patch117 -p1 -b .setlocale
%patch118 -p1 -b .tty_tests
%patch119 -p1 -b .history_syslog
%patch123 -p1 -b .nobits
%patch124 -p1 -b .examples

All done. Let’s rebuild it.

$ rpmbuild -ba bash.spec

After a long wait, the command should end without any error. And it will generate a rpm file named bash-4.1.2-14.el6.x86_64.rpm located in ~/rpmbuild/RPMS/x86_64/ .

5) Install the custom bash rpm. ( force )

$ sudo rpm -Uvh --force bash-4.1.2-14.el6.x86_64.rpm

Let’s see the new “bash” :

$ ll /bin/bash
 
-rwxr-xr-x 1 root root 1030434 Jul 27 02:38 /bin/bash

 

6) Testing 

I use syslog-ng as my syslog server.

Add the following lines to the config file: /etc/syslog-ng/syslog-ng.conf

filter f_bash { facility(local1) and level(debug); };
destination d_bash { file(“/var/log/bash”); };
log { source(s_sys); filter(f_bash); destination(d_bash); };

Restart the syslog-ng:

$ sudo /etc/init.d/syslog-ng restart

Then, you will see your command occurs in /var/log/bash:

Jul 27 02:59:06 alpha -bash: HISTORY: PPID=16253 PID=16254 SID=16254 UID=1001 User=hello sudo cat /var/log/bash

Of course, you can log to the remote syslog server.

 

Enjoy !

 

Reference:

[1] http://wiki.centos.org/HowTos/SetupRpmBuildEnvironment

[2] http://wiki.centos.org/HowTos/RebuildSRPM

 

Automatic build xcode project and distribute to testers using Testflight

Here is my repo in Github:

https://github.com/hellosa/autobuild-upload-testflight

The script is help you build and archive your xcode project from command line, upload to testflight and notify your team members after finishing.

You can create an empty xcode project, read my README of the project and complete the configuration to go through it.

Enjoy !

Configure multiple default gateways in Linux box

Assume that you have a Linux machine which has 3 network interface cards, named eth0, eth1, and eth2. eth0 is 221.237.x.253/24, eth1 is 221.237.x.251/24, and eth2 is 172.16.200.1/22. Because there can be only one default gateway in Linux, the default gateway is 221.237.x.1 via eth0. Although eth0 and eth1 seem to be in the same network, and sharing the same gateway, but actually each of these 2 ip addresses has its own speed rate limit: 10Mb/s. We get total 20Mb/s ideally, but we can’t reach the max speed rate with the only one default gateway, that’s the problem. Let me solve it.

eth0 : 221.237.x.253/24
eth1 : 221.237.x.251/24
eth2 : 172.16.200.1/22 (for intranet, as the router of the local LAN network)
default gateway : 221.237.x.1 via eth0

Here is the situation, this Linux server, as the gateway of the office, I want to use it to route the traffic to the 2 network interfaces.

If some people on the local network want to access a specific IP address (e.g. 61.135.255.144), all the traffic flow through the eth1, all the other situations, through eth0.

1) Linux box, Debian 7, no matter which distro, just use the distro you like. I like Debian most.

2) iproute2, a powerful network utility package. I don’t like the old tools like “route” or “netstat” or something. iproute2 has integrated all the above network tools together. iproute2 is the swiss army knife for System Administrator.

In order to use “ip rule”, you have to make sure that,  the kernel configuration item, “CONFIG_IP_MULTIPLE_TABLES” should be set.

CONFIG_IP_MULTIPLE_TABLES=y

If your kernel doesn’t support this feature, bad luck, you have to recompile the kernel to accomplish the requirement.

Debian 7 ( 3.2.0-4-amd64 ) already has the feature, let’s skip to next step.

First of all, you must understand a concept: routing table.

$ ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default

There are 3 routing tables here, by default, we are in the table main ( remember, not the table default !), and the other 2 tables are empty.

$ ip r s
default via 221.237.x.1 dev eth0
172.16.200.0/22 dev eth2 proto kernel scope link src 172.16.200.1
221.237.x.0/24 dev eth0 proto kernel scope link src 221.237.x.253
221.237.x.0/24 dev eth1 proto kernel scope link src 221.237.x.251

is the same as

$ ip r s table main
default via 221.237.x.1 dev eth0
172.16.200.0/22 dev eth2 proto kernel scope link src 172.16.200.1
221.237.x.0/24 dev eth0 proto kernel scope link src 221.237.x.253
221.237.x.0/24 dev eth1 proto kernel scope link src 221.237.x.251

“ip r s” is short for “ip route show”.

Now, let me do the job.

ip route add 221.237.x.0/24 dev eth1 src 221.237.x.251 table 163
ip route add default via 221.237.x.1 dev eth1 table 163
ip rule add to 61.135.255.144 table 163

Let me explain the above commands.

The routing table 163 has been created when the first command is executed. 163 is the number I like, you can choose yours, 99, perhaps. The table main, and the table 163, they are totally unrelated to each other.

1)The first command is to provide the information about the subnet.

2)The second command is to define the default gateway of the table 163. This is our SECOND default gateway.

3)The third command is to specify a rule to tell the OS when to use the table 163. Without this command, the table 163 is useless.

 

Now, if someone of the subnet wants to access 61.135.255.144, he use the router’s eth1 to communicate with 61.135.255.144.

Let’s have a look at the “ip rule show” again.

0:	from all lookup local
32765:	from all to 61.135.255.144 lookup 163
32766:	from all lookup main
32767:	from all lookup default

If someone has the LAN ip : 172.16.200.55 also wants to use the SECOND default gateway, we can use the following command:

ip rule add from 172.16.200.55 table 163

It’s pretty easy to understand, right?

0:	from all lookup local
32764:	from 172.16.200.55 lookup 163
32765:	from all to 61.135.255.144 lookup 163
32766:	from all lookup main
32767:	from all lookup default

If you want to clear the record of a table, just run the command:

ip route flush table 163

And remember, never run the command ” ip rule flush” when you ssh to this machine, because it will clear all the route rules, you will lost your connection.

alfred workflow: taobao ip

今天看见淘宝也公布了他们的 ip 库 ( http://ip.taobao.com ) ,很赞,还有 RESTFUL 的 api ,马上写了个 alfred 的 workflow: https://github.com/hellosa/taobaoip-alfredworkflow

ip138 的 alfred workflow

实在不想经常开 ip138 的网页了……写了一个 alfred workflow ,也实在奇怪,为什么之前没人写呢?

https://github.com/hellosa/ip138-alfredworkflow

修改 keepalived 的 healthcheck 邮件

keepalived 在检测到 realserver 有问题的时候,是会发邮件通知管理员的,具体的邮件如下:

标题:

[LVS] Realserver [192.168.100.101]:8080 – DOWN

 

正文:

=> TCP CHECK failed on service <=

其实这个邮件的告警作用有限,在机器太多的时候,192.168.100.101 这个机器是什么呢?没人知道,实在有点不清晰。如果要 keepalived 代码里面实现呢,每一次都去查 DNS ,可是很费性能的。于是我决定从邮件入手。

 

我找到一个软件,proxsmtp ,它可以代理我们的邮件,并篡改其中的内容!

下载最新版 1.10,configure, make, make install 三步走。如果报错缺少 libcap2 的话,CentOS 下安装:sudo yum install libcap-devel 。其它系统懒得去测试了。

安装是不会帮你把配置文件也加上去的,自己 copy 一下,在源码目录里,doc/proxsmtpd.conf 。我就配置了三行:

OutAddress: mail.momo.com:25
FilterCommand: sed ‘s/192.168.100.101/test-001/’
Listen: 0.0.0.0:25

而 keepalived 的配置也改改,其中:

smtp_server 指向 proxsmtp 的服务器。

完成,刚才那个邮件再次发出的话,那么 192.168.100.101 就会替换为 test-001 的了(当然,这个看你的 FilterCommand 怎么写)

Done, enjoy !

利用微信公众平台实现手机命令行运维

前几天玩了一下微信公众平台, 取名: 我的公司名, 哈哈, 单凭这个名字竟然每天吸引了数十人的关注.

公众平台的规定是, 关注人数达到 500 人就可以申请认证. 我觉得我可能不需要发一句话, 就可以达到这个认证标准了, 哈哈.

公众平台有两种模式, 一种是编辑模式, 只能实现有限的几种对话模式, 定义好一些关键字, 如果用户发了这些关键字, 就回复事先指定好的回复.

一种是开发模式, 你发一句话给公众帐号, 微信服务器就帮你把相关的内容发送到你定义好的服务器, 然后你的服务器处理完, 就可以返回相应的信息给你了.

选择开发模式.

好了, 我的玩法是, 我用我自己的普通帐号发一个命令行的命令给公众帐号, 然后微信把这个命令发送给我之前定义好的服务器, 然后我的服务器就执行完这个命令, 把结果按照微信规定的格式返回, 然后公众帐号就返回那个结果给我了.

首先, 所谓的网址接入, 文档在这里: http://mp.weixin.qq.com/wiki/index.php?title=消息接口指南 . 照着做吧.

然后, 请准备好服务器程序, 我花了几十分钟用 tornado 写了个简单的接收 POST 请求的接口, 关键处理逻辑部分如下:

def post(self):
  dom = parseString(self.request.body)
  root = dom.documentElement
 
  toUserName = root.getElementsByTagName("ToUserName")[0].firstChild.nodeValue
  fromUserName = root.getElementsByTagName("FromUserName")[0].firstChild.nodeValue
  createTime = root.getElementsByTagName("CreateTime")[0].firstChild.nodeValue
  msgType = root.getElementsByTagName("MsgType")[0].firstChild.nodeValue
  content = root.getElementsByTagName("Content")[0].firstChild.nodeValue
  msgId = root.getElementsByTagName("MsgId")[0].firstChild.nodeValue
 
  print toUserName, fromUserName, createTime, msgType, content, msgId
  cmd = os.popen(content).readlines()[0]
 
response = """
 <xml>
 <ToUserName><![CDATA[%s]]></ToUserName>
 <FromUserName><![CDATA[%s]]></FromUserName>
 <CreateTime>%s</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[%s]]></Content>
 <FuncFlag>0</FuncFlag>
 </xml>
  """ % (fromUserName, toUserName, createTime, cmd)
  self.write(response)

再然后, 就向公众帐号发命令试试吧. 如图:

2013-03-05 17.42.52

 

发挥想象还可以玩出很多不同的花样呢. 例如, ssh 到别的机器来完成某种命令再返回.

我玩什么都是三分钟热度, 这个也就玩玩, 不打算深入研究. 就这样了.

puppet 在 mongodb 的机器上卡死

好久没写技术的内容了, 要长草了… 随便写一篇今天的吧 ( 同事发现的…我只是搬运工 )

现象: 在部分跑着 mongodb 的机器上跑 puppet , 巨卡, 竟然需要跑好几十分钟, 并且 top 看起来还是 system 占用的 cpu 资源而不是 user .

解决:

因为众所周知的原因, 跑 mongodb 时必须关闭 NUMA 来启动. 看了以下这个页面, 才发现还需要关闭 zone_reclaim_mode. 因为此值默认总是关闭的, 所以一直没有为意.

http://docs.mongodb.org/manual/administration/production-notes/#production-numa

因为某些原因, 我们上周开启了 /proc/sys/vm/zone_reclaim_mode, 导致的问题.

http://www.kernel.org/doc/Documentation/sysctl/vm.txt , 已经提醒过大家, 最好关闭了.

http://www.poempelfox.de/blog/2010/03/, 解释最全了. 阐述了多种症状, 我们都命中了…例如一个普通的系统调用需时甚长.

唉, 关闭了 zone_reclaim_mode 就好了.

BLOG 迁移到新域名

终于买到 hellosa.org 的域名了… helosa.org 这个域名就慢慢退出历史舞台吧 …

买了域名才发现, 原来 helosa.org 是在 3 年前的同一天购买的, 真巧.

好了, blog 迁移到新域名 !!

 

AD time: 本人可以提供个人及小型办公室爬篱笆服务, 有兴趣联系我啊