在网络通讯中会经常面对一种情况就是信息广播转发,比较常见就是QQ群聊天。群里的人只要发一条信息就会广播到群里的其他人,不过这种转发量是非常的少一般情况下直接把通过对应用户的socket.send方法发送出去即可。但有些情况并不允可你这样,为什么呢?因为在某些场景下这些信息的转发量和密集度是非常之高,数量可以达到每少10w,20w,50w,100w或更多,也许你的服务器性能好每秒10w的IO不算什么问题,那面对一100W或更多的消息转发呢?有人会可能会问那来这么多的转发量,其实一个同场500的用户,每个用户平均每秒有两次行为改变,那就足以产生50W的转发量了。
从上面的图可以看到用户之间的交互都会压在服务器上,其信息交互是每秒都会产生这样的量,以上图紧紧是6个,如果是500或1000个呢?那是一个怎样的情况。所以从IO的吞吐数量想把这些信息吃了是件不可能的事情。
针对上面的情况我们需要做的就是控制IO,有朋友可能会问题怎么控制,难不成不Send?其实做控制很简单,其实只需用固定的资源去做某些事情就行,当工作的损耗超出的额定资源的情况就让他等一下。
通过线程队列就可以控制IO处理的数量,当队列不存在堆压一般有以下情况:1的线程有足够的资源完成这些事情,2你需要转发的消息不多对队列构不成压力。其实这些情况都不需要进行合并,因为处理不存IO压力。
当队列存在压力的时说线程没足够的资源来处理大量IO,这时候我们就需要做些额外的工作发送数据合并,减低IO压力。
把当前队列的所有数据拿出来进行一个合并处理,然后再发送。整个过程都是内存操作其性能远高于网络IO处理,如果这个过程的实现比IO还损耗资源,那就认真的检查一下实现方法,这是不应该的。
以上这种方式实现的延时是非常乐观的,同时它能根据当前资源的使用情况来决定是否进行合并数据操作。当你服务器资源满足,但延时上有点高那就可以通过多队列来处理,把压力分担到其他线程上以达到一个短的延时处理。
在实际应用测试中由于网络带宽受限,所以只测试了500物体同场景测试,每个物体每秒产生两次变化,实际广播信息在50W每秒,发送IO大概1.5w每秒。core e4300的cpu占用大概在25% 左右,内存使用60mb,带宽80Mbps.,延时大概是60ms左右.
以下是转发信息结构:
class Po : IMessage { public int ID; public short X; public short Y; public short Type; public void Load(BufferReader reader) { ID = reader.ReadInt32(); X = reader.ReadInt16(); Y = reader.ReadInt16(); Type = reader.ReadInt16(); } public void Save(BufferWriter writer) { writer.Write(ID); writer.Write(X); writer.Write(Y); writer.Write(Type); } } |