微服务在微信后台的架构实践

转载:

极客时间

重拾极客精神 · 提升技术认知

APP内打开

微服务在微信后台的架构实践

微服务的理念与腾讯一直倡导的“大系统小做”有很多相通之处,本文将分享微信后台架构的服务发现、通信机制、集群管理等基础能力与其上层服务划分原则、代码管理规则等。

背景介绍

首先,我们需要敏捷开发。过去几年,微信都是很敏捷地在开发一些业务。所以我们的底层架构需要支撑业务的快速发展,会有一些特殊的需求。

另外,目前整个微信团队已经有一千多人了,开发人员也有好几百。整个微信底层框架是统一的,微信后台有千级模块的系统。比如说某某服务,有上千个微服务在跑,而集群机器数有几万台,那么在这样的规模下,我们会有怎么样的挑战呢?

我们一直在说“大系统小做”,联想一下,微服务与腾讯的理念有哪些相同与不同的地方呢?通过对比,最终发现还是有许多相通的地方。所以我挑出来讲讲我们的实践。

看过过去几个会议的内容,可能大家会偏向于讲整一个大的框架,比如整个云的架构。但是我这边主要讲的是几个特殊的点。

概览详情

开始看一下我们的结构。全球都有分布,主要有上海、深圳、香港、加拿大几个数据中心。

image

其中上海服务国内北方的用户,深圳负责南方用户,加拿大服务北美、南美和欧洲,香港服务东南亚、中东和非洲地区。

然后来看看我们的架构:

image

  • 最上边是我们的产品;
  • 然后有一个号称几亿在线的长连接和短连接的服务;
  • 中间有一个逻辑层,后台框架讲的主要是逻辑层往后这块,包括我们的 RPC、服务分组、过载保护与数据存储;
  • 底层有个 PaxosStore 存储平台。

整套就是这么个体系。微服务很容易去构建,但是规模变大后有哪些问题,需要哪些能力?这里挑出三个点来讲一下:

image

一、敏捷

希望你的服务很快实现,不太多去考虑。像我们早期互联网业务,甚至包括 QQ 等,我们很注重架构师的一个能力,他需要把握很多的东西。他设置每个服务的时候,要先算好很多资源,算好容灾怎么做。容灾这个问题直接影响业务怎么去实现的,所以有可能你要做一个具体逻辑的时候要考虑很多问题,比如接入服务、数据同步、容灾等等每个点都要考虑清楚,所以节奏会慢。

二、容错

当你的机器到了数万台,那每天都有大量机器会有故障。再细一点,可以说是每一个盘的故障更频繁一点。

三、高并发

基础架构

接下来看看我们的基础架构。

image

整个微服务的架构上,我们通常分成这些部分:

  • 服务布局
  • 服务之间怎么做一些远程调用
  • 容错(主要讲一下过载保护)
  • 部署管理

服务布局

image

分两层,一个是城市间。城市之间的数据是相对独立的,除了少数账号全球同步,大部分业务都希望做成电子邮件式的服务,各自有自身的环境在跑,之间使用类似于电子邮件的通信。所以我们选择让每个城市自治,它们之间有一个 200-400ms 的慢速网络,国内会快点,30ms。

image

而城市内部,就是每个园区是一套独立的系统,可以互相为对方提供备份。要求独立的电源与网络接入。

城市内部会有整套的划分,终端 --> 接入层 --> 逻辑层 --> 存储层 都是完全独立的一套系统。

远程调用

看到很多框架,竟然是没有协程的,这很诧异。早年我们 QQ 邮箱、微信、图像压缩、反垃圾都是一个 web 服务,只有存储层会独立到后面去,甚至用 web 直连 MySQL。因为它早期比较小,后来变大之后就用微服务架构。

每个东西都变成一个小的服务,他们是跨机的。你可以想象一下,每天我们很多人买早餐的时候,掏出手机做一个微信支付,这一个动作在后台会引起上百次的调用。这有一个复杂的链路。在 2014 年之前,我们微信就是没有做异步的,都是同步的,在这么多调用里,A 服务调用 B,那要先等它返回,这样就占住了一条进程或者线程。所以其实 13 年的时候,我们发生了大大小小的故障,很大一部分原因就在这里。

