给大家推荐一个开发者的知识库里面收录了 Java 程序员需要掌握的核心知识有兴趣的小伙伴可以收藏一下。网站https://farerboy.com一、背景介绍唯品会是一家立足于全球精选正品特卖的电商网站拥有4亿注册会员日活约2千万会员。随着会员数量的增多公司业务部门的飞速发展和用户的沟通变得日益重要。沿用至今的消息网关面对多变的业务和爆发式增长的消息面前显得力不从心多次大促出现性能瓶颈急需重构来跟上公司业务发展的需要。二、唯品会消息网关的架构定位在本次重构中将原来耦合在一起的消息发送渠道被拆分成逻辑消息网关和物理发送渠道。逻辑消息网关后面均用消息网关来代替作为消息发送的总入口对接上游各个业务系统为业务系统提供友好的发送受理服务。逻辑消息网关的下游对接各个物理投递渠道负责对接第三方信道提供方如电信微信等。在重构前消息网关和营销系统耦合较紧包括定制化功能和共用的开发团队。在重构后逐渐剥离了这种关系使得消息网关定位为公司级的基础服务层。其主要职责是受理投递、频次控制、尽力发送、反馈统计、削峰匹配慢速信道。下面介绍一下消息网关在唯品会整体系统中的定位。如图1所示消息网关定位于基础业务服务层而物理信道定位在基础设施层两者之间明确的区分了是否业务相关。那么消息网关具体内部应该是个什么样子下面我们一起来看一下图2消息网关的内部构造。一个合格的消息网关应该具有以下的功能业务友好的受理层模板管理频次控制基于优先级队列的消息分发反馈统计延时发送订阅控制以及其他一些辅助功能。在第二部分将逐个模块的讲解。三、如何设计消息网关在图2中我们全面概览了消息网关内部应该具备的各个功能模块下面我们逐个模块分解看看各个部分的功能模块应该如何设计。1. 消息的受理和分发在实际的业务场景中发送给会员供应商和内部工作人员的消息分为三种类型关键性消息通知类消息以及营销类消息。关键性消息的特点是低时延低吞吐。通知类消息的特点是中时延高吞吐。营销类消息的特点是中时延高吞吐。针对不同的消息类型应该选择不同的受理和分发模块避免互相干扰。如图3所示。对于关键性消息某些渠道如短信必须设置专用的独占信道来满足业务要求。如图4所示中国移动信道质量较其他的供应商更好所以对于关键性消息通过专线连接主要服务商并同时接入电信联通haproxy做备用线路。2. 面向业务友好的接口对使用消息发送服务的业务方来说最好的接入方式是访问配置好模板的统一接口对于需要高度个性化的营销系统是个例外营销系统倾向于在系统内部完成消息个性化的逻辑尽量保持代码接口调用的固定对于少量变动通过修改配置的方式完成。这么做有两点好处一是消息网关内部的优化和渠道变动逻辑不需要被业务系统感知。二是使用预设模板降低了系统交互的开销。图5展示了统一接入接口在系统中的位置。3. 频次控制消息网关需要保护会员不被过多的打扰提供重要的兜底功能。随着业务的发展商城、金融系统逐步独立分散的营销系统往往无法从全局上兼顾整体营销。在营销强度模块正式运行之前控制过度营销的最后一道闸门控制在消息网关这里。图6展示了消息网关在统一接入接口处检查频次控制的情况对于超过限额的发送请求会直接拒绝受理。4. 用户订阅现代消息发送系统都会提供用户退订功能允许用户对希望接收的渠道和功能进行自主选择。那么用户订阅的关系应该维护在哪个系统比较合适呢在实践中发现订阅关系维护在会员系统比较合适消息网关查询订阅关系通过接口访问加缓存的方式去获取。同时各个渠道的退订消息也需要经由消息网关上报到会员系统更新订阅关系。图7展示了用户订阅的调用图。5. 失败重试消息网关调用下游物理网关不可避免的会出现调用失败的情况。那么这个时候就需要进行失败重试。失败重试分为2大类重试失败需要落盘的和重试失败直接记录异常日志的。验证码属于后者。对于通知类消息可以容忍一定的时延采用落盘定时任务轮询重试的方式比较合适。对于营销类消息在时效期内可以落盘重试极端情况也可以采用记录异常日志然后直接丢弃的方式。6. 反馈统计从业务系统投递消息开始会经过消息网关物理消息渠道第三方供应商等多个环节。每个环节都有可能造成消息的丢失因此设计反馈统计机制很有必要在错误排查和费用统计等方面有重要作用。实践中采用反馈队列的方式进行异步统计有分钟级的延时。对消息的最终发送结果ETL到大数据进行费用统计和费用分摊计算。四、消息网关的技术选型业务模块开发采用唯品会自研的RPC调用框架Venus采用OSP协议唯品会私有协议来封装RPC调用底层通信协议采用Netty传输协议使用Thrift。数据库技术选型MySQL。消息队列用Kafka应对高吞吐量消息场景。ETL使用自研VDP(类似于阿里开源的Canal)解析binlog同步数据到HDFS。图10演示了Venus框架的基本结构。Venus框架是一个去中心化的RPC调用框架Client端对Server端的调用由proxy进行转发。Client到LocalProxy以及Local Proxy到Server端保持TCP长连接。Proxy提供跨语言支持服务治理服务发现路由调度限流熔断等功能并额外支持HTTP GET URL Path/ParameterHTTP POST JSON和RPC OSP协议的转换。Proxy分为LocalProxy和Remote Proxy。Local Proxy和Client部署在同一台服务器上通过Domain Socket减少TCP栈的调用开销。Remote Proxy作为备用链路提供防火墙穿透跨组织调用非Java语言HTTP JSON调用等功能。消息网关重度依赖kafka队列分成消息受理队列消息异步落盘队列延时写入队列反馈队列等。由于整个消息网关基本都是异步化操作消息的分发有可能早于消息的落盘这样在数据库消息发送状态更改时就会出现无法找到的情况。可以采用延时队列对消息发送状态的落盘动作进行延时写入。五、消息网关的监控和降级1. 消息网关的监控在日常运维层面消息网关需要监控如下的指标一是受理域分发域各接口的调用情况。这部分数据已经在Venus框架内置导入Mercury监控系统类似于携程开源的CAT系统。二是Kafka队列的消息堆积情况监控。三是采用Zabbix监控数据库服务器的CPU负载内存使用量磁盘IO等关键性指标。四是消息网关内部监控各物理渠道的投递时延。2. 消息网关的降级措施应用于生产系统的消息网关需要部署降级预案保证故障发生时可以尽快的恢复降低故障带来的负面影响。下面列出了部分重要的降级预案。受理域机器宕机由Local Proxy调度转发到正常工作的机器上。Kafka无法提供服务运维提供分钟级紧急恢复期间消息发送受理中断。已入队列但尚未发送消息在原集群恢复后继续发送。数据库主库宕机影响消息状态变更和消息异步落盘。切换到从库。不影响消息的正常发送影响反馈和统计。用户系统订阅关系无法返回结果降级为不再查询默认全部订阅。物理消息网关宕机投递失败有重试机制保证。消息本身不丢失可以在物理渠道恢复后重发有效期内的消息。六、消息网关的几点思考1、业务边界的划分消息网关本身的设计并不复杂使用的技术也是成熟的技术。消息网关的难点在于对于系统业务边界的划分。由于和消息网关打交道的业务系统较多很多功能可以由上游完成也可以由下游实现这个时候就需要权衡各个方面找到折中的方案。在实践中唯品会是这么划分业务系统边界的。用户系统管理用户订阅情况消息网关管理订阅大类和消息模板的映射。消息网关管理消息逻辑层分发物理发送渠道管理具体投递行为。消息网关管理渠道沟通频次营销系统管理营销沟通频次。风控系统提供消息防刷机制易被攻击服务经过风控验证码服务接入消息网关。消息网关提供简单消息模板管理功能非营销类业务系统不自行管理模板。人群标签由用户画像提供渠道动态规划由消息网关承载。营销系统个性化消息组装由营销系统自行负责消息网关只提供发送功能。2. 消息网关数据的使用消息网关的投递的营销消息订阅情况打开率等是营销画像的重要组成部分。全景营销平台可以将消息投递情况、打开率、花费作为营销强度计算的数据源。消息网关数据是各个业务部门费用分摊的主要依据涉及上市公司的财务审计。另外通过消息网关数据统计可以作为各个渠道服务提供商选择和替换的依据。3. 一些踩过的坑短信物理网关的通讯协议按照运营商的不同分成CMPP/SMGP/SGIP三种。都是基于TCP协议上的私有协议需要自行处理断包和粘包问题。需要将包解析类CmppDecoder移动/SmgpDecoder电信/SgipDecoder联通配置到Mina框架NioSocketConnector的FilterChain里面。用IoSession来完成收发操作。消息网关异步化引起的问题比如消息数据异步落盘可能落后于消息发送状态的更新。需要引进延时队列通过定时重试解决此问题。Redis使用上的最佳实践比如Redis存储Value的String不要超过2k字节理论最大值512M以不超过1个网络包(MTU 1500byte)为佳。Set和Sorted的elements不要超过5000个。压力测试机器上配置的最佳实践比如需要配置/etc/sysctl.conf的选项net.ipv4.tcp_syncookies 1 net.ipv4.tcp_tw_reuse 1 net.ipv4.tcp_tw_recycle 1 net.ipv4.tcp_fin_timeout 15七、小结这篇文章总结了唯品会在消息网关重构中使用的架构思路和经验。文中提到的消息网关在今年6.16大促高峰期承担了亿级的消息发送压力经过实践的检验稳定可靠。希望对于行业内有相同应用场景的公司能提供一定的设计借鉴作用。系统的设计无法完美希望不吝赐教共同构建起更加高效和稳定的系统。