Chinaunix首页 | 论坛 | 博客
  • 博客访问: 178894
  • 博文数量: 58
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 14
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-29 17:51
文章分类
文章存档

2015年(3)

2014年(8)

2013年(47)

我的朋友

分类: C/C++

2014-01-03 13:12:34

有空记录下今天的想法,如有问题,欢迎指出!

需求是:要对网络上的报文按照会话进行合并,每分钟处理一次。也就是说每分钟到来的报文都需要进行合并。
最初的做法是:每来一个报文,按照五元组的或运算进行哈希查找,合并到已有节点上或者存储到新的位置。当一分钟到来
或者哈希表存储满(哈希表节点的内存池耗尽)时,就需要进行数据处理。处理完了,清空哈希表,继续下一次操作。
当数据量比较少时,这样做是没问题的。
但是一下情况会导致严重的问题出现,问题现象是:丢包,或者说报文不能完全处理过来。

条件是这样的,有一个程序匀速产生报文,我们的处理程序负责合并和处理。

第一:当报文的五元组都在一个很小范围内,而且不完全相同时,会导致这样的情况:能合并的报文不多,但是他们却都被定格在了
哈希表的一个下标上(专业术语貌似叫‘桶’),这时,合并的效率是很低的,几乎接近于遍历链表,节点越多,越慢。因此,
对一个报文实时去串行合并处理,会花费较多时间,从而减慢了读取的速度,导致丢包出现,性能不能达到要求。
第二:满足处理条件时,当前的报文会触发数据处理操作,如果这个数据操作占用时间比较长的话(比如批量入库花费2秒),会导致瞬间的读取速度下降,
或者瞬间停止读,从而导致写报文的进程和读取进程的缓冲区溢出,数据丢失。

分析引起问题的根本原因是,写进程是稳定速度写入的,比如每秒5万条记录,而处理进程则不是匀速处理的,也就是说处理进程
有一个“僵死点”,在这个‘僵死点’,读写进程速度差异太大,记录数大到读写之间的缓冲区不够存储。
解决办法是:把引起僵死点的操作用另外一个独立于读数据的线程来异步处理,这样就能保证读取线程始终以匀速来读取数据了。
然后创建多分缓冲区,组成一个环形链表,读线程每时刻处在一个节点上,当这个节点的数据填满时,修改标志位通知处理线程,处理
线程也遍历环形链表,挨个处理每个节点上的数据(其实每个节点就是一个缓冲区,比如大小为300万个节点的容量)。这样,
只要处理一个缓冲区的时间小于读线程填满一个节点时间,就永远不会出现溢出情况或者数据丢失,而且N-1个缓冲区作为缓存,平滑了
读线程和处理线程的速度差异引起的波动。

最后,一个更好的方法就是:如果处理线程支持多路的话(当然首先多路的速度肯定要比单路快才行),
可以创建不止一个处理线程来处理数据。比如有10个节点的环形缓冲区,每个节点300万个元素,30个元素占用1K空间的话,每个节点
大概100M空间,10个节点占用1G空间,可以并发5个处理线程,一个读线程,这样就大大提高了处理的速度,而且不影响写数据应用和
读线程的速度。
这样做,充分体现了程序设计中牺牲空间换时间的规律。

阅读(1340) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~