然后 13 年底的时候,这个问题太严重了,严重到,比如发消息的时候,你去拿一个头像之类的,它只要抖动,就可能引发整一条调用链的问题,并且因为过程保护的不完善,它会把整个消息发送的曲线掉下去,这是我们很痛苦的时间。

然后当时我们就去考虑这些方案,13 年的时候抽出 3 个人重新做了一个完整的库 libco。(两千行),实现时间轮盘与事件处理链、常用网络编程模式、同步原语等。它分为三大块,事件驱动、网络 HOOK 和协程机制。

image

image

早期是多进程为主,当年切多线程的时候,也遇到一大波修改,后来线程里有了一个线程变量就好多了。如果没有这个东西,你可能要把许多变量改成参数再一层一层传递下去。有了线程变量就好多了。现在我们的协程变量也是这个意义,效果就像写一个宏一样。

另一个是,我们支持 CGI,早期库在 CGI 上遇到问题,所以没有推广。因为一个标准 CGI 服务是基于一些古老的接口的,像 getENV、setENV,就是说你的 coreString 是通过 ENV 来得到的,那么这个我们也把它给 HOOK 掉了,它会根据你的协程去分派。

最难的一个是 gethostbyname 方法,我发现很多人就连在异步编程里,处理 hostbyname 也可能是用了一套独立线程去做,或者你很辛苦地把整个代码抠出来重新写一遍,这个肯定是有很多问题的。所以我们 libco 就把这个 gethostbyname 给完整地支持了。

最后如果你还不爽,说一般业务逻辑可以这么干,那我还有很多后台代码怎么办呢?很多有经验的老的程序员可能要拿着他们那一堆很复杂的异步编程的代码来质疑我们,他们不认为他们的代码已经完全可以被协程所取代了。

他们有如下两个质疑:

  • 质疑性能:协程有很多切换,会不会带来更大开销?
  • 你可能处理几万并发就好,消耗个 1G 内存就行,但是我们这里是处理千万并发哦,这么大的规模,我不信任你这个东西。

这样我们其实是面临了一个问题,因为一些老代码,越是高级的人写的,它的技术栈越深,稍微改动一点代码,就出 BUG 了。

但是你用协程的话,很多变量就自然在一个连续的内存里了,相当于一个小的内存池,就比如 if……else……这个你没有必要去 new 一个东西保存状态的,直接放在栈里就行了,所以它的性能更好了。

第二个是,它要求很高的并发。由于协程要一个栈,我们一般开 128k,如果你对这个代码掌控得比较好,可能开 16k,就算是这样,你要开 1 万个协程,还是要 100 多 M 的内存。所以我们后来就在这基础上做了一个可以支持千万连接的协程模式。

Libco 是一个底层库,让你很方便开发,但是大部分开发人员不是直接面对 libco 的,我们花了一年时间把整个微信后台绝大部分逻辑服务、存储服务改成基于 libco,整个配置就直接通过配一台机器上的并发数配 10 倍甚至 20、30 倍,这样子就一下子把整个问题解决了。

过载保护

并发数上去后容易引发另一个问题,早期的时候,后端服务性能高,逻辑服务性能相对弱,很容易被 hold,不可能给后端发起很多连接,不具有“攻击性”,但修改完成后,整个前端变得很强,那可能对后端产生很大的影响。这个时候就要来考虑一下过载保护了。

image

一般会提到几个点。

1.轻重分离:

就是一个服务里边不要又有重的操作,又有轻的,这样过载的时候,大量的请求都被某些小请求拦截掉了,资源被占满了。

2.队列:

过载保护一般是说系统内部服务在做过去的事情,做无用功。它们可能待在某个队列里边,比如服务时间要求 100ms,但它们总是在做 1s 以前的任务,所以整个系统会崩溃。所以老的架构师会注重说配好每一个服务的队列长度,估算好。但是在繁忙的开发中,是很难去控制的。

3.组合命令式:

后端服务并不是只有一个,上边这个图中的例子,想要调用很多服务,然后 AB 都过载,它们每一个其实都只是过载一点,通过率可达到 80%,但是前端需要这两个服务的组合服务,那么这里就可能只能达到 60% 的通过率。然后后边如果是更多的服务,那么每个服务的一点点过载,到了前端就是很严重的问题。怎么解决呢?

image

