• 一次网络超时的 Debug 过程 

    线上有部分机器连接外部存储时经常会会发生读写超时,通过 sar 工具查看网卡流量并不是太高,千兆网卡流入流出带宽只达到一半左右:

  • 谁修改了我的 Zookeeper 节点 

    zookeeper 集群一共有 5 台机器组成,上边记录的是应用程序的配置信息和进度信息。 程序在完成一些阶段性工作之后会将当前进度保存到 zk 上,这样就能够在程序意外 crash 之后能够恢复上次的进度。

  • 使用GDB调试Coredump文件 

    写C/C++程序经常要直接和内存打交道,一不小心就会造成程序执行时产生Segment Fault而挂掉。一般这种情况都是因为数组越界访问,空指针或是野指针读写造成的。程序小的话还比较好办,对着源代码仔细检查就能解决。但是对于代码量较大的程序,里边包含N多函数调用,N多数组指针访问,这时想定位问题就不是很容易了(此时牛人依然可以通过在适当位置打printf加二分查找的方式迅速定位:P)。懒人的话还是直接GDB搞起吧。

  • 关于ctime的误区 

    本文的主旨是:千万不要把文件inode中记录的ctime理解为create time!!正确的理解是 change time。 我们知道linux上常用的文件系统比如ext2,ext3等会将文件的元信息存储在inode节点中。inode包含的信息可用下边的结构体表示:

           
    struct stat {
       dev_t     st_dev;     /* ID of device containing file */
       ino_t     st_ino;     /* inode number */
       mode_t    st_mode;    /* protection */
       nlink_t   st_nlink;   /* number of hard links */
       uid_t     st_uid;     /* user ID of owner */
       gid_t     st_gid;     /* group ID of owner */
       dev_t     st_rdev;    /* device ID (if special file) */
       off_t     st_size;    /* total size, in bytes */
       blksize_t st_blksize; /* blocksize for file system I/O */
       blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
       time_t    st_atime;   /* time of last access */
       time_t    st_mtime;   /* time of last modification */
       time_t    st_ctime;   /* time of last status change */
    };

  • 两个有趣的函数 

    最近写代码时偶然从友东同学那里学到两个函数,一个是daemon(),另一个是 sendfile()。如果知道的同学就没必要继续看了。

  • Nagle's Algorithm and Delay Ack 

    今天看 Redis 代码,当服务端接收到来自客户端的请求,服务端要为这个客户端初始化一个 redisClient 结构来保存这个连接的全部信息,代码在 networking.c 的 createClient() 函数。因为 Redis 采用的非阻塞式IO来处理各个文件描述符,所以这个函数首先要做的就是将 accept 返回的文件描述符(fd)通过 anetNonBlock() 函数设置为非阻塞。而接下来的这个anetTcpNoDelay()是起什么作用的呢? anetTcpNoDelay() 函数在 anet.c 文件中,函数只是对 setsockopt 做了层简单包装。代码如下:

    int anetTcpNoDelay(char *err, int fd)
    {   
        int yes = 1;
        if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes;, sizeof(yes)) == -1)
        {
            anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
            return ANET_ERR;      
        }
        return ANET_OK;
    }   
    

  • Oom and Oom-Killer 

    Out of memory 也就是 OOM,指的是操作系统用光了所有内存(包括物理内存和交换区)时的情况。此时如果调用 malloc 函数申请内存的时候将会返回NULL,并且将 errno 设置为 ENOMEM。在引入虚拟内存和交换分区机制之后,OOM情形就很少出现了。但是即便如此,程序中还是应该谨慎的检查是否出现了OOM状况。 Linux系统中,当内核检测到OOM时会运行称作OOM-Killer的过程。以此来杀死一些经过精心挑选的进程,从而释放出他们占用的内存。oom-killer 的宗旨是牺牲一个或一组进程,来保证系统的正常运行。其实现在内核代码中的 mm/oom_kill.c 文件中。如果不想某个进程被 oom-killer 误杀,可以将 /proc//oomadj 设置为 OOM_DISABLE(实际值为 -17)。

    #echo -17 > /proc//oomadj
    

  • 线程库个种类与对比 

    Linux Thread

  • Redis internals - 内存分配 

    Redis中到处都会进行内存分配操作。为了屏蔽不同平台之间的差异,以及统计内存占用量等,Redis对内存分配函数进行了一层封装,程序中统一使用zmalloc,zfree一系列函数,位于zmalloc.h,zmalloc.c文中。 上边说过,封装就是为了屏蔽底层平台的差异,同时方便自己实现相关的统计函数。具体来说就是:

  • 管道与消息队列简单性能测试 

    Unix/Linux中进程间通信有多种方式,比较典型的有管道,命名管道(FIFO),消息队列,信号量和共享存储区。后面三种也叫POSIX XSI IPC。《Unix环境高级编程》中,进程间通信一章对“消息队列”,“STREAMS管道”和“UNIX域套接字”三种IPC的执行时间在Solaris9上进行了比较。考虑到测试时间距离现在已经比较久远,所以本文按照《APUE》中的思路在Linux2.6上重新进行一次测试。

  • Redis Internals - Event Library 

    这是一篇翻译文章,原文见这里。Redis实现了它自己的事件库。事件库的实现在ae.c文件中。要弄明白Redis事件库是如何工作的最好的方法就是弄明白Redis是如何使用它的。

  • 即将消逝的目录 /var/run 

    首先声明这不是愚人节消息,事实上这个消息是昨天就发出来了。Fedora15中将会在根目录中引入一个新的目录/run。而且据这位来在redhat的同学称,Fedora,Debian,Suse以及Ubuntu等发行版的开发人员已经就这件事请谈妥了。Fedora和Suse已经添加这个目录了,Debian和Ubuntu也会马上跟上。而引入这个目录的目的是为了使run-time-dir管理更加标准。

  • Redis Internal - Memory 

    这是一篇翻译文章,原文地址在这里。 本文将对Redis内部的虚拟存储子系统做出说明。本文的目标读者并不是Redis的最终用户,而是那写想要了解并修改虚拟存储实现的程序员们。

  • Hacking Strings - Redis Internals 

    这是一篇翻译文章,原文在这里。 最近在看Redis的源代码,官方文档页面上有三篇对内部实现细节的分析文章,接下来会依次翻译到这里,然后再写一些其它部分的分析。我们知道Redis作为一个NoSQL类型的数据库,使用的是key作为存取对象的唯一标识,对“key”的通俗理解就是“字符串”。在Redis中字符串又分为两类:二进制安全(Binary Safe)的和非二进制安全的,关于二进制安全的描述可以参考这里。Redis处理存储的内容时用的是二进制安全的字符串,而作为key使用的非二进制安全的。

  • 让你的程序优雅的结束 

    写C程序最爽的是什么?我觉得是其中灵活的指针用法能让coder发挥各种想象力和创造力。那最郁闷的是啥?差不多就是N多指针满天飞之后程序一运行就直接segment fault了。这种运行时错误不像编译时错误有明显的错误提示,所以往往很难定位。今天看redis源代码,看见了一个比较不错的追踪此类问题的方式。