融云QCon上海站深度解析:超大规模即时通讯系统性能优化探索及实践
10月17日至19日,QCon全球软件开发大会上海站如约而至。来自 Google、Facebook、LinkedIn、Twitter、腾讯、百度、青云、融云等国内外知名企业的百余位技术专家受邀参会,针对人工智能、编程语言、业务安全、软件性能等热点话题进行深入探讨,并为与会嘉宾分享各自领域的技术干货。
会议首日,融云展位便被众多参会嘉宾围住,分别就融云的IM技术、产品方案及业务合作方式等各内容进行全面的沟通交流,融云的公有云客户汽车之家、沪江网校及私有云客户陆金所等知名企业的技术人员也来到展位交流,纷纷对融云的技术产品及服务表达了高度的肯定。
18日上午,融云首席架构师李淼为大家分享了《超大规模即时通讯系统性能优化探索及实践》主题演讲,就庞大复杂的系统性能问题该如何定位、分析以及工具排查;高并发系统的技术要点、难点、重点把控及措施、技巧;特定场景下系统性能问题优化可行性解决方案等内容进入深度解析。虽然临近午饭时间,但大量的技术干货及精彩的案例分享,让现场一度爆满,很多嘉宾即使站着也一直坚持听完整场演讲;即便会议结束,还有很多人与李淼进一步交流。
以下为演讲实录摘要,希望在适用场景下,对开发者有所脾益。
各位好,临近中午了,感谢还有这么多同学和我一起分享。今天的主题是超大规模即时通讯系统性能优化探索及实践,介绍即时通讯模式下性能优化如何完成。通过今天介绍的模型,大家如果有所得的话可以在系统当中做一些应用实践。
性能问题定位及关注点
首先说性能问题的关注点,对于程序首先最直观的关注点就是程序的响应时长。前提是响应包括你的应答必须是正确的,如果说性能优化完成之后结果不正确,那可以说整个优化失败。
除了程序响应时长以外我们还会关注系统、数据存储以及数据通讯。系统有一些直观指标可以衡量系统的健康性和系统性能。先说CPU,我们主要关注CPU的负载及使用率;接下来是内存,内存主要关注正常的内存利用率,是否使用了虚拟内存,以及内存碎片问题;I/O问题则关注磁盘和网络I/O问题,I/O是整个系统优化过程中特别需要关注的点,I/O如果做的好,对于整个平台的性能提升帮助是最大的,有可能会比前面的CPU和内存还要大。
数据存储方面,在即时通讯保证消息可靠性的情况下,优先进行消息存储,通过这种方式保证消息不丢失、不乱序、不重复。对于数据存储而言,其实和I/O有点类似,对于一般的业务来讲,如果数据存储优化的好,平台优化方面就完成了60%左右的工作。
一般做系统时都会遇到网络相关问题,这就会涉及到网络通讯问题,怎么想办法降低你的数据传输量,或者说降低你和网络之间的交互次数,也是数据通讯里面需要完成的一个优化。
下面通过三个阶段介绍一下融云关于性能问题的定位。第一个阶段融云刚刚成立,那个时候性能问题的定位主要是通过系统监控,配合着系统日志以及诊断工具,主要监控服务器里面的CPU、内存及I/O指标。
对于监控来讲,我们有一个类似业务监控系统,定时对每个节点进行相关性的单元测试,以此来衡量当前服务的健康状况,以及每个系统的响应速度。当线上出现了系统告警时,配合日志来查看业务是否正常。
第二个阶段,我们尝试过用一些开源的APM工具。在整个系统当中通讯模型是基于Actor模型做的,所以没办法整个构建服务监控网络,只能看一些相关数据。但在座各位如果开发系统,用APM是一个非常好的工具,可以帮助你进行服务治理,系统监控相关的工作,同时APM也有很多商业解决方案。
第三个阶段,我们在对APM调研以及试用出现问题之后,只能想办法自研Monitor监控系统,我们会记录每个信令的调用时间和调用链路,后台有一个数据分析平台,我们查看一些信令前一天和今天的比值,看是不是有幅度变化;同时我们也会配合业务数据量观测数据。一旦某个信令出现异常,我们就会进行线上的服务排查。
实际上对于性能问题的定位来讲,第一个阶段是最有效的,后面的手段都是辅助研发人员对于线上问题的定位,这些都是相辅相成的:你判断问题、定位问题需要工具,工具也可以提高你判断问题、定位问题的速度。
高并发系统技术要点
对于高并发系统来讲,其实技术要点很多,我罗列了四条:异步通讯、缓存策略、数据结构及算法、数据存储。对于性能优化来讲,这四点仅仅是一部分,但如果把这四点做好,平台就能得到一个很大的提升。
首先是异步通讯,对于现在的分布式系统来讲,都需要对服务进行拆分,服务拆分以后我们需要通过一种方式将服务串联起来,现在有很多开源的解决方案或框架,但是对于RPC来讲,一般都是同步调用,有点类似于访问数据库,当前的工作线程需要等待调用端反馈结果。
如果说某个服务的响应时长十毫秒,对于调用端来讲就需要等待十毫秒,为了解决这个问题,现在很多RPC都支持异步RPC的方式,通过回调的方式解决同步RPC工作线程占用以及等待的问题。
最后一个是Actor模型,Actor模型实际上在整个软件系统上是一个属于多线程数据协调的模型。所有的请求以及返回结果会以消息的方式进行传递,融云也是使用了Actor模式作为服务间调用。
第二个是缓存策略,我们对于数据分为四层:首先是原始数据,这个数据是保存在数据库里面的;第二个是分布式缓存,对于很多无状态的服务而言,性能优化大部分依赖于分布式缓存来完成;第三个为了对数据访问进行加速,可能会使用一些本地进程内缓存,由于没有网络访问,同时直接的内存访问速度更快,所以本地缓存策略也会作为服务加速的方式;最后就是客户端缓存了,现在无论是App开发,PC客户开发都可以使用用户侧的数据存储,Web上的H5也可以使用类似local storage解决方案,但是一旦使用了客户端存储,我们就需要设计一个健壮的数据同步模型。刨除客户端缓存的问题,为了尽可能达到使热数据离用户近一些这个目的,我们就需要想尽一切办法提高缓存的命中率。
第三个是数据结构及算法,适合场景的高效数据结构,首先我们要明确一个事情,适合的场景一定要对整个系统以及业务有充分的了解,根据这个方式再选择合适的数据结构。有的时候我们需要在时间复杂度和空间复杂度之间做权衡,什么时候拿空间换时间,什么时候拿时间换空间。另外就是算法,在开发过程当中,一定要明确算法的时间复杂度。由于系统里的需求,你需要提高算法复杂度,这个时候开发人员要和产品人员进行协调沟通。算法复杂度太高时,就要想办法优化业务,甚至说优化场景。
第四数据存储,我们依然要提场景的问题。对于一般系统开发来讲,一个关系型数据库基本上就可以满足业务需求开发了,但实际上如果仅仅通过关系型数据库来做的话,即使能满足业务需求也不一定可以满足性能需求。所以说要熟知你的业务场景,根据业务场景选择合适的数据存储。除此之外,还需要了解这些存储的原理。
性能优化案例
下面分享一下融云做的优化案例,融云系统上线过程当中没有出现太多的性能问题,实际上我们更多处理的是线上的BUG,或者说由于一些低级失误产生的故障。
首先第一个案例,字典树在我们优化之后变成了双数组字典树,场景主要应用于敏感词过滤。当时我们字典树的实现都是以哈希多叉树来做的,有几个考虑:第一,敏感词添加过程当中不需要字典树重建,另外算法复杂度很低。有次通过监控,我们发了线上用于审核的系统出现了一些性能问题,排查后发现有大量用户录入了很多业务上的关键敏感词,这时我们将哈希树调整为了双数组字典树,场景我们也做了一些优化,敏感词让用户进行批量添加,防止每次都会重构。另外就是延迟,我们降低了字典树重构的时间。最后,对于审核服务来讲,优化效果直接将CPU的使用率降低了30%。
另外一个就是跳表,转换成环形队列,场景是做一些消息存储。消息有一个时间递增的特性,每个消息都会有一个时间递增的方式,用于跳表方式来讲复杂度很低,同时可以进行定向扫描,但是由于我们需要做内存保护,要对跳表进行流量控制,插入的过程当中需要对老数据进行淘汰,这时就需要一个特别大的锁把内存锁住,保证线程安全和防止内存溢出。但由于业务量不断增大,我们换了一个思路,使用环形队列,主要底线实现都是以数组的方式组织,同时改变之前对于消息的定位模式。之前是通过一个用户请求的时间点开始往后获取最新数据,改变模式之后我们通过最新的数据往前进行迭代,查到时间点为止,通过这样的方式整个降低了占用时间,同时针对这块业务吞吐量大概提高了百分之百。
性能优化案例内存优化篇。这个场景对于key缩短问题,对于系统当中的用户ID本身来讲长度不可控。我们通过一个哈希算法转变进制,变成64进制,这样对于超过22个字节的数据进行压缩,最终优化效果把内存的利用率降低了大概10%。
第二个内存优化主要是LRU缓存优化,如果有大量冷数据访问到系统中之后,会把热数据冲掉,这对于系统的吞吐量有很大影响。我们优化的方式是做了一个二级LRU缓存,将冷热数据按照配比进行隔离,冷数据40%,热数据60%,这样系统里热数据被淘汰的问题便得以缓解了。
性能优化案例。数据状态的延迟写入,这个场景中消息里会记录每个用户的状态。如果用户收了一千条消息,数据就要被写入一千次,我们通过另外一种模式,消息状态数据一直是在本地内存当中进行写入,待多次写入直到数据不活跃后,我们才将数据写入真实的存储里。通过这种优化,将之前的多次数据写入变成了一次数据写入。
之前监控数据每天有几千亿次需要存储和写入,通过添加缓存区,让将监控数据传输量降低了两个数量级。
数据存储。首先对于消息来讲,他的写入和读取场景是比较特殊,通过自研的存储引擎,将存储的设备降低了一半的数据量,同时保证了整个系统的响应速度。另外,调整了数据库的业务引擎,对于业务数据占用磁盘比较高的问题,优化之后的结果大概只有之前的30%左右,即存储降低了70%。
系统设计把控
系统设计把控是一个总结性的内容,对于性能优化来讲首先应该关注的是系统设计,需要充分理解你的需求以及业务场景,根据业务场景来设计你的整个系统,系统设计完成之后,我们要开始进行架构设计,现在很多人做架构分享,例如现在比较火的微服务。但是这些架构设计大家不要拿过来直接引用,需要充分的消化,通过架构设计带入系统设计,进行整个架构的演进和迭代。
另外,技术选型需要充分考虑团队对技术的接受能力,同时一定要对每个你所选东西的原理有充分认识,这样的话才能做出一个比较好的选择。
最后是程序实现,是在开发过程当中要不停进行迭代、改进和分享。技术没有好坏之分,只有适合你的场景才是最好的。谢谢大家!
原文链接:赛迪网 http://www.ccidnet.com/2017/1019/10322713.shtml