这本书在 12、13 年的时候很火,里边提到了两个对我们有用的点。

  • 一个是“希望系统是分布式的,去中心化”,指系统过载保护依赖每一个节点自身的情况去做,而不是下达一个统一的中心指令。
  • 二是“希望整个控制是基于反馈的”,它举了一些例子,像抽水马桶,像过去炼钢铁的参数很难配,但是只要有一个反馈机制就好解决了。

于是我们构建了一套看起来有点复杂的过载保护系统。

image

整个系统基于反馈,然后它把整个拒绝的信息全程传递了。看到最右边,有几个典型的服务,从一个 CGI 调用一个后台服务,再调用另一个后台服务,它会在 CGI 层面就把它的重要程度往下传。回到刚才那个前端调用 A、B 服务的例子,使用这样的一种重要程度传递,就可以直接拒绝那些相同用户的 20% 的请求,这样就解决了这个问题。

怎么配队列?

这个只是反映了生产者和服务者处理能力的差异,观察这个差异,就可以得到一个好的拒绝的数。你不需要去配它多长,只需要去看一个请求在队列里待的平均时间是否可以接受,是一个上涨趋势还是一个下降趋势。这样我们就可以决定要不要去拒绝。那这样几乎是全自动的。你只要配得相对大一点就行了,可以抗一些抖动。在接入之前就评估它,在过去一段时间内平均队列耗时多长,如果超过预支,我们就往下调。这样就把整个系统的过载能力提升了很多。

image

这是一个具体的做法,我们会考虑两个维度,一个是后台服务,可能服务很多不同的前端,它可能来源于一个支付的请求,经过层层调用,到达后台;或者是一个发消息的服务;它也可能是一个不重要的小服务,如果这个账户服务过载的时候,那么我们可以根据这个表来自动地优先去拒绝一些不那么重要的服务请求,使得我们核心服务能力可以更好地提供。这样整个系统就可以做到很好的过载保护。

数据存储

上边提到一个数据层,那我们是怎么去做数据的呢?

image

在过去很多年里,我们可能是尽可能去事务化、不追求强一致,一般是采用主备同步的方法。但我们的目标还是强一致的存储。

强一致是说,写一个数据之后,服务器的返回成功不会因为单机故障而丢失。早年我们用的是自己设计的协议,严格来证明的话,没有 Paxos 这么严谨,所以我们在过去一年多的时间内,重新做了一个 Paxos 存储。

image

它是一个同步复制的数据存储,支持各个园区之间的数据一致性,并且是可以多组多写的,就是说任何一个园区接入,它都可以进行数据的强制读写。另外它并不只是 key-value 模式,它支持 key-value、list、表。在微信这边很少会说完全依赖 key-value 的,因为很多业务都是有列表、表格等的请求,所以很多年前就开始用表格的存储。

Paxos 可用性很高,所以我们就敢做单表有亿行的设计,这样像公众号粉丝等需要很大的,几千万甚至几亿行的记录,就不用考虑自己去分表。并且这个存储可以使用类 SQL 的语句去做,它是完全保证事务的。

它还是插件化系统,不仅支持 LSM,还支持其它存储引擎。

然后它低成本,后台 CPU 有 E3-1230V3,也有 E5-2670 型号的,内存,CPU 与 ssd 之间有一些能力用不上,所以我们系统是可以灵活组合很多不同存储介质的。

这个系统是跑在同城的,也就是上海内部、深圳内部、加拿大内部和香港内部。它们之间的延迟相对较低,几毫秒的级别。这是一个非租约的,没有 leader,不存在切换的不可用期,随时都可以切换任何一个园区。负载均衡这一块我们沿用 kb64 架构,6 台机为一组。因为园区故障少,平时单机时,分摊 25% 的流量,整体比较稳定。6 台为一组时,整个作为一个 set,有很多 set 之间的适用一致性要去做,会有一个很细粒度的伸缩性,比如它可以 100 组扩展到 101 组。

为什么用这么重的方式呢?

因为希望应用是 简单快速 的,不用假设一个数据写完之后还可能被回退掉,这样只会有很多额外的开销,会有很多问题。比如公众号,他们有很多素材库之类的很重要的存储,如果数据突然丢了,或者说回退了,没有了,那用户投诉是会很严重的。微信账号这边也是这样,如果一个账户注册了,但是这个数据回退了,那也是很严重的问题。

