这本书主要分享了作者在实现公司内部的分布式服务系统中积累的多线程和网络编程方面的经验,并介绍了C++ 在编写这种分布式系统的服务端程序时的功能取舍与注意事项,书中的很多决策(design decision)是在这一应用场景下做出的。这本书没有细谈分布式系统的设计,只在第9章列举了分布式系统的挑战及其对程序设计(服务端编程)的影响,例如可靠性、可维护性等。
以下是各章直接的交叉引用关系图(没有计算引用次数),其中第0章是前言,字母章节是附录。可见第9章“分布式系统工程实践”是被引用最多的一章,全书很多内容都是为它做铺垫。
这本书的书名原本打算叫“Linux C++ 多线程系统编程”。写作中发现,与其他Unix/Linux系统编程方面的书不同,这本书有明确的应用场景,因此可以砍掉很多内容,突出重点。“信息”按照香农的定义,是“减少不确定性”,这本书包含的信息正是减少选用编程设施(facilities)方面的不确定性,让读者集中精力攻克本质问题。这不是一本面面俱到的书,因此最终的书名也就不叫“系统编程”了。举例来说:
- 这本书没有花很大的篇幅去讲signal,而是在第4.10节说明多线程程序不要使用signal作为IPC。并且,在muduo-protorpc的示例中给出了Linux专有的signalfd的用法, 可以避免传统signal handler的常见陷阱。第4.4节说明不要从外部终止线程,因此也就不必去细究Pthreads cancellation point了。
- 这本书没介绍daemon进程,因为这种进程的父进程是init(1),不便于监控与管理(第9.8节)。为了管理方便,业务进程不应该fork()。多线程程序也最好不要fork()(第4.9节)。
- 这本书只关注Linux,不考虑移植性。它推荐使用Linux专有的gettid()系统调用作为线程标识(第4.3节),而不是用pthread_self();muduo使用timerfd来实现高精度定时,而且直接使用C++标准库来管理定时器,而不是自己实现小顶堆(heap)。
- 这本书只讲mutex和condition variable作为最基础的线程同步手段(第2章),并且建议只使用非递归的mutex(第2.1.1节),这与某些网上文章的推荐正好相反。这本书第2.3节甚至建议不要使用读写锁和信号量(semaphore),因为一是容易用错,二是不见得能提高性能。有了mutex和condition variable,就能实现多种更易用的同步设施,例如CountDownLatch和BlockingQueue。
- 这本书只讲BSD Sockets作为进程间通信的手段,并且只用TCP长连接(第3.4节)。这样就砍掉了pipe、FIFO、POSIX message queue、shared memory、STREAMS、UNIX domain socket等等内容,因为它们都只限本机进程间通信,无法扩展到多机。
- 网络编程方面(第6、7章),只讲非阻塞IO结合IO复用这一种并发风格(归纳为三个半事件),并介绍在多线程下的扩展(one loop per thread)。本书不讲IPv6,因为目前世界上最大的公司的服务机群也用不完一个私有A类地址(10.0.0.0/8)。
- 这本书举的网络编程的例子不再是简单的echo服务,而是有格式(因此引入codec)、多连接之间会交换数据的网络程序,更接近业务场景,也借机讲解如何避免TCP网络编程的常见陷阱。并且在示例代码中给出了分布式单词计数、多机求中位数等稍微复杂一点的程序。
- 在C++方面,这本书没有介绍动态链接库热更新这种“高级”技术,而是说明,在分布式系统中,为了部署方便,应该从源码编译全部的库,与主程序链接为一个standalone的可执行文件,以减小对运行环境的依赖(第10章)。第11章还讨论了程序库与应用程序之间的接口设计。
更多内容请参考配套网页:chenshuo.com/book,包含样章、勘误表、URL列表等。
书摘
第6.6.2节