管好超时才能做好异步
Posted jinsexiaomifeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了管好超时才能做好异步相关的知识,希望对你有一定的参考价值。
回到正题,今天说说超时,做服务一定绕不开大并发、高效率、可靠稳定、快速响应这些关键词,从技术的角度上讲,每个环节每个步骤都有值得大书特书一番的地方,不过个人觉得最最重要的地方还是超时管理,这方面做好就成功一大半了。首先介绍一下应用场景,作为一个服务,对外受理接入请求,请求报文到达以后先解析,理解用户想要干什么,对于当下大多数的互联网业务,往往需要一系列逻辑处理,这边取点标签那边取点参数,汇总起来算一算得到最终结果再给用户返回回去。随着互联网的发展数据量越来越大,数据本地化早已不能满足业务需要,在逻辑处理过程中数次调用远程通信已是再平常不过的事情了,这就产生了上下游多个节点间的数据通信与传输的问题,那么多连接有tcp的有udp的,有长连接的有短连接的,有先发后回的,有后发先回的,有发了不回的,有不要还回的,各种情况都要考虑到,一个字忒乱。
怎样把超时管理起来呢,epoll非常棒但终究是事件触发的,把超时转化为事件是想要达到的目的。成千上万个连接的超时设置的有长有短,最讨厌的是这些连接还是剧烈频繁变动的,对于有序容器管理这些连接成本真的有点高,要是再加把锁实现进(线)程同步,效率有点让人焦虑,既然不能全局有序可不可以局部有序呢,只关心最值而不是顺序本身,根堆的偏序特性是个相当不错的选择,二叉树每次插值调姿开销确实有点大。根堆分大小,取决于比较函数,不是全局有序因此迭代器意义不大,元素追加弹出基本够用了,在用例中比较函数计算(入队事件 + 超时事件 - 当前事件)最小值当做堆顶。
第2行从小根堆中获取一个元素,获取成功就用套接字超时作为epoll_wait超时,否则阻塞直到有事件发生为止。
第11行判断返回值,如果大于零表明有待处理事件发生,等于零表明有超时发生。
第13行至24行对事件处理,是新接入子套接字则加入epoll监听,否则派发任务到工作线程。
第28行至32行清除epoll事件并从根堆中剔除元素,同时返回上游错误信息。
第8行读取消息(既可能是上游消息也可能是下游消息),大于零启动业务处理,否则清除epoll事件并关闭连接。
第9行识别报文格式,用例采用0x04标识示意,具体业务侧应采用更加严格的定义。
第11行调用上半场处理函数。
第15行调用下半场处理函数。
第13行至18行业务实现过程。
第21行或23行为初始化下游连接操作(tcp和udp是个人封装过的),需要注意的是,udp需要采用connect方式初始化,即将对端地址关联到套接字上,以方便read读取。
第28行和29行在发送完毕数据以后将套接字再次注册事件和追加到超时根堆中去。
第32行若tcp连接失败则向上游返回失败信息,udp只能通过超时判断。
第8行至9行清除epoll事件并从根堆中删除元素。
第11行至13行业务实现过程。
第15行至20行根据业务实现结果向上游返回不同的消息。
第6行获取当前的系统时间。
第7行入队时间加上超时时间。
第9行至11行计算当前时间与超时时间的差值。
第13行将差值转换成epoll超时的时间单位。
完整的代码片段http://git.oschina.net/gonglibin/codes/rc87dt0iagk4exqm3psuw66,作为论证和用例代码仅供参考,调试测试通过,根堆封装成对象的时候已经加入锁,epoll对象早年封装的没有考虑同步的问题,代码中通过注释已经提请留意了。
来源:云栖社区
以上是关于管好超时才能做好异步的主要内容,如果未能解决你的问题,请参考以下文章