另一个原因是 可用性。在一个传统的主备系统里面,当主机挂掉,面临切不切备机的抉择,然后你会层层请示,说明目前的同步状况,甚至你不知道当前的同步状况,经过很多流程来请示是否切换备机。

而另外,它也不是一个高成本的方案。

为什么不用 Raft 呢?

Raft 的开源很有价值,它把互联网后台的数据一致性能力提升了很多,就算是一个很小的团队,它也能直接用 Raft 获得一个强一致能力,而这可能就已经超过了许多互联网后台的强一致能力,因为很多后台都是用了很古老的架构,比如长期用到主机架构。

Raft 与 Paxos 的区别是什么呢?

image

其实 Raft 和 Paxos 不是一个层面的概念,这个图就是典型的通过一个 log 变更 db 的架构,通过三条 log 一致性做到数据持久强一致性。那 Paxos 在哪里?在一个 log 的某一个 entry 那边,三个点构成一个常量。

那 Raft 是什么呢?它是整一个二维的东西,就是说,基于一个 Paxos 强一致协议做的一条 log,它整个就是一个 Raft。所以我们可以认为 Raft 其实是 Paxos(log)的一种选择。如果你允许绿色部分不存在,那它就不是 Raft。因为 Raft 的设计是你自己做的,它与 Paxos 没关系。

整个 PaxosStore 架构如图:

image

它包含了很多层,包括缓存和汇聚层、同步复制的组件等。

这一套方案是在线上用了好几千台的,是一个非租约的方案。存储引擎可以自由定制。如果想用大表,那可以用 leveldb。如果想用更强的 LSM,也可以选择。然后我们也有很多 Bitcask 的模型,更适合于内存的 key-value。

