文章归档

cgroup内核实现

cgroup模块里比较重要的数据结构是:struct cgroup, struct css_set, struct cg_cgroup_link,搞清楚这三个数据结构之间的关系,基本就可以了解内核是怎么管理cgroup的了。关于cgroup的一些资料,可以参考redhat写的介绍:

>> Relationships Between Subsystems, Hierarchies, Control Groups and Tasks

»» 继续阅读全文

hotfix内核热更新技术

最近研究了一下内核热升级技术,顺便和组内的同学做了一个分享。

https://github.com/pipul/coutune/blob/master/papers/kpatch.pdf

参考资料如下:

  1. 阿里虚拟化技术 http://pan.baidu.com/s/1eQcSPTw
  2. Safe and Automatic Live Update for Operating Systems  https://www.cs.vu.nl/~giuffrida/papers/asplos-2013.pdf
  3. LUCOS http://pan.baidu.com/s/1kTmSd4F
  4. ksplice http://www.ksplice.com/doc/ksplice.pdf
  5. 淘宝内核月报 http://kernel.taobao.org/index.php/%E5%86%85%E6%A0%B8%E6%9C%88%E6%8A%A52014-05-06
  6. kgraft http://lwn.net/Articles/596776/
  7. kpatch https://github.com/dynup/kpatch

memory allocator and coredump analysis

这几天彻底被一个线上BUG搞跨了,我们准备上线一个新的模块,灰度的时候发现系统极其不稳定,几乎每过几十分钟就core一次,而且coredump的地方比较有规律。现在来回顾一下这个core的分析过程

coredump现象

我们上线的流程是 稳定性测试 + 小流量灰度 + 全量上线 稳定性测试的机器环境是centos 6,线上自己的环境是 centos 5.4,稳定性测试的时候从线上拷贝流量,启动所有模块,持续跑了两天没有发现问题,然后接着小流量灰度。(后来的事实说明,环境也是导致coredump触发的一个很重要因素)

小流量灰度的时候问题出现了,时不时的core一下,core的地方比较稳定,每次都差不多都是那几个地方。既然core的比较稳定,说明应该是附近的代码出现了问题。

信息收集

从coredump的栈帧信息来看,现在能确定的是:

  • core在stl内部,说明不是明显的NULL引用等引发的coredump
  • 用户态极少使用malloc/free等来分配释放内存
  • coredump比较稳定,附近代码有问题的可能性比较大

静态代码分析

由于初步分析coredump处附近

  • 分析coredump代码附近有可疑的地方,例如数组越界,多线程race condition,不正确的malloc/free等等,没有发现问题。
  • 分析新上线的代码,例如有可能引入或者触发coredump的地方,没有发现问题。
  • 检查线程安全,race condition的地方,例如多线程读写map等

排查

初步分析没有发现明显的问题后,我们开始一步一步的排查和定位问题。通过配置线上可运行的模块,定位到其中某个模块可能有问题。由于静态代码分析的 时候看过这部分代码,很难定位到出问题的地方。加上在排查过程中即使卸载可疑的模块,仍然没法彻底解决问题,只是降低了coredump之间的时间间隔

coredump很可能不是在crash的地方附近,而是在之前别的地方就已经被破坏掉了。

Valgrind

为了证实这个问题,我们对所有模块都做了一次长时间的Valgrind测试,最终发现一个已经长时间运行的模块存在一个BUG,这个BUG非常难捕捉到,主要是由于一个Json的不正确使用导致的,走了一条很少有的执行路径,触发了此BUG

这个问题为什么之前没有爆发出来呢?double free这种错误会由于内存管理器的实现不用而表现出不稳定性,原因是假设你轻微地破坏了一块内存,而且被破坏的地方不影响别的内存块,那么如果这块内存 释放后并没有被重复利用,这个BUG就难以复现出来。所以我们看到coredump的地方未必是问题发现的地方。

笛卡尔 - 谈谈方法

追求真理的一些基本法则和行为规范

法则

  1. 凡是我没有明确地认识到的东西,我绝不把它当成真的接受
  2. 把我所审查的每一个难题按照可能的和必要的程度分成若干部分,以便一一妥为解决
  3. 按次序进行我的思考,从最简单、最容易认识的对象开始,一点一点逐步上升,直到认识最复杂的对象;就连那些本来没有先后关系的东西,也给他们设定一个次序
  4. 在任何情况之下,都要尽量全面的考察,尽量普遍地复查,做到确信毫无遗漏

行为规范

  1. 服从我国的法律和习俗,笃守我靠神保佑从小就领受的宗教,在其他一切事情上以周围最明智的人为榜样,尊奉他们在实践上一致接受的那些最合乎中道、最不走极端的意见,来约束自己
  2. 在行动上尽可能坚定果断,一旦选定某种看法,哪怕它十分可疑,也毫不动摇地坚决遵循,就像它十分可靠一样
  3. 永远只求克服自己,不求克服命运,只求改变自己的愿望,不求改变世界的秩序

proxyio性能测试工具

测试工具位于源码目录 perf/ 下,可见:https://github.com/proxyio/xio/tree/master/perf

