Archive for ‘Unix/Linux’ Category

October 8, 2013

  场景:一个多线程服务器,每个线程执行一个事件循环。在事件循环开始前,调用 socket/bind/listen 监听端口,然后将监听句柄(fd)添加到 epoll,然后开始事件循环,执行 epoll_waitepoll_wait 返回有效事件时,对于监听事件,调用 accept 建立新连接,将该连接句柄添加到 epoll;对于普通连接,调用 read/write 进行网络 IO 及其他处理逻辑。
  现象:服务器进程 CPU 占用彪高,几乎每个事件循环都在 accept,客户端出现超时。
  原因:ulimit -n65535, 进程打开的 fd 已经超过该数值,导致 accept 时无法取得 fd 而失败,而此时 TCP 连接的三次握手已经建立。又因为 epoll 使用的 LT 触发模式,该连接事件会不停地由 epoll 上报,于是产生了所谓的『死循环』,其实是事件循环闲不下来了,即使没有实际的 网络 IO。

Tags: ,. 657 views
March 21, 2013

  多线程程序中,默认情况下各个线程的名字与进程名相同,但是可以通过操作系统提供的接口(prctl)修改这个名字。方法很简单,但某些时候,可以给程序的调试和运维带来很大的帮助。
  最近在调优tair的proxy server,其中使用到了tair client,每个tair client会创建若干个线程用于网络IO,另外proxy server本身还有其他IO线程。压测过程中发现,某个线程CPU彪到了100%,其他线程只有50%左右。根据该线程的调用栈可以推测出是tair client的IO线程,但其他IO线程不好分辨属于tair client还是proxy server。将IO线程按照功能命名后,发现4个tair client IO线程中,一个线程跑满了所在CPU核心,其他三个一直处于空闲状态。因此可以推断出tair client在连接分配上存在问题……找到了问题根源,解决起来就很容易了。

Tags: . 1,449 views
September 14, 2012

  经常需要查看一个文件有多少页面驻留在物理内存中,Linux中没有找到现成的命令,自己动手写了个小工具,基于mincore(2)系统调用。代码放在Github上面,可以git clone git://github.com/dutor/mincore.git获取。
  目前可用选项有限:查看特定文件驻留物理内存的页面数/字节数;将文件全部加载到物理内存;递归地查看某个目录下所有文件的映射情况。其他需要的功能,可能在以后添加。
  另外有一个叫vmtouch的工具,可以提供更丰富的功能。

Tags: . 878 views
July 24, 2012

  偶然发现glibc提供的lib.so是“可执行的”,这是快速查看glibc版本的一种方法,

1
2
3
4
5
6
7
~$ /lib/i386-linux-gnu/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.13-20ubuntu5.1) stable release version 2.13, by Roland McGrath et al.
Copyright (C) 2011 Free Software Foundation, Inc.
...
Compiled by GNU CC version 4.6.1.
Compiled on a Linux 3.0.17 system on 2012-03-07.
...

  这是gcc提供的一种叫做PIE(Position Independent Executable)的特性,可以创建位置无关的可以执行对象。它可以像共享库一样被加载到任何地址上执行。

Tags: ,. 765 views
March 3, 2012

  lsof, LiSt Opened Files, 列出打开的文件, 听起来很简单的样子. 但想*nix中很多其他工具一样, lsof把这件简单的事情做到了炉火纯青. 因为Unix认为”一切皆文件”, 那么”打开的文件”就不仅仅是传统意义上打开的文件了, 还可以是网络/Unix域套接字, 匿名/具名管道, 共享库文件, 目录文件, 设备文件等等. 很多场景下, 查看进程或系统打开的文件会给调试带来极大的帮助. 下面简单地介绍lsof常被使用的功能选项.

  • lsof : 简单地执行lsof会列出当前系统中所有被打开的文件, 但为了看到完整的信息, 通常需要具有root权限;
  • lsof -u dutor : 列出用户dutor打开的文件, 可指定多个用户, 默认是OR的关系;
  • lsof -c tair : 列出名称以tair开头的进程打开的文件, c for command, 可指定多个;
  • lsof -c /^t.*r$/ : 列出名称以t开头, r结尾的进程打开的文件;
  • lsof -p 12315 : 列出进程号为12315的进程打开的文件, 可指定多个;
  • lsof server.log : 列出打开server.log文件的进程, 可指明多个文件;
  • lsof . : 列出打开当前目录的进程;
  • lsof +D . : 递归地列出当前目录中被打开的文件, 当然也可以lsof | grep `pwd`;
  • lsof -i : 列出打开的套接字;
  • lsof -i tcp : 列出打开的tcp套接字;
  • lsof -i :5198 : 列出打开5198端口的进程;
  • lsof -i :ssh : 列出打开22端口的进程;
  • lsof -i tcp:5198 : 列出打开5198号tcp端口的进程;
  • lsof -U : 列出打开Unix域套接字的进程;
  • lsof -d 0-2 : 列出在0到2文件描述符上打开文件的进程;
  • lsof -d mem : 列出打开映射文件的进程;
  • lsof -d txt : 列出打开的可执行文件.
