你怎么编写软件使其可伸缩?你怎么改变你的软件使其可伸缩?有大量的经验规则都是假设硬件能处理多少。我们需要真实的执行性能。 要进入下一个等级,我们需要解决的问题是: - 包的可扩展性
- 多核的可扩展性
- 内存的可扩展性
精简包-编写自己的定制驱动来绕过堆栈- 数据包的存在的问题是它们要通过Unix的内核。 网络堆栈复杂又慢。你的应用程序需要的数据包的路径要更加直接。不要让操作系统来处理数据包。
- 做到这一点的方法是编写自己的驱动程序。所有驱动程序要做到是发送数据包到你的应用程序而不是通过堆栈。你可以找得到驱动有:PF_RING,Netmap,Interl DPDK(数据层开发套件),英特尔是闭源的,但是有许多绕开它的支持。
- 有多快呢?Inter有一个基准是在一个轻量级的服务器上每秒可以处理8000万的数据包(每个数据包200个时钟周期)。这也是通过用户模式。数据包通过用户模式后再向下传递。当Linux获得UDP数据包后通过用户模式在向下传递时,它每秒处理的数据包不会超过100万个。客户驱动对Linux来说性能比是80:1。
- 如果用200个时间周期来每秒获得1000万个数据包,那么可以剩下1400个时钟周期来实现一个类似DNS/IDS的功能。
- 用PF_RING来获得原始的数据包的话,你必须自己去做TCP协议栈。人们正在做用户模式的堆栈。对于Inter来讲已有一个提供真正可扩展性能的可用的TCP堆栈。
多核的可扩展性
多核的可扩展性和多线程可扩展性是不一样的。 我们熟知的idea处理器不在渐渐变快,但是我们却拥有越来越多的idea处理器。
大多数代码并不能扩展到4核。当我们添加更多的核心时并不是性能不变,而是我们添加更多的核心时越来越慢。因为我们编写的代码不好。我们期望软件和核心成线性的关系。我们想要的是添加更多的核心就更快。
多线程编程不是多核编程多线程: 每个CPU有多个线程
多核: - 每个CPU核心一个线程
- 当两个核心中的两个不同线程访问同一数据时,它们不用停止来相互等待
- 所有线程是同一任务的一部分
- 我们的问题是如何让一个程序能扩展到多个核心。
- Unix中的锁是在内核中实现的。在4核心上使用锁会发生什么?大多数软件会等待其他线程释放一个锁。这样的以来你有更多的CPU核心内核就会耗掉更多的性能。
- 我们需要的是一个像高速公路的架构而不是一个像靠红绿灯控制的十字路口的架构。我们想用尽可能少的小的开销来让每个人在自己的节奏上而没有等待。
- 解决方案:
- 保持每一个核心的数据结构,然后聚集起来读取所有的组件。
- 原子性. CPU支持的指令集可以被C调用。 保证原子性且没有冲突是非常昂贵的,所以不要期望所有的事情都使用指令。
- 无锁的数据结构。线程间访问不用相互等待。不要自己来做,在不同架构上来实现这个是一个非常复杂的工作。
- 线程模型。线性线程模型与辅助线程模型。问题不仅仅是同步。而是怎么架构你的线程。
- 处理器族。告诉操作系统使用前两个核心。之后设置你的线程运行在那个核心上。你也可以使用中断来做同样的事儿。所以你有多核心的CUP,但这不关Linux啥吊事儿。
|