上周六,公司加班举办技术专场招聘活动,在忙碌的下午茶歇时间,我尊敬的伟大的韩百万老师提议带着我去瑞幸装了个 BI,扫码领取咖啡的那一个瞬间,瑞幸店内的电视大屏上赫然显示了:韩百万。回来的路上我虚心请教韩老师,才得知这是瑞幸为其黑金鹿会员提供的专属特权权益:王者霸屏!
原本以为这只是一次单纯的装个 BI 行动,谁曾想我“卷”到天际的充满挑战精神的韩百万老师周一又给他的大虾兄弟出了一道题:你想想怎么实现这个功能?。
然后就是“卷”到我了。从技术角度看,这是一个既经典又有趣的场景,涉及到微服务架构、服务间的通信、分布式事务处理以及其他一些非功能性需求的满足。于是乎,我接下了这个“卷”,从单纯的技术角度探讨下这一个场景的具体实现方式。
文章声明:本文所探讨的实现方式仅作为技术交流和娱乐探讨,与瑞幸咖啡实际采用的方案无关,请勿将本文内容与瑞幸咖啡的具体实现方式强行对号入座!
一、全局架构设计
我们先从全局的视角来看整体的架构设计思路:
上图简单示意了一个支撑王者霸屏的微服务架构,从层次上看:
首先,端侧层面包括提供给用户下单的 APP、线下店里的扫码器以及线下店里的大屏等设备,这些设备直接与用户进行交互,构成整个系统的前端。
其次,有明确的网关层,作为微服务架构的入口,承载流量流量网关和业务网关的双重职责作用,不仅可以对请求进行负载均衡,还可以对服务进行鉴权处理,特别是在高流量负载的场景下可以在网关层实现对请求进行限流/降级处理,保证系统的稳定性和可用性。
在和端侧交互的层面,我引入了一个消息队列,虽然在常规系统架构设计中,消息队列的位置不太会出现在这里,上图这个位置主要是为了说明实现和大屏的交互,你猜对了,在王者霸屏这个场景下,我选择了消息队列作为系统和大屏的通信交互方式。
在服务器端,我采用微服务的设计模式,针对王者霸屏这个场景,我设计了多个微服务,包括提供用户信息相关查询的用户微服务,处理咖啡下单商品微服务、订单微服务、库存微服务,以及对接消息队列的微服务(是否需要把消息队列相关的独立成微服务取决于实际场景需求,比如在上图中存在一个与端侧交互行为控制的微服务,那消息队列相关的就不必独立出来)。
最后,底层就是各个微服务对应的数据存储部分,为了简化表达,我未详细展示每个微服务的具体数据存储设计,在实际场景中,每个微服务都有其对应的数据存储方案,以满足各自业务功能的需求。
二、王者霸屏设计
基于上述微服务架构模式,再来看看王者霸屏功能的实现流程:
在这个过程中,用户的扫码行为虽然是一次性操作,但实际系统中可以被解耦为两个处理流程:
- 扫码后先对订单进行完结处理,处理完成后返回用户侧。
- 同时另外一个处理流程是判断用户是否符合王者霸屏的资格,如果符合,发送消息给消息队列,由大屏服务订阅对应的消息并进行内容展示。
三、关键技术考虑
从我之前对分布式系统架构相关内容的介绍,在王者霸屏这个场景下除了上面的架构设计和流程设计,作为架构师或者主要研发担当来说,还应该考虑以下关键技术点:
1、数据库和缓存
在瑞幸这个场景下,比如对用户订单的数据存储是要考虑分库分表策略的,选型上可以是常规关系型数据库或者新型关系型数据库。
同时为了提高系统的性能并降低数据库的负载,可以使用 Redis 等缓存数据库来对用户信息、王者霸屏资格等这些变动不会那么频繁的数据进行缓存,比如用户信息和王者霸屏的资格状态。
该流程中涉及到不同数据库不同数据表的操作,因此,充分考虑分布式事务的处理机制。
2、系统的扩展性和可维护性
在进行微服务设计时,要充分考虑到各个微服务系统的扩展性,让各个微服务之间尽量独立和解耦。
可使用容器化技术和集群管理,来提高系统的扩展性和可维护性,如 Docker 或者 Kubernetes。
3、安全性
端侧和服务端进行交互需要使用 HTTPS。同时对用户数据要进行适当的加密和脱敏处理。
4、监控与日志
适用 Prometheus、Grafana 等工具进行系统的监控和日志收集,确保系统出现异常时可以及时发现和处理。
四、替代方案思考
1、实时数据库同步方案
将王者霸屏的信息实时写入一个共享的数据库,大屏显示器服务直接从数据库读取最新的数据进行展示。这种方案实现相对简单,数据一致性较好。但是对数据库读写性能要求很高,特别是在高并发的场景下。
2、RESTful/WebHooks
王者霸屏资格确认后,可以通过调用大屏显示服务提供的 RESTful 或者直接触发对应的 WebHooks 来推送消息。这样做相对灵活,可以实现跨平台、跨服务的通信,但是需要保证 API 的稳定性和安全性,可能存在网络延迟的问题。
3、Redis 的发布-订阅功能
使用 Redis 的发布-订阅功能,王者霸屏资格确认后发布消息,由大屏显示服务订阅并展示,这种方案实时性高,性能很好,但是数据持久化相关的操作需要额外处理。在瑞幸这个场景下,可以考虑适用该方式来替换消息队列的实现方式。
4、SSE 方案(Server-Sent Events)
王者霸屏资格确认后可以通过 SSE 向大屏显示服务推送信息,这种方案实时性比较好,也相对轻量级,但是需要保持长连接,对服务器资源有一定的消耗。
5、WebSocket 通信方式
建立王者霸屏资格确定服务和大屏显示服务之间的 WebSocket 连接,实现实时数据推送,实时性比较高,适用于需要频繁交互的场景,但是在王者霸屏场景下适用性比较低,而且这种方案下需要管理 WebSocket 连接的生命周期,对网络和服务性能有一定要求。
当然,除了我介绍的这些方式,一定也还有其他实现方式来实现王者霸屏,具体选择哪种方案需要根据实际业务场景、技术栈以及系统性能要求来进行综合考虑做出最终的方案选型。屏幕前面的你,还有其他方案吗?可以留言一起聊聊~