乐鱼资讯中心详情

首页 资讯中心 【旅游】从游击队到正规军马蜂窝旅游网的IM系统架构演进之路

【旅游】从游击队到正规军马蜂窝旅游网的IM系统架构演进之路

  本文引用自马蜂窝公众号,由马蜂窝技术团队原创分享。


  今天,越越多的用户被马蜂窝持续积累的笔记攻略嗡嗡等优质的分享内容所吸引,在这里激发了去旅行的热情,同时也拉动了马蜂窝交易的增长。在帮助用户做出旅行决策完成交易的过程,IM 系统起到了重要的作用。


  IM 系统为用户与商家建立了直接沟通的渠道,帮助用户解答购买旅行品的问题,既促成了订单交易,也帮用户打消了疑虑,促成用户旅行愿望的实现。伴随着业的快速发展,几年间,马蜂窝 IM 系统也经历了几次比较重要的架构演化和转型。


  本文将分享马蜂窝旅游网的IM系统架构从零演进的整个过程,希望能给你的IM技术选型和方案确定带启发。


  关于马蜂窝旅游网马蜂窝旅游网是领先的自由行服台,由陈罡和吕刚创立于2006年,从2010年正式开始公司化运营。马蜂窝的景点餐饮酒店等点评信息均自上亿用户的真实分享,每年帮助过亿的旅行者制定自由行方案。


  学交流 即时通讯推送技术开发交流4群9154推荐 移动端IM开发入门文章新手入门一篇就够从零开发移动端IM


  本文同步发布于一套海量在线用户的移动端IM架构设计实践分享含详细图文一套原创分布式即时通讯IM系统理论架构方案从零到卓越京客服即时通讯系统的技术架构演进历程蘑菇街即时通讯IM服器开发之架构选择以微博类应用场景为例,总结海量社交系统的架构设计步骤一套高可用易伸缩高并发的IM群聊单聊架构方案设计实践腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT微信技术总监谈架构微信之道大道至简演讲全文如何解读微信技术总监谈架构微信之道大道至简快速裂变见证微信强大后台架构从0到1的演进历程一


  初期为了支持业快速上线,且当时版本流量较低,对并发要求不高,IM 系统的技术架构主要以简单和可用为目的,实现的功能也很基础。


  IM 1.0 使用 PHP 开发,实现了 IM 基本的用户客服接入消息收发咨询列表管理功能。用户咨询时,会通过均分配的策略分配给客服,记录用户和客服的关联关系。用户客服发送消息时,通过调用消息转发模块,将消息投递到对方的 Redis 阻塞队列里。收消息则通过 HTTP 长连接调用消息轮询模块,有消息时即刻返回,没有消息则阻塞一段时间返回,这里阻塞的目的是降低轮询的间隔。


  消息收发模型如下图所示


  上图模型消息轮询模块的长连接请求是通过 phpfpm 挂载在阻塞队列上,当该请求变多时,如果不能及时释放 phpfpm 进程,会对服器性能消耗较大,负载很高。


  为了解决这个问题,我们对消息轮询模块进行了优化,选用基于 OpenResty 框架,利用 Lua 协程的方式优化 phpfmp 长时间挂载的问题。Lua 协程会通过对 Nginx 转发的请求标记判断是否拦截网络请求,如果拦截,则会将阻塞操作交给 Lua 协程处理,及时释放 phpfmp,缓解对服器性能的消耗。


  优化的处理流程见下图


  伴随着业的快速增长,IM 系统在短期内面临着大量定制需求的增加,开发了许多新的业模块。面对大量的用户咨询,客服的服能力已经招架不住。


  因此,IM 2.0 将重心放在提升业功能体验上,比如


  1在处理用户的咨询时,将从前单一的分配方式演变为采用均权重排队等多种方式;


  2为了提升客服的效率,客服的咨询回复也增加了可选配置,例如自动回复FAQ 等。


  以一个典型的用户咨询场景为例,当用户打开 App 或者网页时,会通过连接层建立长连接,之后在咨询入口发起咨询时,会携带着消息线索初始化消息链路,建立一条可复用可检索的消息线;发送消息时,通过消息服将消息存储到 DB ,同时会根据消息线检索当前咨询是否被分配到客服,调用分配服的目的是为当前咨询完善客服信息;最后将客服信息更新到链路关系。


  这样,一条完整的消息链路就建立完毕,之后用户客服发出的消息通过转发服传输给对方。


  以上处理流程如下图所示


  业量在不断积累,随着模块增加,IM 系统的代码膨胀得很快。由于代码规范没有统一接口职责不够单一模块间耦合较多等种原因,改动一个需求很可能会影响到其它模块,使新需求的开发和维护成本都很高。


  为了解决这种局面,IM 系统必须要进行架构升级,首要任就是服的拆分。目前,经过拆分后的 IM 系统整体分为 4 块大的服,包括客服服用户服IM 服数据服。


  如下图所示


  如上图,我们进行一下解读


  1客服服围绕提升客服效率和用户体验提供多种方式,如提供群组管理成员管理质检服等提升客服团队的运营和管理水;通过分配服转接服使用户的接待效率更灵活高效;支持自动回复FAQ知识库服等提升客服咨询的回复效率等;


  2用户服分析用户行为,为用户做兴趣推荐及用户画像,以及统计用户对马蜂窝商家客服的满意度;


  3IM 服支持单聊和群聊模式,提供实时消息通知离线消息推送历史消息漫游联系人文件上传与存储消息内容风控检测等;


  4数据服通过采集用户咨询的源入口是否咨询下单是否有客服接待用户咨询以及客服回复的时间信息等,定义数据指标,通过数据分析进行离线数据运算,最终对外提供数据统计信息。主要的指标信息有 30 秒1 分钟回复率咨询人数无应答次数均应答时间咨询销售额咨询转化率推荐转化率分时接待压力值班情况服评分等。


  现有的 IM 系统 ,用户咨询时一个完整的用户状态流转如下图所示


  如上图所示


  1用户点击咨询按钮触发事件,此时用户状态进入初始态;


  2发送消息时,系统更改用户状态为待分配,通过调用分配服分配了对应的客服后,用户状态更改为已分配未解决;


  3当客服解决了用户或者客服回复后用户长时间未说话,触发系统自动解决的操作,此时用户状态更改为已解决,一个咨询流程结束。


  在服拆分的过程,我们需要考虑特定服的通用性可用性和降级策略,同时需要尽可能地降低服间的依赖,避免由于单一服不可用导致整体服瘫痪的风险。


  在这期间,公司其它业线对 IM 服的使用需求也越越多,使用频次和量级也开始加大。初期阶段的 IM 服当连接量大时,只能通过修改代码实现水扩容;新业接入时,还需要在业服器上配置 Openresty 环境及 Lua 协程代码,业接入非常不便,IM 服的通用性也很差。


  考虑到以上问题,我们对 IM 服进行了全面重构,目标是将 IM 服抽取成独立的模块,不依赖其它业,对外提供统一的集成和调用方式。考虑到 IM 服对并发处理高和损耗低的要求,选择了 Go 语言开发此模块。


  新的 IM 服设计如下图


  其,比较重要的 Proxy 层和 Exchange 层提供了以下服


  1路由规则例如 iphash轮询最连接数等,通过规则将客户端散列到不同的 ChannelManager 实例上;


  2对客户端接入的管理接入后的连接信息会同步到 DispatchTable 模块,方便 Dispatcher 进行检索;


  3ChannelManager 与客户端间的通信协议包括客户端请求建立连接断线重连主动断开心跳通知收发消息消息的 QoS 等;


  4对外提供单发群发消息的 REST 接口这里需要根据场景决定是否使用,例如用户咨询客服的场景就需要通过这个接口下发消息。


  针对上述第4点,主要原因在以下 3 点


  1发消息时会有创建消息线分配管家等逻辑,这些逻辑目前是 PHP 实现,IM 服需要知道 PHP 的执行结果,一种方式是使用 Go 重新实现,另外一种方式是通过 REST 接口调用 PHP 返回,这样会带 IM 服和 PHP 业过多的网络交互,影响性能;


  2转发消息时,ChannelManager 多个实例间需要互相通信,例如 ChannelManager1 上的用户 A 给 ChannelManager2 上的客服 B 发消息,如果实例间无通信机制,消息无法转发。当要再扩展 ChannelManager 实例时,新增实例需要和其它已存在实例分别建立通信,增加了系统扩展的复杂度;


  3如果客户端不支持 WebSocket 协议,作为降级方案的 HTTP 长连接轮循只能用收消息,发消息需要通过短连接处理。其它场景不需要消息转发,只用给 ChannelManager 传输消息的场景,可通过 WebSocket 直接发送。


  初始化消息线及分配客服过程由 PHP 业完成。需要消息转发时,PHP 业调用 Dispatcher 服的发消息接口,Dispatcher 服通过享的 Dispatcher Table 数据,检索出接收者所在的 ChannelManager 实例,将消息通过 RPC 的方式发送到实例上,ChannelManager 通过 WebSocket 将消息推送给客户端。


  IM 服调用流程如下图所示


  当连接数超过当前 ChannelManager 集群承载的上限时,只需扩展 ChannelManager 实例,由 ETCD 动态的通知到监听侧,从而做到滑扩容。目前浏览器版本的 JSSDK 已经开发完毕,其它业线通过接入文档,就能方便的集成 IM 服。


  在 Exchange 层的设计,有 3 个问题需要考。


  1多端消息同步


  现在客户端有 PC 浏览器Windows 客户端H5iOSAndroid,如果一个用户登录了多端,当有消息过时,需要查找出这个用户的所有连接,当用户的某个端断线后,需要定位到这一个连接。


  上面提到过,连接信息都是存储在 DispatcherTable 模块,因此 DispatcherTable 模块要能根据用户信息快速检索出连接信息。DispatcherTable 模块的设计用到了 Redis 的 Hash 存储,当客户端与 ChannelManager 建立连接后,需要同步的元数据有 uid用户信息uniquefield唯一值,一个连接对应的唯一值wsid连接标示符clientip客户端 ipserverip服端 ipchannel渠道,对应的结构大致如下


  这样通过 keyuid 能找到一个用户多个端的连接,通过 keyfield 能定位到一条连接。连接信息的默认过期时间为 2 时,目的是避免因客户端连接异常断导致服端没有捕获到,从而在 DispatcherTable 存储了一些过期数据。


  2用户在线状态同步


  比如一个用户先后和 4 个客服咨询过,那么这个用户会出现在 4 个客服的咨询列表里。当用户上线时,要保证 4 个客服看到用户都是在线状态。


  要做到这一点有两种方案


  一种是客服通过轮询获取用户的状态,但这样当用户在线状态没有变化时,会发起很多无效的请求;


  另外一种是用户上线时,给客服推送上线通知,这样会造成消息扩散,每一个咨询过的客服都需要扩散通知。


  我们最终采取的是第二种方式,在推送的过程,只给在线的客服推送用户状态。


  3消息的不丢失,不重复


  为了避免消息丢失,对于采用长连接轮询方式的我们会在发起请求时,带上客户端已读消息的 ID,由服端计算出差值消息然后返回;使用 WebSocket 方式的,服端会在推送给客户端消息后,等待客户端的 ACK,如果客户端没有 ACK,服端会尝试多次推送。


  这时就需要客户端根据消息 ID 做消息重复的处理,避免客户端可能已收到消息,但是由于其它原因导致 ACK 确认失败,触发重试,导致消息重复。


  上文提到过 IM 服需要支持多终端,同时在角色上又分为用户端和商家端,为了能让通知消息在输出时根据域名终端角色动态输出差异化的内容,引入了 DDD 领域驱动设计的建模方法对消息进行处理。


  处理过程如下图所示


  伴随着马蜂窝「内容交易」模式的不断深化,IM 系统架构也经历着演化和升级的不同阶段,从初期粗旷无序的模式走向统一管理,逐渐规范形成规模。


  我们取得了一些进步,当然,还有更长的路要走。未,结合公司业的发展脚步和团队的技术能力,我们将不断进行 IM 系统的优化。


  目前我们正在计划将消息轮询模块的服端代码用 Go 替换,使其不再依赖 PHP 及 OpenResty 环境,实现更好地解耦;另外,我们将基于 TensorFlow 实现向智慧客服的探索,通过训练数据模型分析数据,进一步提升人工客服的解决效率,提升用户体验,更好地为业赋能。1 有关IM架构设计的文章浅谈IM系统的架构设计简述移动端IM开发的那些坑架构设计通信协议和客户端一套海量在线用户的移动端IM架构设计实践分享含详细图文一套原创分布式即时通讯IM系统理论架构方案从零到卓越京客服即时通讯系统的技术架构演进历程蘑菇街即时通讯IM服器开发之架构选择腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT微信后台基于时间序的海量数据冷热分级架构设计实践微信技术总监谈架构微信之道大道至简演讲全文如何解读微信技术总监谈架构微信之道大道至简快速裂变见证微信强大后台架构从0到1的演进历程一17年的实践腾讯海量品的技术方法论移动端IM大规模群消息的推送如何保证效率实时性?现代IM系统聊天消息的同步和存储方案探讨IM开发基础知识补课二如何设计大量图片文件的服端存储架构?IM开发基础知识补课三快速理解服端数据库读写分离原理及实践建议IM开发基础知识补课四正确理解HTTP短连接的CookieSession和TokenWhatsApp技术实践分享32人工程团队创造的技术神话微信朋友圈千亿访问量背后的技术挑战和实践总结王者荣耀2亿用户量的背后品定位技术架构网络方案等IM系统的MQ消息间件选型Kafka还是RabbitMQ?腾讯资深架构师干货总结一文读懂大型分布式系统设计的方方面面以微博类应用场景为例,总结海量社交系统的架构设计步骤快速理解高性能HTTP服端的负载均衡技术原理子弹短信光鲜的背后网易云信首席架构师分享亿级IM台的技术实践知乎技术分享从单机到2000万QPS并发的Redis高性能缓存实践之路IM开发基础知识补课五通俗易懂,正确理解并用好MQ消息队列微信技术分享微信的海量IM聊天消息序列号生成实践算法原理篇微信技术分享微信的海量IM聊天消息序列号生成实践容灾方案篇新手入门零基础理解大型分布式架构的演进历史技术原理最佳实践一套高可用易伸缩高并发的IM群聊单聊架构方案设计实践阿里技术分享深度揭秘阿里数据库技术方案的10年变迁史阿里技术分享阿里自研金融级数据库OceanBase的艰辛成长之路社交软件红包技术解密一全面解密QQ红包技术方案架构技术实现等社交软件红包技术解密二解密微信摇一摇红包从0到1的技术演进社交软件红包技术解密三微信摇一摇红包雨背后的技术细节社交软件红包技术解密四微信红包系统是如何应对高并发的社交软件红包技术解密五微信红包系统是如何实现高可用性的社交软件红包技术解密六微信红包系统的存储层架构演进实践社交软件红包技术解密七支付宝红包的海量高并发技术实践社交软件红包技术解密八全面解密微博红包技术方案社交软件红包技术解密九谈谈手Q红包的功能逻辑容灾运维架构等即时通讯新手入门一文读懂什么是Nginx?它能否实现IM的负载均衡?即时通讯新手入门快速理解RPC技术基本概念原理和用途多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了从游击队到正规军马蜂窝旅游网的IM系统架构演进之路 更多同类文章 2 更多其它架构设计相关文章腾讯资深架构师干货总结一文读懂大型分布式系统设计的方方面面快速理解高性能HTTP服端的负载均衡技术原理子弹短信光鲜的背后网易云信首席架构师分享亿级IM台的技术实践知乎技术分享从单机到2000万QPS并发的Redis高性能缓存实践之路新手入门零基础理解大型分布式架构的演进历史技术原理最佳实践阿里技术分享深度揭秘阿里数据库技术方案的10年变迁史阿里技术分享阿里自研金融级数据库OceanBase的艰辛成长之路达达O2O后台架构演进实践从0到4000高并发请求背后的努力优秀后端架构师必会知识史上最全MySQL大表优化方案总结米技术分享解密米抢购系统千万高并发架构的演进和实践一篇读懂分布式架构下的负载均衡技术分类原理算法常见方案等通俗易懂如何设计能支撑百万并发的数据库架构?多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了从新手到架构师,一篇就够从100到1000万高并发的架构演进之路更多同类文章


  本文同步发布于

上一篇:【奖励】国家旅游景区质量评定标准 下一篇:【研究】寂寞女人:我因失恋放纵自己和男上司寻欢