分别是吞吐量测试和时延测试:

  • 吞吐量测试:thr_sender + thr_recver
  • 时延测试:lat_sender + lat_recver

吞吐量测试

thr_sender不停的发送消息,thr_recver接受消息,记录消息大小,整个过程的耗时,最好得到的结果类似如下:

message size: 100000000 [B] throughput: 90497 [msg/s] throughput: 707.013 [Mb/s]

thr_sender用法如下:

usage: thr_sender <connect-to> <msg-size> <msg-count>

其中:

  1. connect-to 表示消息接收端的地址
  2. msg-size 表示发送消息的大小(不包括协议的header,仅指用户消息的长度)
  3. msg-count 表示消息数量

thr_recver用法如下:

usage: thr_recver <bind-to> <msg-count>

其中:

  1. bind-to 表示监听一个socket地址
  2. msg-count 表示消息的数量

 

时延测试

在pingpong模式下,测试每个消息来回的传输时间,测试过程如下,记录时间戳,发送消息,接受响应,记录时间戳,计算时延 rtt / 2

lat_sender用法如下:

usage: lat_sender <connect-to> <msg-size> <roundtrips>

其中:

  1. connect-to 表示消息接收端的地址
  2. msg-size 表示发送消息的大小(不包括协议的header,仅指用户消息的长度)
  3. roundtrips 表示消息来回的次数

lat_recver用法如下:

usage: lat_recver <bind-to> <msg-count>

其中:

  1. bind-to 表示监听一个socket地址
  2. msg-count 表示消息的数量

输出结果类似如下:

message size: 1000 [B] roundtrip count: 100000 average latency: 67.626 [us]

High performance Network Programming

tcp hangle算法

默认socket是开启nagle特性的,该特性主要用于提升网卡的吞吐量,但会增加小包的传输时延。对于一些时延敏感的通信,需要关闭nagle算法:

int flags = 1; rc = setsockopt (rs->ss_fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof (flags));

内核会通过以下调用栈来设置socket的nagle特性:

setsockopt()    // net/socket.c tcp_setsockopt() // net/ipv4/tcp.c

/* * Socket option code for TCP. */ static int do_tcp_setsockopt(struct sock *sk, int level, // net/ipv4/tcp.c int optname, char __user *optval, unsigned int optlen) { //... switch (optname) { case TCP_NODELAY: if (val) { /* TCP_NODELAY is weaker than TCP_CORK, so that * this option on corked socket is remembered, but * it is not activated until cork is cleared. * * However, when TCP_NODELAY is set we make * an explicit push, which

»» 继续阅读全文

select的正确用法

在linux平台上主要头文件如下: /usr/include/sys/select.h /usr/include/bits/select.h

select 相关的几个API如下:

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set);

参考man-pages,其中nfds的解释是:

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

这里的nfds不表示fd_set的大小(实际上表示不了),而是指 the highest-numbered file descriptor + 1, the highest-numbered file descriptor也就是fd_set里fd的最大值。而且这个最大值不能超过 FD_SETSIZE

An fd_set is a fixed size buffer. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in undefined behavior.

至于为什么不能超过FD_SETSIZE,主要是因为fd_set是一个大小固定的bitmap,而这个bitmap的大小是通过FD_SETSIZE计算出来的。对于大于或者等于FD_SETSIZE的fd,FD_SET非法修改了不属于自己的内存。

所以每次FD_SET的时候都应该检查fd是否合法。

tcp缓冲区大小不对称

今天写单元测试时发现setsockopt/getsockopt在设置SO_SNDBUF/SO_RCVBUF参数时不对应,getsockopt拿到的并不是setsockopt时的值 下面代码可以说明这个问题:

on = 1024; BUG_ON(tcp_setopt(sfd, TP_NOBLOCK, &on, sizeof(on))); BUG_ON(tcp_getopt(sfd, TP_NOBLOCK, &on, &optlen)); BUG_ON(on != 1024);

内核最终设置的值会发生变化,例如可能double,等等,redhat上的BUG反映:https://bugzilla.redhat.com/show_bug.cgi?id=170694 我的内核版本是:Centos 6.5 2.6.32-431.5.1.el6.x86_64 #1 SMP 翻了一下内核源码,linux-2.6.32-358.6.2.el6/net/core/

/* * This is meant for all protocols to use and covers goings on * at the socket level. Everything here is generic. */ int sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { // ... case SO_SNDBUF: /* Don't error on this BSD doesn't and if you think about it this is right. Otherwise apps have to play 'guess the biggest size'

»» 继续阅读全文

Event-driven architecture, state machines et al.

http://250bpm.com/blog:25

In my previous blog post I've described the problems with callback-based architectures and hinted that the solution may be replacing the callbacks by events and state machines. In this post I would like to discuss the proposed solution in more detail. Specifically, I am going to define what the events and state machines actually are and explain why they are useful.

While the article may be used as an intro to nanomsg's internal architecture it can be also be though of as an opinion piece of possible interest to anybody dealing with event-driven architectures and/or

»» 继续阅读全文

第 5 页,共 13 页« 最新...34567...10...最旧 »