浅谈互联网三高:高并发、高性能、高可用

浅谈互联网三高:高并发、高性能、高可用

摘要:本文通过查阅相关资料,介绍了互联网中高可用、高性能、高扩展的产生背景及概念,介绍了一种高性能web设计架构,同时以美团中分布式架构设计为例,介绍了在实际应用场景中,互联网公司是中如何解决三高问题的。

关键词:分布式架构设计、高并发、软件架构

一、什么是互联网三高

互联网的三高架构就是指设计互联网系统架构时需要满足高可用,高性能,高并发,但其中可将高并发系统和非高并发系统,算成两个维度,在这两个维度下还有三高:(1)高可用 (2)高性能 (3)高扩展

二、高并发

高并发指的是系统同时处理很多请求。高并发的出现是一种结果导向,例如:淘宝的双11、春运时的抢票、微博大V的热点新闻等,这些典型场景并不是陡然出世,而是随着业务发展的发展而逐渐出现。同时,产生了支持高并发业务场景的架构——技术要为业务服务,业务倒逼技术发展。

高并发的衡量标准并没有具体限制,也就是说,只看数据是不行的,要结合具体的场景。不能说10W QPS的秒杀是高并发,而1W QPS的信息流就不是高并发,因为信息流场景涉及复杂的推荐模型和各种人工策略,其业务逻辑可能比秒杀场景复杂10倍不止。业务场景不一样,执行复杂度不一样,单看并发量也没有意义。

总结,高并发无定势,是要和具体的业务场景相结合的,无高并发场景,也就无高并发架构。

三、一种高并发、高性能的Web架构

这张图展示了一个典型的,三层架构的高性能 Web 应用。这种成熟的架构多年以来已被广泛部署于包括 Google、Facebook、Twitter、Wikipedia 在内的诸多大型 Web 应用中。

(1)反向代理服务

位于三层构架中最外层的反向代理服务器负责接受用户的接入请求,在实际应用中,代理服务器通常至少还要完成以下列表中的一部分任务

l 连接管理:分别维护客户端和应用服务器的连接池,管理并关闭已超时的长连接。

l 攻击检测和安全隔离:由于反向代理服务无需完成任何动态页面生成任务,所有与业务逻辑相关的请求都转发至后端应用服务器处理。因此反向代理服务几乎不会被应用程序设计或后端数据漏洞所影响。反向代理的安全性和可靠性通常仅取决于产品本身。在应用服务的前端部署反向代理服务器可以有效地在后端应用和远程用户间建立起一套可靠的安全隔离和攻击检测机制。如果需要的话,还可以通过在外网、反向代理、后端应用和数据库等边界位置添加额外的硬件防火墙等网络隔离设备来实现更高的安全性保证。

l 负载均衡:通常使用轮转(Round Robin)或最少连接数优先等策略完成基于客户请求的负载均衡;也可以使用 SSI 等技术将一个客户请求拆分成若干并行计算部分分别提交到多个应用服务器。

l 分布式的 cache 加速:可以将反向代理分组部署在距离热点地区地理位置较近的网络边界上。通过在位于客户较近的位置提供缓冲服务来加速网络应用。这实际上就构成了 CDN 网络。

l 静态文件伺服:当收到静态文件请求时,直接返回该文件而无需将该请求提交至后端应用服务器。

l 动态响应缓存:对一段时间内不会发生改变的动态生成响应进行缓存,避免后端应用服务器频繁执行重复查询和计算。

l 数据压缩传输:为返回的数据启用 GZIP/ZLIB 压缩算法以节约带宽。

l 数据加密保护(SSL Offloading):为与客户端的通信启用 SSL/TLS 加密保护。

l 容错:跟踪后端应用服务器的健康状况,避免将请求调度到发生故障的服务器。

l 用户鉴权:完成用户登陆和会话建立等工作

l URL别名:对外建立统一的url别名信息,屏蔽真实位置。

l 应用混搭:通过SSI和URL映射技术将不同的web应用混搭在一起。

l 协议转换:为使用 SCGI 和 FastCGI 等协议的后端应用提供协议转换服务。目前比较有名的反向代理服务包括:Apache httpd+mod_proxy / IIS+ARR / Squid / Apache Traffic Server / Nginx / Cherokee / Lighttpd / HAProxy 以及 Varnish 等等。

(2)应用服务

应用服务层位于数据库等后端通用服务层与反向代理层之间,向上接收由反向代理服务转发而来的客户端访问请求,向下访问由数据库层提供的结构化存储与数据查询服务。应用层实现了 Web 应用的所有业务逻辑,通常要完成大量的计算和数据动态生成任务。应用层内的各个节点不一定是完全对等的,还可能以 SOA、μSOA 等架构拆分为不同服务集群.

Web 应用节点由 IO 回调线程池、Web 请求队列以及后台工作线程池等三个重要部分组成,其伺服流程如下:

