本篇文章内容来自2016年TOP100summit 58到家架构师封宇的案例分享。
编辑:Cynthia
2017年11月9-12日北京国家会议中心第六届TOP100summit,留言评论有机会得到免费体验票。android
封宇:58到家架构师。主要负责到家消息系统以及H5门户等公司战略级产品研发。在消息设计,流量增加等方面经验丰富。redis
导读:经历野蛮发展阶段后,58到家存在众多消息收发场景及不一样技术。本案例总结多个业务场景下消息收发的难点与挑战,梳理各项技术的特色,结合实际业务及研发需求,构建了一套通用消息投递方案。方案创建统一的端到端、端到服务器、服务器到端的消息通道,对业务方屏蔽不一样技术的差别,提供消息到达率等核心指标的监控统计。实现业务线可以快速接入各种消息服务的目标。
本文将介绍本次实践的具体过程、步骤和方法,供同行借鉴。segmentfault
一.问题的提出后端
1.1 到家业务复杂
58到家是一家作生活服务类O2O业务的创业公司,自成立至今,业务发展迅速。公司自营三大业务:家政、丽人、速运。找保洁、保姆、月嫂可使用家政业务;指甲美容等可使用丽人业务;拉货搬家能够找速运。除了三大自营业务,还有很是重要的开放平台,商家在开放平台上发布服务、用户能够在平台消费服务。开放平台涵盖了你能想到的各类内容,从开锁到换灯泡,从送花到健身。缓存
1.2 消息需求多样
众多业务和不一样场景给消息系统带来很大的挑战。
好比速运业务:用户须要搬家,拿出手机查看司机位置、下单、司机抢单、运送完成后计算路程,这些业务都要求及时高效地传递订单及经纬度信息;
又好比用户资产变化或者优惠券即将到期,系统须要给用户推送提示信息,而用户不会一直开着58到家的应用,咱们须要低成本有效地将提示类信息送达用户;
再好比开放平台里,用户须要跟商家沟通,了解提供的服务或商品的具体状况,系统须要确保用户商家不一样时在线的状况下可以实现交流。安全
1.3 重复开发严重
为了应对业务的快速发展,初创公司都会选择最容易实现的方法和框架。58到家也同样,结果建设了众多的消息系统(如图1),散落在各个业务线。有的用MQTT、有的用HTTP、有的用个推、有的用米推,消息协议不一致,互联互通存在障碍。研发人员须要熟悉多套消息系统,研发效率低下,研发质量很难保证。服务器
图1:混乱的消息系统微信
所以迫切须要建设一个统一的消息系统,对研发人员屏蔽细节,提高开发效率、提升开发质量。网络
二.解决思路session
2.1 统一消息平台
如图2所示,统一消息平台主要包括四大部分:TCP消息系统、推送通道、策略中心、端。
图2:统一消息平台架构
● TCP消息系统
自研的基于TCP协议的消息系统,支持端到端、端到服务器、服务器到端的消息传递,具备性能高、开销小等优势。用于逐步替换五花八门的消息系统。
● 推送通道
强化推送消息能力。整合个推、米推、APNS、微信、短信等消息推送方式。自研的TCP消息系统也是一种消息推送方式。
● 策略中心
人为配置消息投递的策略,能够根据消息可达率或者业务场景须要进行修改。
● 端
主要是指移动端。统一消息平台提供统一的SDK,支持移动端与消息平台服务器的交互。同时,端还包括微信、手机短信等用户经常使用的接收消息的软件。
在这个架构下,业务研发人员只需关注端上的统一SDK和服务器端统一消息交互接口,其余的精力均可以放在处理业务逻辑上。
2.2 TCP消息系统
TCP消息系统的总体结构如图3所示。
图3:TCP消息系统
虚线框描述了TCP消息系统的功能组成。包括接入层(msg-gate)、逻辑层(msg-logic)、ip配置(ipconfig)、路由缓存(redis)四大部分。
接入层
图中的msg-gate模块是接入层,主要功能包括:
● 链接整流:维护与客户端的海量TCP长链接,将外界海量TCP长链接整流为少许与后端msg-logic的TCP长链接。
● 安全信道:创建安全的TCP信道,加密与解密。
● 初步攻防:实施初步的anti-attack策略,限速策略,消息体大小限制。
● 消息投递:将msg-logic投递过来的消息发送给客户端。
逻辑层
msg-logic模块叫逻辑层,主要功能包括:
● 链接验证(能够理解为在消息系统中登陆)。
● APP向app-server发送消息的接口,能够理解为C2S接口。
● app-server向APP发送消息的接口,包括单发和群发。
Redis缓存
缓存业务客户端的链接状态,连到哪个msg-gate,链接状态是否正常。用于向用户推送消息时,提供消息路由。
ipconfig
为客户端提供接入层ip地址,实现负载均衡、业务分组等功能。
2.2.1 Session管理
接入层保持着与海量客户端的TCP长链接,须要实时跟踪这些链接的状态,TCP消息系统将客户端的链接信息保存在接入层的内存中,叫作session。session记录了客户端对应的channel,能够理解为socketid,标记了登陆状态isLogin、登陆时间loginTime,和最后活跃时间lastKeepAliveTime。
session须要状态、信息须要实时维护,维护时机主要包括如下内容:
● 登陆、登出很好理解,须要修改Peer的登陆状态。
● Keepalive,心跳须要修改session的最后活跃时间。
● Logic层请求踢人,来自后端的踢人请求。
● 接入层对某个客户端的限速、客户端发消息速度过快会被认为是攻击行为,强制断开链接。
● socket可能发生异常,非法消息,通不过消息头校验,也须要断开链接。
还有一种状况,客户端链接到服务器后,没有传输任何消息,这种状况有多是网络缘由形成的,也有多是疑似攻击行为。咱们须要定时遍历全部session,发现长时间不活跃的session,将它清除掉。
这么多的读写维护session的场景,归结起来有3类:
● 经过业务属性用户id定位session;
● 经过channel定位session;
● 遍历session。
图4:session结构图
如图4所示,session管理主要包括3个结构:
● 中间的Map是保存Peer的核心数据结构,能够经过channelid检索到session;
●右侧的双向Map保存uid和channelid的映射关系,双向Map能够根据uid检索channelid,也能够根据channelid检索uid,为何用双向结构,后续会提到。
● 左侧的队列保存有链接到接入服务器的全部客户端的channelid,队列采用无锁实现方式,定时任务逐条遍历session,不会产生锁,不影响性能。
定时任务从队列读出channelid1,判断channel1是否正常,若是发现长时间不活跃,认为对应的客户端没有链接到接入服务器。须要将HashMap中的session清除,同时须要将BiMap对应的数据清除,清除BiMap数据的时候,须要根据channelid定位数据,这就是双向Map的用处。
其余的根据uid或者channelid定位并修改数据的请求也不会产生锁,不会对性能构成影响。
有一个点要注意:在新增或删除Peer的时候,须要作好相应的并发控制。
2.2.1 离线消息
离线消息拉取方式如图5。
图5:离线消息逻辑
为了防止一次拉取过多离线消息,拉取方式采用分页拉取的方式。每次拉取10条。
● APP端拉取离线消息,传递三个参数uid=123,msgid=100,size=10,uid表示是谁拉取消息,msgid是App现有消息中最大的消息id,消息id递增,最大的消息id表示App端最后收到的消息数据。若是App端尚未收到过消息,msgid传0。
● 消息服务器收到拉取离线消息请求,msgid=100代表App端已经收到msgid=100以前的数据。将msgid=100以前的离线消息删除。
● 检索msgid=100以后的10条消息,假设msid从101到110。
● 消息服务器将这10条数据返回App端,完成1页离线数据拉取。
● 若是APP端拉取到的离线消息条数不为0,则APP端将msgid=110作为参数再次请求拉取离线消息,直到服务端不返回数据结束离线消息拉取。
2.3 推送通道
58到家的用户不会常常打开App,TCP消息系统极可能没法及时把消息送达用户。相似限时抢购类的活动,必须在某个时间把消息投送给用户,单靠TCP消息系统没法知足需求。
统一消息推送通道,整合TCP、个推、米推、APNS、微信、短信等消息推送方式,尽最大可能确保消息送达用户。统一推送通道结构如图6所示。
图6:统一推送通道结构图
推送通道的核心工做是完成消息到端的推送。不一样的通道,推送时所需参数不彻底一致,推送通道可以获取相应通道所需的参数(如图7所示)。
图7:推送通道及参数
2.4 策略中心
策略中心支持推送策略的人工配置及自动调整。
举两个例子。
第一个例子:假设我是健身爱好者,我用App经过TCP消息系统跟健身房老板沟通价格,结果健身房老板没有打开58到家的App,收不到个人消息,这时系统能够根据策略中心的策略,经过APNS或者个推、米推向健身房老板发出消息提醒;
第二个例子:某人肯定找一个美甲师作美甲,这个信息对美甲师很是重要,策略中心的一个投递策略极可能是push的同时给美甲师发送短信。
策略中心结构如图8。
图8:策略中心结构图
策略配置模块。人为配置消息推送的策略,便于根据消息可达率,或者业务场景须要,修改消息推送策略。好比前面提到的产品来回调整推送通道,就能够经过这个模块进行配置。
策略解析,解析推送消息策略。读取配置的消息发送策略,同时根据手机类型选择推送通道,小米手机用米推、其余android手机用个推、苹果用apns。
若是是多个通道推送,须要确认是并行推送(好比资产变化,同时经过APNS、微信推送)或顺序推送(根据ACK状况、如速运订单,优先经过TCP通道推送,若是规定时间没有收到ACK,则经过个推或米推推送)。
计时调度器,根据推送策略定时探查消息缓存,判断消息是否已送达。依据推送策略进行其余渠道推送或反馈消息是否送达结果。
ACK检测,判断消息是否送达,经过哪一个通道送达。
2.4 端
提供统一的移动端开发SDK来支持整个移动端的消息传输。端上SDK有四个核心要点:保活、消息去重、TCP重连随机延时和电量控制。
● 保活:确保在各类型号手机上TCP连接可用是消息传输是否正常的最关键因素。
● 消息去重:采用了内存队列+SQLite的技术实现,确保在复杂网络环境下,呈现给用户的消息不出现重复状况。
● TCP重连随机延时:避免TCP接入服务器意外挂掉后,大量客户端同时发起对其余服务器的链接请求致使雪崩。
● 控制耗电量是移动开发都须要注意的问题。
三.实践过程
3.1 抽象到家复杂的消息场景
面对复杂的业务,首先须要进行抽象建模,图9展现了消息类型的划分。
图9:消息分类
图中上边一排的手机和笔记本图标在消息系统中被称为端,或者客户端,英文用client表示。中间云的图标是咱们的统一消息平台。下边的服务器图标是业务服务器,英文用sever表示。
58到家各类复杂的消息需求,能够抽象为3类。
● C2S,client to server
例如速运司机手机端,须要将开车轨迹的经纬度近实时的传递到速运后台服务器,服务器才能根据行车轨迹计算车费。
● S2C,server to client
用户有张保洁优惠券快到期了,服务器须要通知用户。这类由服务器主动发起推送的消息。
● C2C,client to client
开放平台业务,用户须要咨询商家问题,将问题发给商家,商家进行回答。
3.2目标明确,按部就班
● 系统须要实现的目标明确。
统一消息平台在规划之初已经考虑到了支持3类消息,同时预见到须要强化消息推送能力以及灵活配置能力。整体结构图包括的四大部分:TCP消息系统、推送通道、策略中心、端,确保可以达成最终目标。
● 按部就班地推进实施。
具体实施中,首先研发TCP消息系统,解决大量消息传输的痛点,并逐步推广到各个业务;接着整合多种推送通道,增长推送策略。实施阶段的每一步,都能让业务线看到成效,消息平台也得以在这个过程当中快速推广。
4、效果评价和总结
在统一消息平台以前各个团队自行研发消息收发功能,重复投入,代码质量差,维护没有延续性。统一后,一次投入,通过持续改进和维护,大大提升研发效率,提高系统质量。具体表如今如下方面。
● 提供移动端SDK,统一端上开发接口。
●服务器端接口,统一服务器侧开发接口。
● 强化消息推送能力,不开App也能送达用户。
● 增长消息推送策略,知足业务需求变化。
11月9-12日,北京国家会议中心,第六届TOP100全球软件案例研究峰会,58到家资深架构师柳忠伟将分享《O2O系统架构演进》
TOP100全球软件案例研究峰会已举办六届,甄选全球软件研发优秀案例,每一年参会者达2000人次。包含产品、团队、架构、运维、大数据、人工智能等多个技术专场,现场学习谷歌、微软、腾讯、阿里、百度等一线互联网企业的最新研发实践。
更多TOP100案例信息及日程请前往[官网]查阅。4天时间集中分享2017年最值得学习的100个研发案例实践。
免费体验票申请入口