本文由百度技术团队分享,引用自百度Geek说,原题“千万级高性能长连接Go服务架构实践”,为了阅读便利,本文进行了排版优化等。
移动互联网时代,长连接服务成为了提升应用实时性和互动性的基础服务。
本文将介绍百度基于golang实现的统一长连接服务,从统一长连接功能实现和性能优化等角度,描述了其在设计、开发和维护过程中面临的问题和挑战,并重点介绍了解决相关问题和挑战的方案和实践经验。
* 关联文章:《百度统一socket长连接组件从0到1的技术实践》、《淘宝移动端统一网络库的架构演进和弱网优化技术实践》,建议可一并阅读。
本文是专题系列文章的第10篇,总目录如下:
移动互联网时代,用户对服务的实时性、互动性有了更高的要求,因此能够极大提升服务实时性、互动性的长连接服务,成为了移动互联网应用的刚需。
长连接,顾名思义,是应用存活期间和服务端一直保持的网络数据通道,能够支持全双工上下行数据传输。其和请求响应模式的短连接服务最大的差异,在于它可以提供服务端主动给用户实时推送数据的能力。
不过:长连接作为基础服务,要做到低延时、高并发、高稳定性,对服务的开发和维护有较高的要求。
如果每个业务都维护自身的长连接服务,一方面有较大的重复开发和维护成本,另一方面长连接服务功能迭代、服务稳定性、专业性很难跟上业务诉求。
因此:统一长连接项目通过打造完整的端到服务端的长连接服务系统,给业务提供一套安全、高并发、低延迟、易接入、低成本的长连接服务能力。
统一长连接服务主要目的是给业务提供一套安全、高并发、低延迟、易接入、低成本的长连接服务系统。
主要愿景包括:
统一长连接服务与接入业务的边界关系是长连接业务架构设计的首要问题。
与业务专用的长连接服务不同,统一长连接服务要实现的目标是多业务方共用一条长连接。因此在设计时既要考虑到不同业务方、不同业务场景对长连接服务的诉求,同时,也要明确长连接服务的服务边界,避免过多介入业务逻辑,限制后续长连接服务的迭代和发展。
通常,业务对长连接服务的主要诉求包括三个方面:
数据上下行过程中,需要能够支持不同业务数据协议上的差异。
此外,根据不同的业务类型,对下行数据推送模式、推送量级有着不同的要求。
以长连接服务常见的消息、直播、PUSH业务方为例:
综上,统一长连接服务,要实现的服务能力如下:
统一长连接服务因为要给百度体系APP提供长连接能力的服务,要做到高并发、高可用、高稳定性。具体到长连接服务本身,其主要包括以下几个方面。
1 )建联qps、延时、成功率、连接维持:
长连接在app打开同时需要完成建立、并在app存活期间保持连接存活。
因此,长连接服务要支持万级别的建联qps和千万级别在在线连接维持,并支持横向扩容。
此外,连接建立作为长连接服务的基础,建联的成功率和延时重中之重。
2) 上行请求qps、延时、成功率:
连接建立完成后,需要将业务请求转发给业务侧,这个依赖于用户规模和请求频率,一般至少要支持到几十乃至百万级别,并可以支持横向扩容。
3) 下行请求qps,延时、成功率:
下行请求根据业务场景的不同,分为批量单播和组播,且不同业务对应请求qps要求不一样,一般批量单播需要支持到百万级ups,组播要支持到千万级ups,且支持横向扩容。
下面简单介绍下,为了完成上述目标,统一长连接服务所做的一些方案设计和实践经验。
统一长连接服务整体架构如上图所示,整个服务包括四个部分组成:
统一长连接SDK归属于客户端,控制层、接入层、路由层归属于服务端。每个组成部分在整体系统中的扮演的角色和功能如下。
1)统一长连接SDK:
统一长连接SDK归属于客户端,负责连通业务SDK和长连接服务端。
其主要职责包括:
2)控制层:
长连接建联之前的一个前置服务,主要用来验证接入设备的合法性和决定设备的接入策略。
其主要职责包括:
3)接入层:
接入层作为统一长连接核心服务,承担了连接介入,连接维护、请求转发、下行推送等主要功能,是长连接核心逻辑和主要压力的承担者。
其主要职责包括:
4)路由层:
负责构建设备标识和连接标识的映射关系,在业务指定设备标识进行推送的时候,提供设备标识查询连接标识的能力。
长连接生命周期内主要有四个核心流程:
具体是:
长连接由于连接生命周期较长,在周期内连接可能会因为各种网络情况、数据传输异常导致连接发生状态变化。同时也为了防止恶意设备模拟正常的客户端对长连接服务进行攻击,需要有一套机制能够让服务端验证长连接状态是合法有效的,同时对于处于异常状态的连接,能够触发其重连并快速恢复。
统一长连接通过引入状态机的方式构建了该机制。即明确定义长连接在生命周期内可能存在的各种状态、每种状态可以触发的操作,以及状态间相关转移的场景等。
比如:
引入这种的机制好处是:简化长连接状态流转的开发逻辑,长连接生命周期里面每种状态以及状态间转移关系,触发的操作都是明确定义的,避免了线上因为各种未知原因导致连接处于不可知状态,导致长连接异常甚至无法恢复。
统一长连接一个主要愿景是支持多业务复用一条长连接,即同一条连接上,能够兼容不同业务的数据协议,且在上下行业务数据传输时候能够区分不同业务的请求转发给指定业务。
这个主要是通过长连接私有数据协议来支持,长连接数据协议是长连接SDK和长连接接入层交互使用的数据协议,采用的二进制私有协议。
协议主要分为三部分:
通过解析协议公参里面的业务标识,长连接SDK和长连接接入层能够确认业务数据对应的业务方,并根据业务标识将请求做对应转发。业务的请求数据放在业务数据部分,协议有业务侧指定,长连接服务只做转发,不介入业务具体细节。
接入层根据业务标识确认业务数据来源后,会通过RPC请求将业务数据转发给业务server,然后将业务Server的返回写回给端上。
上行请求转发除了会转发业务上行请求数据外,也会讲长连接公参数据一并带给业务Server。
除此外, 如果业务有诉求,在连接状态发生变化,比如连接断开等,长连接接入层也可以将该信号实时通知业务Server,以便业务Server 根据状态信号变化做进一步操作。
下行推送,根据业务需要,主要分为两类,单播推送和组播推送,以下对比了单播推送和组播的差异。
1)单播推送:
服务端主动推送时候,比如一个业务要给某个设备推消息,由于接入层是多实例部署的,首先需要知道这个设备与哪个长连接实例相连。其次需要知道这个设备与这个实例内哪条长连接相关联,那么这个实例地址和对应的长连接一期就构成了这个设备当时的连接信息,给某个用户推消息。本质上就是通过用户设备找到这个设备对应的连接信息的过程,也就是设备ID -> 连接信息(实例ip+连接ID)映射关系的过程,路由层负责构建和维护设备和连接信息的一个模块。
这个对业务的主要成本是确定需要推送用户的设备ID:
2)组播推送:
此外,由于下行推送的时候,在某些场景下,会存在需要给大批量用户推送相同消息的场景,比如直播(聊天室)。
路由层会维护一个连接组信息,连接组ID->组内连接信息的映射。连接组的创建、连接加入和退出连接组,主要由对应的业务场景来控制,路由层只提供对应的接口能力,在连接组建立好后,向对应的连接组推消息,长连接服务会自动将消息拆分发给组内每一条连接。
使用连接组,业务需要做的事情:
长连接底层强依赖 tcp&tls、quic、websocket 等通讯协议。
一方面,不同的场景,可能会使用到不同的通讯协议,比如NA端一般倾向于tcp和tls,小程序和web端倾向于websocket。一方面,现有协议的迭代和新协议的出现,也会给长连接的性能和通道质量带来优化。因此,为了适配不同场景下的通讯协议,同时也为了能够快速探索通讯协议迭代对长连接服务质量的提升。统一长连接做了对不同通讯协议的兼容。
即为了支持多种通讯协议,接入层对连接概念做了划分,将连接分为了两层,connection 和 session。
1)connection层: 和具体的通讯层协议交互,封装不同通讯协议的接口和逻辑差异,比如tls、websocket、quic 等等。同时给上层session 层提供统一的数据接口,包括连接建立、数据读取、写入、连接信息获取等。新协议的接入,只需要在connection做相应适配,不影响session层的长连接业务逻辑。
2)session层:长连接业务级别连接概念,维护长连接业务连接状态,维护连接状态机,支持请求转发、下行推送等业务逻辑,本身依赖connection层提供的数据接口和实际的通讯协议进行交互。但是不感知具体的通讯协议差异。
同时,端上在建联时,控制层会根据客户端当前的情况,比如端类型(NA、小程序、Web)、当前的网络类型(4G、5G)、设备质量情况等,下发不同的建联协议和对应的接入点,端上根据下发的建议协议和接入点,结合端上自身情况,选用合适的接入协议和接入点进行建联。
这样设计的主要优势在于:
连接建立完成后,接入层主要面临着三个压力来源:
按照单个实例需要支持百万连接来考虑:
综上:单个实例如果要支持百万连接,通常需要支持3-4w qps 上行,5-10w 的ups下行。
统一长连接层接入层服务是使用golang来实现的,按照golang 常用的网络模型,一条连接会有对应两个goroutine,一个用来读数据和处理数据,一个用来写数据。
这个模型存在两个问题:
统一长连接通过引入请求转发组和下行任务组来解决上述两个问题。
1)请求转发组:
接入层在实例启动的时候,会根据支持的业务上行qps,初始化对应的请求转发组,连接在读取完请求数据后,会根据请求属于那个业务将请求转给对应的请求转发组,由请求转发组内的goroutine完成后续请求。
不同业务的请求转发组是不同的goroutine池,避免业务间相互影响。连接本身的读goroutine只是负责读取数据,转发请求给请求转发组,避免请求处理存在排队的情况。
2)下行任务组:
下行数据写入的时候,会有一个公共的任务组,每个连接在任务组中会有一个固定的处理协程,有数据下行的时候会讲写入数据的任务发到下行任务组。
这个主要目的是,由于单个实例需要维护大量的在线长连接,每个长连接通常需要两个协程,一个读协程、一个写协程,如果单实例支持50w连接,也就会单实例存在百万协程,这个对服务gc和资源都会造成一定的压力。
同时,一个实例维持的所有连接通常不会同时都下行写消息,因而,可以通过维护一个下行任务组,任务组里面维护动态数量的协程数,每个连接绑定任务组里面一个协程,有下行任务时将任务发送到任务组里面,有任务组里面的协程负责将任务下行,减少实例服务压力。
统一长连接服务部署上,主要做了以下几点。
1)长连接在国内三大运营商的华东、华北、华南地域均部署了接入点;部分业务需要支持海外业务,增加了香港机房的独立接入点入口。
2)根据业务量级和重要性,分大小集群部署,每个集群对应不同的域名,不同业务通过控制层下发域名分流到对应集群。主要目的针对于重点业务,提供独立部署的能力;对于次级业务,提供混部服务,降低成本和提高资源利用率。
3)针对接入层每个实例,将实例的配置和能够支持的连接数,控制在10w-20w量级,避免单个实例支持连接数过多,实例发生服务抖动时,对整个集群服务产生较大影响;单个实例支持的连接数有限制,减少实例内常态维护的goroutine数,减轻gc压力。
业务接入统一长连接通常涉及以下几个步骤:
目前统一长连接已支持了千万级长连接并发在线,支持过百万级ups 批量单播和组播消息下行,拥有实时横向扩容能力。
服务第一次完成上线至今,长连接服务稳定,经历过多次重大活动高并发推送的考验,没有出现过任何影响其他业务服务质量的case。
总的来说,统一长连接项目从立项、开发到最后上线运维,服务质量整体上是符合预期的。
从统一长连接项目整个项目流程,主要总结有以下三点经验:
统一长连接服务经历数次迭代后,目前基本功能已经趋于稳定,将进一步对长连接服务进行改善和优化。
主要集中在以下几个方向:(本文已同步发布于:http://www.52im.net/thread-4623-1-1.html)
[1] 百度统一socket长连接组件从0到1的技术实践
[2] 淘宝移动端统一网络库的架构演进和弱网优化技术实践
[3] 直播系统聊天技术(二):阿里电商IM消息平台,在群聊、直播场景下的技术实践
[4] 长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践
[5] 长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路
[6] 长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践
[7] 长连接网关技术专题(七):小米小爱单机120万长连接接入层的架构演进
[8] 不为人知的网络编程(十五):深入操作系统,一文搞懂Socket到底是什么
[9] 零基础IM开发入门(一):什么是IM系统?
[10] WebSocket从入门到精通,半小时就够!
[11] 网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议
《百度APP移动端网络深度优化实践分享(一):DNS优化篇》
《百度APP移动端网络深度优化实践分享(二):网络连接优化篇》
《百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇》
《全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等》
《深入了解百度开源的分布式RPC框架brpc的方方面面》
《直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践》
《IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现》
《百度统一socket长连接组件从0到1的技术实践》
《百度网盘千万节点的P2P架构设计(PPT) [附件下载]》
《即时通讯音视频开发(二十):一文读懂视频的颜色模型转换和色域转换》
《揭秘百度IM消息中台的全量用户消息推送技术改造实践》
《百度基于金融场景构建高实时、高可用的分布式数据传输系统的技术实践》
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。