写在前面
疫情期间,随着返岗复工人员大幅流动,疫情扩散传播风险巨大,疫情防控也面临新的严峻挑战。为了更好地统计流动人口信息,云南省公安厅面向社会公共场所推出“云南抗疫情”小程序,对公共场所的流动人口进行信息登记。具体措施是:每个场所都事先申请场所进出二维码,人员在进入某公共场所时,扫描“进场”二维码进入场所;离开时则需扫描“离场”二维码离开场所。二维码里面有单位及相关负责人的关联信息,人员进出公共场所都需要扫码。
上线不到一个月,截至 3 月 12 日,“云南抗疫情”扫码小程序公共场所累计注册 103 万余个,扫码登记 3.65 亿人次,扫码用户数达 1755 万余人。各个公共场所登记生成二维码的请求量超过 10w/min,扫码登记请求量超过 80W/min。云开发服务的高效稳定将直接影响广大人民群众进出各个场所的效率。
那么,如何应对短时间的流量洪峰,确保小程序功能的正常使用?如何优化小程序响应速度,在高并发下仍旧保持快速响应?
高并发,不可忽视的业务技术挑战
高并发对于任何服务来说都具有不小的技术挑战。
在传统模式下,一方面,要求业务的研发人员有一定的业务预见性,能够提前对业务峰值做相对准确的预估,过多则造成资源浪费,过少则影响业务效果。另一方面,要求研发人员对业务架构进行合理设计,提前部署大量资源,甚至要进行大量压测以确保可靠性。不仅如此,还需要开发运维等人员参与。可以说,应对高并发问题,在传统开发模式下,需要耗费很多的人力物力,成本昂贵。
然而,这些高并发问题,在云开发模式下,相对确简单了很多。云开发作为一个支持多端开发的云 + 端一体化解决方案,采用 serverless 架构,架构具备足够的轻量和弹性,可以无限自动水平扩容,支持海量并发请求。对开发者来说,使用云开发就是典型的 NoOps 实践。随着请求量的不断增长,云开发可以进行自动扩缩容量,确保允许在云开发上面的业务高性能、高可用,按需使用资源使得开发者不需要为了应对高并发而提前部署大量资源,这大大节约了资源成本。
此外,通过云开发各类端侧 SDK 就可以轻松实现包括微信小程序、QQ 小程序、WEB 端、移动应用等多端开发,仅需专注于开发者自身的业务实现,而无需关心传统 C/S 架构中的服务端基础架构,业务可以快速开发上线,极大地提高开发效率,降低研发成本。
当前,云开发日均调用超过七亿次,其中微信读书、拼多多等客户单个环境的请求量已经达到过亿级别。
云开发的高性能高可用架构设计
云开发作为一个公有云服务,不仅要能为开发者提供各类能力支持,更重要的是能为客户业务提供连续不间断的服务。这里,云开发的高可用就包括两个方面:一是确保云开发自身服务的高可用,可以不间断提供服务;二是为客户提供支持高并发的能力支持,确保客户业务不断上涨过程中,客户业务高可用。
而云开发服务调用链路上有非常多的功能模块,这就要求云开发内部的所有功能模块都是高性能和高可用的,目前云开服务内部依赖模块,日常均达到远超过 99.99% 的服务可用性和极低的响应时间。
那么云开发如何保证高可用高性能呢?
下面先来看一下云开发整体架构:
从图中可以看到用户的一次服务调用需经过多个中间层服务,最终到的客户资源层,所以云开发服务的高可用高性能从大的层面上可分为 “数据链路” 和 “底层资源” 两个方面。目前,云开发系统 “数据链路” 和 “底层资源” 均超过 99.99% 以上的可用性。
数据链路
应用从端侧 SDK 开始访问云资源(云函数、数据库、文件存储)需经过的一系列服务模块最终到的资源层,这一调用链路对开发者来说是透明无感知的,所以这里将这一部分统称为 “数据链路”。
数据链路为用户提供 端侧 和 云资源侧 的连通能力,数据链路也并不仅仅进行数据转发和传输,还包括一系列的处理逻辑,如微信登录鉴权、票据生成与校验、数据编解码、云账户身份鉴权、集群路由、云资源信息绑定、安全规则、数据签名与校验、上下文环境信息注入、访问记数、并发控制等多方面的能力支持模块。
云开发服务各层服务模块均按多集群进行部署,集群内各层及各服务模块也均进行了跨多机房的冗余部署,提供充分的冗余,并且自动发现和剔除故障主机,确保在服务故障时能够进行快速屏蔽,保证云开发服务的高可用性。另外数据管道在资源部署上也提供了充足的容量支持,并备有一定量的 Buffer,当有用容量需求时,可进行快速扩容。部分模块也开始尝试容器化部署,能够更快速弹性扩容。
链路是用户请求能否成功到达客户资源的关键,链路耗时也会对用户请求总耗时产生直接影响。所以保证链路的高可用性和高性能非常关键,云开发团队在性能和可用性方面也做了很多的设计优化,以下为部分设计和优化点:
尽可能简单,不引入不必要的依赖,尽可能减少依赖;
无状态设计,各个模块均是无状态的,便于在系统请求量上升时快速进行横向扩容;
可降级设计,链路中各个模块均进行可降级设计,在单个模块出现问题时,可自动或手动降级到备用方案,并且有兜底方案;
多级缓存设计,在系统内部存在多级别的缓存设计,提升系统性能;
自动故障转移,链路上下游主机可以自动发现和剔除故障主机,快速恢复服务;
多集群部署,链路中各个模块均进行了跨机房的多集群部署,在故障时能够进行切换;
重试策略,针对系统中可重试的场景设计重试机制,保证成功率;
网络策略优化,长连接优化,部分模块内部采用更高效的 RPC 调用;
采用更高性能的实现方式,减少耗时;
快慢请求分离,快请求同步慢请求异步的方式提高性能。
底层资源
底层资源的高可用是云开发服务高可用的关键一环,这一部分将对 “云函数 ”和 “云数据库” 进行分别介绍。
云函数优化
云函数在高可用性方面进行了充分的架构考量,在部署上做了充分的冗余,下图为云函数高可用的部署架构。
从图中可以看到,云函数从接入层到资源层,各层均进行了多集群的部署,每个集群都按跨机房的方式部署。集群内单机或单机房故障系统能够自动发现并且快速剔除,这种部署方式可以应对单机故障、机房网络故障等设施类故障。集群故障也能够快速的切换用户集群来快速恢复服务,缩短故障时间,保证高可用性。另外这种部署上的设计,也便于进行更大范围的横向扩容,提供更大的系统并发容量,以满足客户不断上涨的业务需求。
在云函数资源底层,面多高并发请求,首先就需要有充足的能够承担高并发的计算资源,云开发的云函数底层建立了规模非常大的资源池,同时也预留的大量的 Buffer 资源,云函数系统从资源池分配资源给函数实例,在资源池消耗到一定程度时,系统可以自动化申请云上 VM 资源,快速扩容资源池,实现多层次的水平弹性伸缩,以应对开发者可能的海量业务需求。
同时,在发布策略上,按集群进行逐步的灰度,如果出现系统 Bug,能够只影响少量请求。
目前,云函数已经完成了新一轮的系统架构升级,以更高的可用性和性能,应对未来更大并发的挑战。
云函数在执行性能方面,也做了非常多的优化。熟悉云开发的开发者应该了解,函数在一次调用中会涉及到函数的启动,启动又可以分为冷启动和热启动,热启动是非常快速的,而冷启动则相对较慢。
冷启动的过程如图所示,对比可以看出,冷启动需要创建函数实例,创建过程又包含多个子任务,如下载函数代码、部署函数等,通常需要几百毫秒的耗时。
启动耗时对于云函数性能来说是非常关键的,所以云函数性能的优化重点之一就在于减少冷启动率和冷启动耗时。云函数在启动耗时方面也做了诸多优化:
优化代码下载耗时,在虚拟机内和可用区内建立多级缓存,提升下载云函数代码包下载速度;
优化函数网络部署策略,降低部署耗时;
优化容器启动,降低启动时间;
基于用户请求量变化趋势和周期性的请求量变化规律,对云函数并发量进行准实时预测,提前进行扩缩容量;
支持版本别名,用户更新代码, 以 Rolling Update 方式进行新旧版本替换,保证热启动率;
优化函数实例预留时间,保证整体的低冷启动率。
云函数底层也采用了腾讯云自研的轻量级虚拟化技术,MicroVm 启动时间缩短至 90 毫秒,函数冷启动减低至 200 毫秒,并且支持上万台计算节点同时扩容;
目前,经过函数底架构上和性能上的不断优化,部署云函数实例的各阶段耗时也在不断减少,进而云函数的冷启动时间不断降低。为客户提供更高的可用性和性能支持。
云开发目前为开发者提供单个云函数 1000 并发的能力支持,假设云函数的执行时间为 100ms,单个云函数可以达到 10000 QPS,这已经可以满足大部分用户场景的需求了,50 个云函数的总 QPS 将可以达到 50W QPS。
云数据库优化
云数据库在接入层和数据库底层也做了非常多的专项优化,同时也在部署方面进行了诸多方面的设计。云数据库的部署架构如图所示。
从架构图中可以看到,云数据库接入层进行了分层设计并支持水平横向扩容,所有用户请求会被分配到不同的主机上,每个主机都独立的维护用户数据库连接,这种方式保证了数据库接入层能够大规模进行水平扩展。另外,在部署上也进行了多集群的策略部署,集群内部能够自动发现故障主机并剔除。不同用户分配到不同的接入集群,用户请求可在多集群上进行灵活调度,以应对可能出现的服务故障,提供更高的可用性和更短的恢复时间。
在发布策略上也能做到更加可靠,按集群进行进行灰度,影响范围小。
数据库引擎实例也均进行了跨主机的多数据库实例的部署,在单数据库实例故障时能够进行自动化的转移。
数据为每个数据实例进行每日的全量备份并保存到对象存储中,以保证用户数据安全,当用户数据出现问题时,可进行数据回档,也间接的为用户提供了一定的业务可用性支持。
数据底层也将支持在线热迁移,在出现主机负载过较高时,自动在线热迁移用户实例到负载低的主机,此过程用户几乎是无感知的。热迁移同时也能够支持全局的数据库主机间的负载均衡。
数据库目前也已经提供自动加索引能力,自动化的分析用户慢查询请求并针对性的进行自动索引优化,能够在用户无感知的情况下优化用户查询性能,使开发者可以更少的关心数据库性能优化就可以有优良的性能体验,降低客户负担,更加专注于自身的业务逻辑。
高并发业务如何利用云开发进行优化?
虽然云开发为开发者提供便利的云服务能力,同时也期望能够尽可能的解决开发者在使用过程中遇到的所有问题,但显然,这是一个永无止境的长期追求。
其实开发者在这方面也可以有很大的想象和发挥空间。开发者在面对高并发需求时,可以通过云开发做哪些优化呢?
通常高并发业务按并发量上涨模型来划分,可以分为以下两种形式:
业务量相对平缓上涨,并发量逐步上升,上升速度平缓,系统有充足的预热时间;
业务并发量爆发上涨,并发量瞬间上升,上升速度很快,例如常见的秒杀类业务。
对于第一种并发量以较均匀的速度上涨的业务,直接使用云开发就可以轻松应对。对于第二种呈爆发式上涨的业务,通过一定的策略和技术上的优化,也能较轻松应对。
云函数在应对高并发请求的难点在于弹性,弹性支持了服务资源的按需部署,因此可以为开发者节省了大量资源花费。但也是因为弹性,在面对瞬时高并发需求时,服务瞬间面对比上之前大几十倍甚至上百倍的并发请求,云函数伸缩系统难以预料这种爆发性上涨,因为冷启动耗时相对较长,弹性扩容机制难以在秒级时间内实现大量云函数实例部署,无法跟上并发上涨的速度,热启动率降低,启动时间变长,进而导致部分请求超时,甚至出现超并发的情况,进而导致活动参与者因参与失败而放弃,活动效果达不到预期。如何解决这个问题呢?
策略上的优化方案
提前评估活动并发量及 QPS 等指标;
充分进行活动预热,在活动越热阶段统计和再评估参与人数及并发量;
在活动预热页面通过埋点代码的方式对业务云函数进行预热,通过参数控制不执行业务逻辑即可,也可以通过其他方式或多种方式进行预热;
在评估并发量之后也别忘记评估套餐是否能满足业务需求,云开发提供按量计费和包年包月两种计费模式,业务方可以根据实际情况调整套餐,或者切换为按量计费,避免因套餐限制影响业务。
技术上的优化方案
技术上的优化核心就一点:降低耗时。
云函数方面,可通过以下方式进行优化:
减少调用依赖服务的次数,如进行请求合并;
降低依赖服务的响应时间,如数据查询耗时,其他接口调用耗时等;
并发调用依赖服务;
根据业务逻辑合并多个函数到单个函数、或拆分单云函数到多个云函数;
精简代码、减少依赖、降低函数体积,缩短冷启动时间。
数据库方面,尽管云开发已经针对数据库查询进行了自动化的索引优化,但是系统对于用户业务逻辑和数据的设计是远远不能及业务方的,所以业务方研发团队可以在查询性能等多方面进行优化。针对高并发的场景,一些优化建议如下:
通过创建高效索引,提升数据库查询效率;
通过优化设计,减少数据库查询;
采用高效的查询条件;
减少返回数据的条数以及字段数,降低数据库的查询时间以及网络数据传输时间;
减少事务的使用,尽量用替代方式;
聚合类需求如排行榜等,可保存中间结果到数据库或缓存,避免每次进行统计计算;
数据量较大,可对集合水平拆分,降低单集合数据量,提升查询效率。
实际上,尽管云开发数据库资源层从云服务的角度来说是海量的,但是单个数据库实例计算能力是有硬件上限的,当出现较多慢查询时,数据库系统将会大打折扣,将会影响大量数据库操作,整体上会拖慢开发者自身业务响应时间,影响业务能力。云开发也计划推出慢查询日志、慢查询告警等方面的能力,提供数据库优化最佳实践。
其他建议:
对系统进行一定程度的实际压测,验证设计实现是否符合预期,并提前解决,避免活动上线之后达不到效果;
独立活动业务实现,避免活动影响现有业务。
作者介绍
艳杰,腾讯高级前端开发工程师,云开发团队核心开发专注于中后台系统开发以及系统架构设计。
评论 1 条评论