Tags: . 5,503 views
February 19, 2012

  关于ssh还有两点需要说明一下。若想登录时免去输入密码,只需要在目标主机上相应用户的~/.ssh/authorized_keys中追加本地主机的公共密钥即可。另外,如果出现登录速度极慢的情况,抛开网络原因,可能是因为目标主机sshd的反向域名解析(由IP查找域名)导致的。反向域名解析可能是出于安全的考虑,但我也没有深究。很多人给出的解决方法是在目标主机上面修改sshd的配置文件/etc/sshd_config,但这对于我来说有些不切实际(大部分主机是很多用户共享的,而且我也不负责主机维护)。试验发现,在本地的~/.ssh/config文件中加入GSSAPIAuthentication no也可以解决这个问题。
  最后,使用这个脚本的使用大概是这个样子滴,

1
2
3
4
5
6
7
local~$ ./mysh.sh 
1) devel
2) test
host to connect> 1
Password:
# here are login messages
remote~$
Tags: . 721 views
February 15, 2012

  Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型pthread_t,由pthread_self()取得,该id由线程维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。你可能知道,Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。
  有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread id,而只能使用该线程的真实pid,称为tid。
  有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。使用syscall得到tid只需一行代码,但为了加深各位看官的印象,简单提供下面场景。
  有一簇进程,其中一个进程中另外启了一个线程。各进程共享一个数据结构,由shared_ptr指明,其中保存有线程的tid。在各个进程的执行过程中,需要判断线程是否存在,若不存在则(重新)创建。

Tags: ,. 2,434 views
December 25, 2011

  场景是这样的。我在写一个Nginx模块,该模块使用了MySQL的C客户端接口库libmysqlclient,当然mysqlclient还引用了其他的库,比如libm, libz, libcrypto等等。对于使用mysqlclient的代码来说,需要关心的只是mysqlclient引用到的动态库。大部分情况下,不是每台机器都安装有libmysqlclient,所以我想把这个库静态链接到Nginx模块中,但又不想把mysqlclient引用的其他库也静态的链接进来。
  我们知道gcc的-static选项可以使链接器执行静态链接。但简单地使用-static显得有些’暴力’,因为他会把命令行中-static后面的所有-l指明的库都静态链接,更主要的是,有些库可能并没有提供静态库(.a),而只提供了动态库(.so)。这样的话,使用-static就会造成链接错误。
  在StackOverflow上面提了How to do partial linking这个问题,但两天都没人搭理我,大概那些哥们儿也像中国人一样,圣诞狂欢呢吧。但最后一个叫Employed Russian的哥们给了一个链接,和我的问题相似(你很少能遇到独一无二的问题)。这个帖子唯一的一个解答解决了问题。
  我之前的链接选项大致是这样的,

1
CORE_LIBS="$CORE_LIBS -L/usr/lib64/mysql -lmysqlclient -lz -lcrypt -lnsl -lm -L/usr/lib64 -lssl -lcrypto"
Tags: . 3,878 views
November 2, 2011

一个致命字符串

  传说中,存在这么一串神秘的字符,你把它们放到终端,然后回车,不消太久,你的机器就变植物人只能低电平复位重启了。这串神秘的字符看起来是这样的,

1
dutor@home: ~$ :(){ :|:; };:&

  这是神马玩意儿呢?好的,现在听我的,把你的脑袋面对显示器逆时针旋转四分之一圆周,像不像一个张着血盆大口的长袍老怪?
  严肃点,你看懂它的真相了吗?换种等价的写法,

1
dutor@home: ~$ foo(){ foo|foo; };foo&

  其实就是“声明”了一个函数,然后在后台执行这个函数。在函数体内部,以管道的形式调用递归调用自身。第一种写法只是把函数名换成”:”产生的怪胎。

Tags: . 748 views
June 11, 2011

  换了Arch Linux,感觉很清爽,但也有不少问题,但大多都能在Arch Wiki上面得到解决,但仍有一个问题。
  我使用slim登陆管理器,登陆后由.xinitrc启动openbox-session,没有问题。但在slim启动之前,会出现短暂的终端登陆界面,但slim登陆界面随即被启动。登陆后(slim),在命令行,who命令没有输出。执行halt命令关机时,桌面立即退出,立即显示一个终端的登陆界面(而不是关机时的相关信息),几秒钟后机器正常被关闭。
  可是为什么who命令没有输出呢?我觉得这可能是session的有关问题(但不确定),我对session的理解不是很清晰,希望知道事情真相的朋友能够帮到我,谢谢!

1
2
3
4
5
6
7
8
9
10
11
#! /bin/bash
 
xscreensaver &
rl=$(runlevel | grep -o [0-6])
 
case $rl in
	4) exec openbox-session;;
	5) exec gnome-session;;
#4) exec ck-lauch-session openbox-session;;
#5) exec ck-lauch-session gnome-session;;
esac
Tags: . 444 views
Page 1 of 9123456789