很有意思,这么有名的事情,昨天才亲身经历了。
隔壁小王继续用google perftools 排查cpu占用率。先说明一下场景。多服务进程阻塞在select上,这个select是和一个消息队列对应的,一旦有消息进入队列,select就唤醒阻塞的进程,从队列中取消息处理。发现select(__select_nocancel)占用了30%左右的cpu。先是怀疑select阻塞也被perftools记在内了。写了个小程序验证了一下,非也。遂在select下加一行log,发现每处理一个消息之前,就会有多个select被唤醒。才意识到一个消息来了之后,多个阻塞在select的服务进程都被唤醒,而只有一个会到达消息并处理。才知道这就是著名的惊群效应。
解决中。尝试在select之前加互斥锁,select之后释放锁,确保任何一个时刻只会有一个进程在select阻塞。为了确保锁不会被集体唤醒,特意查了一些资料,linux中,阻塞在互斥锁上的进程id是存放在一个队列中的,每次只会取出一个唤醒。更近一步考虑,获取锁的进程一旦检测到有消息进来,就立即去出一个消息,并释放锁,然后遍历消息队列有一个就处理一个。这里先取出一个基于两点考虑:1.在消息队列中只有一个消息时,如果不及时取出,释放锁后,获得锁的下一个进程就会来取这个消息,但很可能取不到,因为前一个进程刚好去走了,多了一次无谓的进程切换。2.一个进程处理一个消息,特别是比较耗时的业务,能使得并发量最大。