内存的可扩展性- 问题:假设你有20G内存(RAM),第个连接占用2K,假如你只有20M三级缓存(L3 cache),缓存中没有数据。从缓存转移到主存上消耗300个时钟周期,此时CPU处于空闲状态。
- 想象一下,(处理)每个包要1400个时钟周期。切记还有200时钟周期/每包的开销(应该指等待包的开销)。每个包有4次高速缓存的缺失,这是个问题。
- 协同定位数据
- 不要使用指针在整个内存中随便乱放数据。每次你跟踪一个指针都会造成一次高速缓存缺失:[hash pointer] -> [Task Control Block] -> [Socket] -> [App]。这造成了4次高速缓存缺失。
- 将所有的数据保持在一个内存块中:[TCB | Socket | App]. 为每个内存块预分配内存。这样会将高速缓存缺失从4降低到1。
- 分页
- 32G的数据需要占用64M的分页表,不适合都放在高速缓存上。所以造成2个高速缓存缺失,一个是分页表另一个是它指向的数据。这些细节在开发可扩展软件时是不可忽略的。
- 解决:压缩数据,使用有很多内存访问的高速架构,而不是二叉搜索树。
- NUMA加倍了主内存的访问时间。内存有可能不在本地,而在其它地方。
- 内存池
- 在启动时立即分配所有的内存。
- 在对象(object)、线程(thread)和socket的基础上分配(内存)。
- 超线程
- (一个)网络处理器能运行4个线程,Intel只能运行2个。
- 掩盖延迟,比如,当在内存访问中一个线程等待另一个全速线程。
- 大内存页
- 减小页表的大小。从一开始就预留内存,并且让应用程序管理(内存)。
总结 - 网卡(NIC,Network Interface Card)
- 问题:通过内核驱动并不完美。
- 解决:使用你自已的驱动程序管理它(网卡),使适配器(网卡)远离操作系统(内核)。
- CPU
- 问题:采用传统的内核方法(即使用内核驱动)来协调应用程序,效果并不是很好。
- 解决:让Linux管理前两个CPU,您的应用程序管理其余的CPU。这样中断就不会发生在不允许的CPU上。
- 内存
- 问题:为了使其更好的工作,(内存)需要特别的关照。
- 解决:在系统启动时就给你管理的大页面(hugepages )分配大多数的内存.
(仅)把控制层留给Linux,与数据层毫无瓜葛。由应用程序管理数据层。应用程序与内核间没有交互。没有线程调度,没有系统调用,没有中断,什么都没有。
然而,你拥有的是在Linux上运行的代码,并且可以正常调试,它并不是某些需要特殊定制的怪异的硬件系统。你得到了定制硬件的性能,就像你期待的那样,只是需要用你熟悉的编程(语言)和开发环境。
|