大屏技术演进-推模式

1,506 阅读5分钟

一、问题

  • 在我们上一篇文章《大屏技术演进-拉模式》最后思考部分,我们提出条件单一使用拉模式其实也可以,定时控制一下时间粒度问题,整个架构也简单,那如果我们条件增加了呢,用那个模式是不是又回到前端请求同时要根据条件计算的问题呢?
  • 我们是否可以理解为在大屏上面其实在很多时刻可能没有大量日志数据打点,那我们在人类社会一般沟通方式都是:你有事叫我,没事别叫我(尽量少这样做,会没有朋友的),在服务架构上,咱们还是尽量做到:有日志上报通知我,而前端不需要定时去拉取数据,数据拉取也是需要消耗网络流量的。

二、解决方案

那么基于上面两个问题,我们要思考方向就是推的模式,这里使用时websocket,中心思想就是:有日志上报大屏就有网络请求,没有上报就老实一点,别发请求了,省省吧

那么对应websocket不太理解的同学,可以考虑看下 WebSocket原理及如何使用 ,里面讲解的比较详细。


上我们的时序图:


说明:

  1. 大屏在打开的时候,会发起一个websocket的connect请求,这个时候连接成功后,会进行一个token的返回。
  2. 将返回的token与前端请求的条件参数进行合并提交请求到服务端,服务端将token与条件进行一个绑定操作,条件进行唯一值计算,我们使用是md5,在redis里面进行一个集合的绑定操作。
  3. 后台任务会定时去拉取这个关联关系,并且将条件参数提取出来,将条件进行一个单独的进程去进行对应的计算,多核cpu下面,可以考虑使用线程或者多进程来实现,当然如果是go语言,直接用内置的协程也是可以的,毕竟在语言级别实现csp模型还是非常不错的。
  4. 因为是多个模块数据数据生成,并且多模块下面有一些是实时数据,还有一些是要增量数据,实时数据在每次计算都可以覆盖以前的,而增量的数据只能判断当前是否有数据,没有数据不能覆盖数据源,只有有数据才可以进行覆盖。
  5. 计算发现数据版本已经变更后,就通知服务端 条件(condition)与模块列表(modules)需要更新,服务端收到请求后,就将关联关系里面 条件对应的token取出,然后一次性对于这些token发起服务端推送操作,内容就是模块列表(modules)
  6. 前端使用onmessage接收到响应后,在使用token与module请求服务端获取对应模块的数据,服务端获取modules列表后去对应redis里面取出数据直接返回给前端。
  7. 大体的流程就是上面所讲的。


三、过程中的问题

Q:websocket为什么要用ping/pong来维持?

A:因为在本方案里面,ping/pong心跳用来确定一个大屏是否打开的,因为我们在后端计算大屏数据是跟我们的条件来走的,如果我们的大屏掉线了,能够及时通知后台任务,那么我们的计算量会少很多

Q:用ping/pong就能百分百保证我的websocket不会断连吗?

A:答案是否定的,互联网上真没有百分百的事情,网络的一个抖动,我们的ping/pong就有可能挂了,这是很正常的情况,我们在业务上会对于ping/pong进行一些重试机制,这个重试可能会短时间内的,比如1s内发起多少次请求的;如果这个请求不能正确获取数据,那么服务端过期后,其实这个token就没有太多用处了,前端就会有个定时器去探测websocket服务与本地通讯是否有问题,没有问题进行重新的connect操作,而在探测过程中,我们有个降级操作,会将我们websocket操作变成传统的拉模式,这个要结合我们上一篇文件技术方案。

Q:我条件肯定会变更,变更证明做?

A:这是一个好问题,因为啥,切换大屏参数直接导致我们很多模块数据是需要重新渲染的,那么我们需要重新的发送push操作,然后后续逻辑是一致的。

Q:为什么要用token的介入呢,我已经登入系统了,直接uid就可以不?

A:开始我们也是考虑到uid的方案的,为什么不行呢,主要是我们这里的token是跟websocket相关的,可以近似的认为是socket里面的fd,比如我一个人开了10个大屏,那么我推送的那一刻,我需要将10个大屏数据都能推送到,而区别就在于,uid只有一个,token是10个


四、总结

这里为什么花了两个篇幅来写大屏这块呢,主要是在一些简单场景下,我们1.0版本会更适合,毕竟websocket相对于流程复杂一点,那么中间节点处毛病地方就会多一点,但是复杂场景下面,又必须要这样做设计,所以我们就分开两个文章来进行说明。

希望通过两篇文章,同学们能够从中学习到大屏制作技术方案的相关知识点,能够让我们应对产品经理 完(刁)美(钻)需求时候,我们有一个非常合适的技术方案输出。