Fork me on GitHub
网络通讯合并数据发送的重要性和实现原理

在网络通讯中会经常面对一种情况就是信息广播转发,比较常见就是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);
    }
}

  

专注于可靠、高性能的Socket TCP通讯组件
posted on 2012-05-10 20:22  HackerVirus  阅读(195)  评论(0编辑  收藏  举报