当一个 Web 请求到达后,底层操作系统通过 IOCP、epoll、kqueue、event ports、real time signal (posix aio)、/dev/poll、pollset 等各类与具体平台紧密相关的 IO 完成(或 IO 就绪)回调机制通知 AIO(Asynchronous IO)回调线程,对这个已到达的 Web 请求进行处理。

在 AIO 回调池中的工作线程接收到一个已到达的 Web 请求后,首先尝试对该请求进行预处理。在预处理过程中,将会使用位于本地的高速缓存来避免成本较高的数据库查询。如果本地缓存命中,则直接将缓存中的结果(仍然以异步 IO 的方式)返回客户端,并结束本次请求。

如果指定的 Web 请求要求查询的数据无法被本地缓存命中,或者这个 Web 请求需要数据库写入操作,则该请求将被 AIO 回调线程追加到指定的队列中,等待后台工作线程池中的某个空闲线程对其进行进一步处理。

后台工作线程池中的每个线程都分别维护着两条长连接:一条与底层到数据库服务相连,另一条则连接到分布式缓存(memcached)网络。通过让每个工作线程维护属于自己的长连接,后台工作线程池实现了数据库和分布式缓存连接池机制。长连接(Keep-Alive)通过为不同的请求重复使用同一条网络连接大大提高了应用程序处理效率和网络利用率。

后台工作线程在 Web 请求队列上等待新的请求到达。在从队列中取出一个新的请求后,后台工作线程首先尝试使用分布式缓存服务命中该请求中的查询操作,如果网络缓存未命中或该请求需要数据库写入等进一步处理,则直接通过数据库操作来完成这个 Web 请求。

当一个 Web 请求被处理完成后,后台工作线程会将处理结果作为 Web 响应以异步 IO 的方式返回到指定客户端。

(3)应用服务

数据库服务为上层 Web 应用提供关系式或结构化的数据存储与查询支持。取决于具体用例,Web 应用可以使用数据库连接器之类的插件机制来提供对不同数据库服务的访问支持。在这种架构下,用户可以灵活地选择或变更最适合企业现阶段情况的不同数据库产品。例如:用户可以在原型阶段使用 SQLite 之类的嵌入式引擎完成快速部署和功能验证;而在应用的初期阶段切换到廉价的 MySql 数据库解决方案;等到业务需求不断上升,数据库负载不断加重时再向 Clustrix、MongoDB、Cassandra、MySql Cluster、ORACLE 等更昂贵和复杂的解决方案进行迁移。

Memcached 服务作为一个完全基于内存和 <Key, Value> 对的分布式数据对象缓冲服务,拥有令人难以置信的查询效率以及一个优雅的,无需服务器间通信的大型分布式架构。对于高负载 Web 应用来说,Memcached 常被用作一种重要的数据库访问加速服务,因此它不是一个必选组件。用户完全可以等到现实环境下的数据库服务出现了性能瓶颈时在部署它。值得强调的是,虽然 memcached 并不是一个必选组件,但通过其在 YouTube、Wikipedia、Amazon.com、SourceForge、Facebook、Twitter 等大型 Web 应用上的多年部署可以证明:memcached 不但能够在高负载环境下长期稳定地工作,而且可以戏剧性地提升数据查询的整体效率。

当然,我们也应该注意到:以 memcached 为代表的分布式缓存系统,其本质上是一种以牺牲一致性为代价来提升平均访问效率的妥协方案——缓存服务为数据库中的部分记录增加了分布式副本。对于同一数据的多个分布式副本来说,除非使用 Paxos、Raft 等一致性算法,不然无法实现强一致性保证。

另外,即使是 Paxos、Raft 之类的分布式一致性算法也只能在单个记录的级别上保证强一致。意即:即使应用了此类算法,也无法凭此提供事务级的强一致性保证。

与此同时,可以看到:从二十年前开始,各主流数据库产品其实均早已实现了成熟、高命中率的多层(磁盘块、数据页、结果集等)缓存机制。既然分布式缓存有如此多的缺陷,而数据库产品又自带了优秀的缓存机制,它为何又能够成为现代高负载 Web App 中的重要基石呢?

其根本原因在于:对于十年前的技术环境来说,当时十分缺乏横向扩展能力的 RDBMS(SQL)系统已成为了严重制约 Web App 等网络应用扩大规模的瓶颈。为此,以 Google BigTable、Facebook Cassandra、MongoDB 为代表的 NoSQL 数据库产品,以及以 memcached、redis 为代表的分布式缓存产品纷纷粉墨登场,并各自扮演了重要作用。与 MySQL、ORACLE、DB2、MS SQL Server、PostgreSQL 等当时的 "传统" SQL数据库产品相比,无论 NoSQL 数据库还是分布式缓存产品,其本质上都是以牺牲前者的强一致性为代价,来换取更优的横向扩展能力。

