zoukankan      html  css  js  c++  java
  • 网页端消息推送之推与拉

    需求之缘由

      用户A在网页段登陆,系统或其他用户的某些操作会导致在网页显示消息,用以提醒用户。实现方式大致有三种。

    1. 轮询拉取
    2. 建立长连接
    3. HTTP长轮询

    消息通知之发送方和处理方

      发送方

    • 系统发给A的“系统通知”,可能对实时性要求没这么高

    • 用户发给A的“聊天消息”,有对实时性要求比较高,越实时越好

      处理方

    • 有服务对消息进行逻辑处理

    • 有数据库对数据进行落地

    • 有缓存对数据进行加速

    方式之一_轮询拉取

     

    轮询拉取,是最容易想到的实现方式:

    • 发送方发送了消息,先入队列

    • 网页端起一个timer,每个一段时间(例如10秒),发起一个轮询请求,拉取队列里的消息

    • 如果队列里有消息,就返回消息

    • 如果队列里无消息,就10秒后再次轮询

    这种方式的优势是:实现简单,直观且,容易理解,互联网兴起时,人数不多的聊天室就是这么玩的。

    缺点也很明显:

    • 实时性差:最坏的情况下,1条消息进入队列后,10s之后才会收到

    • 效率低下:发消息是一个低频动作,如果10次轮询才收到1条消息,请求有效性只有10%,浪费了大量服务器资源

    更要命的是,在这种方案下,实时性与效率是一对不可调和的矛盾:如果将轮询周期设为1/10,将时延缩短到1秒,意味着100次轮询才会收到1条消息,请求有效性则降为了1%。

    方式之二_建立长连接

      如果要兼顾实时性和效率,长连接是最佳之选,PC端聊天软件基本都是使用长连接。网页端常见的实现长连接的方式有两种:

    • WebSocket

    • FlashSocket

    这两种方案的细节不再展开,ta们均有一定的局限性。

      局限性:由于websocket需要浏览器的支持,浏览器需要web-server支持,如果用户的浏览器不支持websocket功能,容易导致用户缺失某些功能。

    方式之三_HTTP长轮询

    HTTP长轮询的核心在于,浏览器与服务端之间建立了一条“通知连接”,它的特点是:

    • 这是一条browser发往web-server的HTTP连接

    • 这条连接只用来收取推送通知

    • 不像普通的“请求-响应”式HTTP请求,这个HTTP会被服务端夯住,直到有推送通知到达,或者超过约定的时间

    画外音:对于HTTP请求,为了提高效率,一般来说browser和web-server都会有一些设置,如果一条HTTP请求长时间没有数据(例如,150秒),会被断开。“通知连接”为了不被browser和web-server粗暴断开,一般会设置一个约定阈值(例如,小于150秒),由系统返回一个空消息,以便“优雅返回”。

    更具体的,对于这条“夯住”与“只收推送通知”的“通知连接”,是怎么玩的呢?

    场景1

    发起通知连接时,队列里正好有消息,则:

    • 发起通知连接,正好队列里有消息

    • 实时把队列里的消息带回

    • 立马再发起通知连接

    场景二

    发起通知连接时,队列里无消息,则:

    • 发起通知连接时,队列里无消息

    • 一直等待,直到触发“时间阈值”,返回无消息

    • 立马再发起通知连接

    场景三

    新消息来时,正好有通知连接在,则:

    • 新消息来时,正好有通知连接在

    • 通知连接实时将消息带回

    • 立马再发起通知连接

    上面三个场景的最终状态,都是“一定,永远,会有一条通知连接,连接在浏览器与服务器之间”,这样就能够保证消息的实时性。当然,有人会说,HTTP的返回与再次发起会有一个时间差,如果这个时间差,恰巧有新消息过来呢?

    场景四

    新消息来时,没有通知连接,则:

    • 新消息来时,没有通知连接

    • 把新消息放入队列

    最后这个场景,发生的概率非常小,但也确保了在“HTTP的返回与再次发起会有一个时间差”内,消息不会丢失,在通知连接发起后,消息能够实时返回。

    总结

    网页端收消息,究竟是推还是拉?

    • 最容易想到的是拉,但实时性和效率是一对无法调和的矛盾

    • 最佳的方式是推,但WebSocket和FlashSocket各有局限性,需要浏览器的支持

    • 最通用的方式是长轮询,通过HTTP短连接拼装长连接,具体是通过“夯住”“只收推送通知”的“通知连接”来实现的,能够做到消息的实时性到达

     

  • 相关阅读:
    Spring 注解@Transactional
    数据库中为什么要建立视图,它有什么好处?
    类、抽象类与接口的区别
    Comparable和Comparator的区别?
    jetty安装
    python 命令行参数sys.argv
    python--用户认证登录实现
    python--查询员工信息
    python基础
    python学习之路---编程风格规范
  • 原文地址:https://www.cnblogs.com/lufeiludaima/p/pz20190208.html
Copyright © 2011-2022 走看看