HonorLee
2020-02-19 16:19:55 +08:00
目前我在做同样类型的项目,智能设备通过 Nodejs 进行 Socket 长连接并实时发送数据,用到了 Redis 做缓存和 Mysql 持久化
对于连接数 Nodejs 可以采用单机多进程负载和多机负载,Node 的 IO 效率很高,在不需要做密集型 CPU 计算.信息收集到直接存储的,单机单进程就可负载大量的 TCP 连接.上层可以用 Nginx 或是其他前端负载方案进行负载,但要注意如果同时监控设备连接状态的话,尽量做好但设备断线后(负载后)重连的自冾问题,应为有时候网络原因或其他原因会导致 Node 未收到断开信息包时,tcp 连接已经断开了.同样在计算量不大的情况下,服务器硬件配置反而要求很低.树莓派级别的就可以处理大量的 tcp 了
不太了解 flink,kafaka 经过测试,不太适合我们的项目,所以我自己写了一套基于 TCP 的消息转发和轮询分发的消息中心,但原理上与 kafaka 和各种主流 MQ 不大,同样具备消息校验、重发、队列等等,最重要的就是保住消息的实时性而非削峰;
说一下我这边的解决方案:
Socket 服务 S,计算、存储信息服务 Assist,消息中心 M,前端用户接口 CA,Redis 主缓存 RM,Mysql 主备+读写分离 MM,日志及其他 Redis 缓存 RL,Mysql 日志 ML
其中
S 服务负责硬件设备的 Socket 连接,接收设备的上报以及来转发自用户的控制指令至设备,没有大量计算,仅仅是解析设备信息通过消息中心轮询转发至 Assist 服务,或组装用户 TCP 消息通过 Socket 连接发送给设备。服务具备可负载、自冾、自维护能力。
Assist 助理服务,负责处理整个业务的计算工作,读写缓存、计算状态、生产日志等;这个服务是强负载,多个服务器多个进程通过被轮询的方式接收大量的处理工作,这一块压力是最大的,但好的负载可以减轻压力;但要注意一点就是缓存或持久化存储在负载处理状态下,必须要考虑分布式锁,避免多个服务进程同时读写同一个 Key 导致系统问题或数据问题。
CA 接口就是针对前端用户的 API 或其他功能,来调取数据,可涉及部分计算,可负载可不负责,根据项目情况。
RM 主缓存用来存储设备的实时状态信息,当然也保留了最后上报的 100 条状态信息,可根据实际情况进行调整,用来加快用户端所获取数据的计算,避免用户的每次请求或计算都落在 Mysql 上,最大限度提高缓存的利用率并降低 Mysql 的读写并发,可以保证系统的稳定性,但同样要考虑好 Redis 服务器和 Mysql 的架构,如有必要分布式缓存和 Mysql 负载也不能少
MM 主要数据库存储的大部分是一些固化数据,比如系统配置、用户管理、设备管理、订单记录等等,数据变动量少,更多的压力是在读而非写
RL 日志缓存主要用来临时存储所有服务在运行过程中持续生成的日志数据,为了降低 ML-Mysql 日志数据库的写入压力,先写入 Redis 缓存,然后利用独立的日志处理程序,定期从缓存中分批读出日志然后持久化等等
其他的则考虑一些分布式系统常用的优化和解决方案。
我们这套系统架构设计目的是在不影响各节点或其他服务的情况下进行单服务的重启维护,而且实时性要求极高,后期在设备上线量越来越多后,可能面临秒级单位的万、百万甚至千万条消息或数据上报、传递等大并发情况,所以系统的各个服务也建立的不同的负载方案,保证能随时进行横向扩充而且不会影响现行服务。
最后说一下,系统架构不是一成不变的,需要根据项目的实际运行情况、预估后期的运作情况,进行迭代更新和调整。
希望我的经验可以给你提供一定的帮助。