应当看到,这种取舍是在当时技术条件下做出的无奈、痛苦的抉择,系统因此而变得复杂——在需要事务和强一致性保障,并且数据量较少的地方,使用无缓存层的传统 RDBMS;在一致性方面有一定妥协余地,并且读多写少的地方尽量使用分布式缓存来加速;在对一致性要求更低的大数据上使用 NoSQL;如果数据量较大,同时对一致性要求也较高,就只能尝试通过对 RDMBS 分库分表等方法来尽量解决,为此还要开发各种中间件来实现数据访问的请求分发和结果集聚合等复杂操作……各种情形不一而足,而它们的相互组合和交织则再次加剧了复杂性。

四、美团的即时物流的分布式系统架构设计

1、背景

美团外卖已经发展了五年,即时物流探索也经历了3年多的时间,业务从零孵化到初具规模,在整个过程中积累了一些分布式高并发系统的建设经验。最主要的收获包括两点:

(1)即时物流业务对故障和高延迟的容忍度极低,在业务复杂度提升的同时也要求系统具备分布式、可扩展、可容灾的能力。即时物流系统阶段性的逐步实施分布式系统的架构升级,最终解决了系统宕机的风险。

(2)围绕成本、效率、体验核心三要素,即时物流体系大量结合AI技术,从定价、ETA、调度、运力规划、运力干预、补贴、核算、语音交互、LBS挖掘、业务运维、指标监控等方面,业务突破结合架构升级,达到促规模、保体验、降成本的效果。

2、即时物流架构

美团即时物流配送平台主要围绕三件事展开:一是面向用户提供履约的SLA,包括计算送达时间ETA、配送费定价等;二是在多目标(成本、效率、体验)优化的背景下,匹配最合适的骑手;三是提供骑手完整履约过程中的辅助决策,包括智能语音、路径推荐、到店提醒等。

早期,美团按照业务领域划分成多个垂直服务架构;随着业务的发展,从可用性的角度考虑做了分层服务架构。后来,业务发展越发复杂,从运维、质量等多个角度考量后,逐步演进到微服务架构。这里主要遵循了两个原则:不宜过早的进入到微服务架构的设计中,好的架构是演进出来的不是提前设计出来的。

3、分布式系统

上图是比较典型的美团技术体系下的分布式系统结构:依托了美团公共组件和服务,完成了分区扩容、容灾和监控的能力。前端流量会通过HLB来分发和负载均衡;在分区内,服务与服务会通过OCTO进行通信,提供服务注册、自动发现、负载均衡、容错、灰度发布等等服务。当然也可以通过消息队列进行通信,例如Kafka、RabbitMQ。在存储层使用Zebra来访问分布式数据库进行读写操作。利用CAT(美团开源的分布式监控系统)进行分布式业务及系统日志的采集、上报和监控。分布式缓存使用Squirrel+Cellar的组合。分布式任务调度则是通过Crane。

在实践过程还要解决几个问题,比较典型的是集群的扩展性,有状态的集群可扩展性相对较差,无法快速扩容机器,无法缓解流量压力。同时,也会出现节点热点的问题,包括资源不均匀、CPU使用不均匀等等。

首先,配送后台技术团队通过架构升级,将有状态节点变成无状态节点,通过并行计算的能力,让小的业务节点去分担计算压力,以此实现快速扩容。

第二是要解决一致性的问题,对于既要写DB也要写缓存的场景,业务写缓存无法保障数据一致性,美团内部主要通过Databus来解决,Databus是一个高可用、低延时、高并发、保证数据一致性的数据库变更实时传输系统。通过Databus上游可以监控业务Binlog变更,通过管道将变更信息传递给ES和其他DB,或者是其他KV系统,利用Databus的高可用特性来保证数据最终是可以同步到其他系统中。

第三是保障集群高可用,主要从三个方面来入手,事前较多的是做全链路压测评,估峰值容量;周期性的集群健康性检查;随机故障演练(服务、机器、组件)。事中做异常报警(性能、业务指标、可用性);快速的故障定位(单机故障、集群故障、IDC故障、组件异常、服务异常);故障前后的系统变更收集。事后重点做系统回滚;扩容、限流、熔断、降级;核武器兜底。

4、多中心尝试

美团IDC以分区为单位,存在资源满排,分区无法扩容。美团的方案是多个IDC组成虚拟中心,以中心为分区的单位;服务无差别的部署在中心内;中心容量不够,直接增加新的IDC来扩容容量。

5、单元化尝试

相比多中心来说,单元化是进行分区容灾和扩容的更优方案。关于流量路由,美团主要是根据业务特点,采用区域或城市进行路由。数据同步上,异地会出现延迟状况。SET容灾上要保证同本地或异地SET出现问题时,可以快速把SET切换到其他SET上来承担流量。

免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部