由于有几万台机,所以变很重要,我们也基于 BT 做了一套存储方案。它会以园区为根据地,通常一个变更,会以 BT 协议发送到每个园区里,然后园区内部把同机架机器分成一个分组,然后分组内再互传。就我了解,Facebook 和 Twitter、Ebay 都是这样做的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为一款全球流行的社交软件,微信架构设计非常复杂和庞大。微信架构涉及到包括移动客户端、服务器、数据库、网络通信等多个方面。下面将对微信架构进行详细的介绍。 一、微信移动客户端架构 微信移动客户端是微信的主要入口,也是用户使用最为频繁的部分。微信移动客户端主要包括以下几个模块: 1.登录模块:用户需要先进行注册和登录才能使用微信,登录模块主要实现用户身份验证和授权。 2.聊天模块:微信最核心的模块,主要实现文字、语音、视频、图片等多种形式的聊天功能。 3.通讯录模块:主要实现好友管理、添加好友、查找好友等功能。 4.发现模块:主要提供了微信朋友圈、公众号、小程序等功能,让用户可以更方便地浏览和使用。 5.我模块:主要提供了账户管理、设置、支付等功能。 微信移动客户端采用MVC(Model-View-Controller)架构,将客户端的业务逻辑、界面显示和用户交互分离开来,使得代码更加模块化和清晰。其中,Model层主要负责业务逻辑的处理和数据的操作,View层主要负责用户界面的显示和交互,Controller层主要负责协调Model和View的交互。 二、微信服务器架构 微信服务器是微信移动客户端和其他系统之间的中间件,主要负责数据的传输和处理。微信服务器主要包括以下几个模块: 1.登录验证模块:用户登录后,微信服务器需要对用户进行身份验证和授权,并生成相应的token。 2.消息传输模块:微信服务器需要将用户发送的消息进行传输和处理,包括文字、语音、视频、图片等多种形式的消息。 3.好友管理模块:微信服务器需要对好友关系进行管理,包括添加好友、删除好友、查找好友等。 4.朋友圈管理模块:微信服务器需要对朋友圈进行管理,包括发表动态、评论和点赞等。 5.支付模块:微信服务器需要对用户的支付进行管理,包括支付请求、支付处理和支付结果通知等。 微信服务器采用分布式架构,将不同的功能模块分别部署在不同的服务器上,以提高系统的稳定性和可扩展性。同时,微信服务器采用负载均衡技术,将访问请求分配到不同的服务器上,以降低单一服务器的压力。 三、微信数据库架构 微信数据库主要用于存储用户信息、聊天记录、朋友圈动态、支付记录等数据。微信数据库采用分布式数据库架构,将不同类型的数据分别存储在不同的数据库中。具体来说,微信采用以下几种数据库: 1.关系型数据库:主要用于存储用户信息、聊天记录和支付记录等数据,采用MySQL和Oracle等关系型数据库。 2.非关系型数据库:主要用于存储朋友圈动态和其他非结构化数据,采用MongoDB和Redis等非关系型数据库。 3.图数据库:主要用于存储社交网络数据,采用Neo4j等图数据库。 微信数据库采用分库分表技术,将数据按照用户ID进行分片存储,以提高数据库的性能和扩展性。同时,微信数据库采用主从复制和备份技术,以保证数据的安全性和可靠性。 四、微信网络通信架构 微信的网络通信架构主要包括移动网络、运营商网络、互联网和微信服务器之间的通信。微信采用HTTPS加密协议进行通信,以保证数据的安全性和可靠性。具体来说,微信的通信架构包括以下几个部分: 1.移动网络:主要是用户的移动设备和运营商之间的通信,包括2G、3G、4G和5G等移动网络。 2.运营商网络:主要是用户的移动设备和微信服务器之间的通信,包括电信、联通和移动等运营商网络。 3.互联网:主要是微信服务器之间的通信,采用互联网协议TCP/IP进行通信。 4.微信服务器:主要是微信移动客户端和其他系统之间的中间件,采用HTTPS协议进行通信。 微信的网络通信架构采用CDN(Content Delivery Network)技术,将用户请求分配到离用户最近的服务器上,以提高访问速度和减少网络延迟。同时,微信采用反向代理和负载均衡技术,将访问请求分配到不同的服务器上,以降低单一服务器的压力。 五、微信技术架构 微信的技术架构主要由以下几个方面组成: 1.移动开发技术:微信移动客户端采用原生开发技术,包括iOS和Android两个平台,同时还采用了React Native和Flutter等跨平台开发技术。 2.服务器开发技术:微信服务器采用Java、Python、C++等编程语言进行开发,同时还采用了Spring、Hibernate、MyBatis等框架和技术。 3.数据库技术:微信数据库采用MySQL、Oracle、MongoDB、Redis等数据库技术。 4.网络通信技术:微信采用HTTPS、TCP/IP、CDN、反向代理、负载均衡等网络通信技术。 5.大数据技术:微信采用Hadoop、Spark、HBase等大数据技术进行数据分析和处理。 微信技术架构是一个复杂而庞大的系统,涉及到多种技术和工具的应用和整合。微信技术架构的设计和优化,对于提高微信的性能和稳定性具有重要意义。 六、微信安全架构 微信的安全架构主要包括以下几个方面: 1.身份验证和授权:微信使用OAuth 2.0协议进行身份验证和授权,以保证用户的身份安全。 2.数据加密和解密:微信采用AES加密算法进行数据加密和解密,以保证数据的安全性。 3.防范攻击:微信采用防火墙、入侵检测、反病毒等安全技术,防范各种攻击和恶意软件。 4.数据备份和恢复:微信采用数据备份和恢复技术,以保证数据的安全性和可靠性。 微信的安全架构采用多层次和多重保护措施,以保证用户的账户和数据的安全性和可靠性。 七、微信数据分析架构 微信数据分析架构主要用于对用户数据进行收集、分析和处理,以提供更好的用户体验和服务。微信数据分析架构主要包括以下几个方面: 1.数据收集:微信采用数据收集工具,收集用户的行为数据、社交网络数据、搜索数据等。 2.数据存储:微信采用分布式数据库和云存储技术,存储用户的数据,包括用户信息、聊天记录、朋友圈动态等。 3.数据处理:微信采用Hadoop、Spark、HBase等大数据技术,对用户数据进行处理和分析,提供更好的用户体验和服务。 4.数据可视化:微信采用数据可视化技术,将数据以图表、报表等形式展现出来,方便用户进行数据分析和决策。 微信数据分析架构的设计和优化,对于提高微信的用户体验和服务质量具有重要意义。 综上所述,微信架构设计非常复杂和庞大,涉及到移动客户端、服务器、数据库、网络通信、技术、安全和数据分析等多个方面。微信架构设计和优化,对于提高微信的性能、可靠性和安全性,以及提供更好的用户体验和服务质量具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值