-
一次网络超时的 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源代码,看见了一个比较不错的追踪此类问题的方式。