在大部分互联网公司中业务和技术是这样的关系,公司是业务驱动型的,技术是服务于业务的,在不同阶段技术承担着业务背后的守门员角色。

互联网系统系统发展到一定规模之后需要面对多个层面不同的压力,从资源压力到数据访问瓶颈都需要持续进行解决。

比如早期的互联网业务更多的是为了进行业务试错,所以通过单体系统实现一个MVP架构。随着业务落地之后用户规模的增加,会进入分布式阶段,通过大量无状态的服务水平扩展解决大用户量带来的压力。之后进入业务和数据高度丰富的阶段,这个解决需要解决的除了性能问题还有数据安全性和业务的可用性,一般通过异地多活的方式实现容灾。再之后是一系列的精细化运营,主要是降低平台成本,通过工具化自动化等方案实现降本增效。

对于互联网架构,一般需要解决的问题是高并发场景下的高性能,高可用,以及高扩展。

高性能的标准是低延迟,高可用的标准是几个9,高扩展的标准是开发成本低。

我们假借支付宝的发展看下在业务和数据发展到一定规模之后,互联网系统架构应如何设计。

比如在数据量发展到一定规模之后,我们可以进行数据库拆分,可以进行分表,一般采用水平拆分解决写瓶颈或是数据量问题。也会按照业务垂直的拆分到多个库中,上层是一套套的微服务,经过分库分表和微服务拆分基本可以支撑TPS在万级甚至更高的访问量了。

随着微服务应用数量的越来越多,数据库连接数量也增长巨大,让数据库本身资源成为了瓶颈。这个问题发生的根源在于所有应用无差别的访问数据库,这样数据库连接数就变成了笛卡尔积了。

本质上这种是因为资源隔离处理的不够彻底,需要解决的方式是逻辑上移,从数据层,到服务层,到API层进行分离,也就是一套套的独立部署单元,也就是单元化的雏形。

这样我可以将整套单元进行独立打包部署,同类请求进入一个单元内被消化,由于这种彻底的隔离性,整个单元可以轻松部署到任意到机房并且保证逻辑上的统一。

强一致性场景,比如金融可以做三地五中心部署:

支付宝是一个金融场景,也是一款国民应用,日访问的TPS可以达到几十万上百万,所以早就做了单元化方案,去解决容量上的问题和实现异地容灾的需求。

支付宝采用三地五中心保障整体系统的可用性,其单元化分成三类(CRG架构):

  • - RZone(Region Zone):就是从数据层,到逻辑层,到API层的整体部署最小单元,每个RZone连上数据库可以撑起一片天空,让业务跑顺滑。

  • - GZone(Global Zone):全局单元,也就是全局一份,部署了不可拆分的数据和服务,比如系统配置数据。正常情况下GZone也会进行异地部署,不过容灾的目的更高一些,一个GZone写,其他GZone目的为读。

  • - CZone(City Zone):就是以城市为单位部署的单元,同样部署了一套一体的数据和服务,比如用户账号服务,客户信息服务等。CZone是基于特定的GZone场景进行优化的一种单元,访问频次上会高于GZone,低于RZone。GZone里面会出现“写读时间差现象”,所以RZone如果想访问某些数据可以只访问CZone,而不是GZone。

“写读时间差现象”情况是,大部分数据写入后,都会需要持续的读取,比如我们办完银行卡后,可能很长时间才会存进去一笔钱,这样在我们真实世界中对于数据一致性的要求是远低于数据复制的一致性的。所以异地延迟100ms对于业务上也不会造成营销,所以只需要CZone中写入后100ms后可以用到这个数据,就可以将数据和服务放到CZone中。

为什么需要这三种部署单元方式,背后是因为业务上对于不同性质数据的要求不同。我们经常用UserId来进行分库分表操作,围绕此类系统数据可以分为两类:

  • - 用户流水型数据:比如用户订单或用户访问数据等。这些都是根据用户行为产生的流水型数据,具有天然的用户隔离,非常适合分库分表后独立部署服务,因为用户之间的数据不需要相互访问,内聚在一个单元即可。

  • - 用户间共享型数据:比如用户创建的一些共享的信息,比如微博,文章等,还有比如关系型数据,比如商品,财务统计等这些非用户产生的数据,所有用户都需要访问。比如商品数据如果按所在地存放数据,那么上海用户如果想访问杭州的商品数据,就需要跨zone了,达不到单元化的理想状态,如果在多个zone中进行数据存放,会给整个系统运维带来复杂度提升。

我们可以将上面提到的数据划分到RZone和GZone中,RZone包含具体用户数据及服务,GZone包含用户共享数据及服务。

在支付宝单元化架构中,是没有CZone的。GZone只能单地部署,因为数据要被共享,多地部署会再来异地延迟引起不一致,比如实时风控数据,如果多地部署,每个RZone只访问本地数据很容易获取旧的数据和规则这样很危险。

那么所有数据都不支持延迟吗?

其实大部分场景是写后不需要实时读取的,也就是对于数据强一致性要求不高的。对于这部分数据我们允许每个地区RZone服务直接访问本地,为了支持这些RZone的数据访问,也就提出了CZone概念,在CZone场景下,写请求一般从GZone写入公共数据的主库,然后同步到OB集群,然后由CZone提取数据,比如支付宝会员服务。

单元化之后,异地多活只是多地部署而已,支付宝对单元化的基本要求是每个单元都具备服务于用户的能力,而且支付宝的单元化和用户关系的配置是可以动态修改的,这样异地双活的单元还起到了彼此备份的作用。

spanner是nginx的代理网关,有些请求可以通过反向代理转发到其他IDC的spanner而无需进入后端服务。对于应该在本IDC处理的请求,直接映射到对应的RZ即可。

进入单元内的请求如果只需要访问用户流水型数据,一般不会在进行路由了。而有些场景可能需要访问其他用户共享的数据,那么可能会涉及到再次路由,这种处理有两个结果:跳转到其他IDC或跳转到本IDC的其他RZone。

RZone到DB数据分区的访问是实现配置好的,比如RZ和DB的关系为:

- RZ0* --> a

- RZ1* --> b

- RZ2* --> c

- RZ3* --> d

比如杭州用户访问了支付宝域名,默认按照地域路由流量,根据IP将域名解析到杭州IDC的IP。之后请求达到IDC-1的spanner集群服务器上,spanner从内存读取到了路由配置,知道了请求主体用户所属的RZ3*不在本IDC,于是直接转发到IDC-2处理。之后根据流量配比规则分发到RZ3B进行处理。RZ3B得到请求后对数据分区C进行访问,处理完成后原路返回。

为了解决跨地域路由问题,可以将决策迁移到客户端,比如每个IDC机房有自己的域名,如IDC-1对应域名1,IDC-2对应域名2,APP中可以直接通过rest访问不同的域名,后面对于用户行为的解析都在域名之上发生,避免了走一遍IDC-1带来的延迟。

对于容灾的处理的前提是,当发生灾难后通用的方法是把陷入灾难的单元的流量打到正常的单元上去,这个过程叫做切流量。支付宝架构灾备有三个层次:

1. 同机房单元间灾备

2. 同城机房间灾备

3. 异地机房间灾备

对于灾难来说,最小的灾难是某个单元由于插座断开,线路老化,人为误操作等导致宕机,由于每组RZ都有A,B两个单元,可以用来做同机房灾备,并且AB之间是双活双备,正常AB两个单元共同分担所有请求,一旦A挂了,B将自动承担A单元流量份额,是默认灾备方案。

如果因为机房光缆被挖断,或者机房维护任何操作事务,需要人工定制切流量。

切流量流程如下:

  1. 将陷入灾难的机房RZone对应的数据分区访问配置进行修改。

  2. 在修改IDC和RZ配置之前,需要先把数据分区进行配置修改。

  3. 之后在修改IDC和RZ之间的映射配置。

这样在切流量期间的用户请求会失败,并发起重试提示。真实情况下,并不是在发生灾难时才进行切流量,而是事先配置好预案,推送给客户端,或者集成到spanner。

异地机房容灾方案和同机房灾备方案基本一致。

分布式系统解决的最大痛点就是单机系统可用性问题,要想高可用,必须分布式。比如我们会启动多个服务层水平扩展,底层可能还是一个数据库。一方面解决了单点导致的低可用性问题,另一方面无论这些水平扩展的机器间网络是否出现分区,这些服务器都可以各自提供服务,因为机器之间是无状态的,不需要考虑数据一致性问题。

为什么分布式系统里面不推崇采用数据库事务呢?因为用了事务数据库就变成了单点和瓶颈了。

所以从CAP角度来说,分布式系统如果满足了CP,A不出色是常态,也就有另一个BASE定理了,也就是最终一致性。在分布式系统里面,一致性一般选择退让。

一般系统应用层是无状态的水平扩展,数据一致性处理一般交给数据层,那么如果想要在应用层做到一致性,有什么好方法吗?做好一致性需要处理应用之间的状态同步,大家可以参考下ZK的方案。

对于数据层,我们可以采用读写分离,一主多从缓解读可用性问题,写可用性问题的解决方案可以通过keepalived的HA框架保证主库是活着的,这种方案带来性能上的可用性提示,至少不会因为某个实例挂了就不可用了。

主从之间进行通信,通过心跳保证只有一个Master,一旦发生分区,每个分区会选择一个新的Master,这样出现脑裂,常见的主从数据库解决方案,没有自带的脑裂解决方案。可以考虑引入仲裁机制,从而实现最终一致性,自动规则无法合并的情况只能依赖于人工处理了。

异地多活的意思是,每一地都可能产生数据写入,异地之间偶尔网络延迟,网络故障都会导致网络产生分区,一个机房里面很少产生网络分区,但是异地这个概率会很高。所以支付宝的三地五中心需要考虑这个问题,应对网络带来的分区问题,做好数据一致性处理。

支付宝的每个单元由两部分组成:复制业务逻辑计算的应用和负责数据持久的数据库。应用层不对写一致性负责,这个任务下沉到数据库。所以关键在数据库。

支付宝自研了OceanBase,可以解决分区之后脑裂的数据不一致问题。

分区容忍性可以分为“可用性分区容忍”和“一致性分区容忍”。

可用性分区容忍的关键在于不让一个事务到所有节点,一个事务没必要让所有节点都参与。

一致性分区容忍的意思是说,既然分区了还谈什么事实一致性,但要保证最终一致性也不是那么容易,如果出现分区,如何保证同一时刻只有一份协议呢?如何保证脑裂后只有一个脑呢?

简单的脑的理解是可以处理写的,那些非脑就是只处理读的。

Paxos是唯一解决分布式场景下一致性的解决方案。Paxos逃离了CAP的约束。所以我们可以任务Paxos是唯一一种保障分布式系统最终一致性共识算法,通过过半投票保障大家结果一致。

我们想一下Paxos是怎么处理的。

Paxos要求任何一个提议,需要超过半数以上节点认可,才认为可信。如果已经完成了多数节点认可,但是系统宕机了。重启后仍然可以通过一次投票知道哪些值是合法的。这样可以解决分区下的共识问题。

一旦产生分区,我们要求一个分区内节点数量超过半数,这样的设计可以巧妙的避开脑裂问题。当然MySql集群脑裂问题可以通过其他方式解决,比如同时ping一个公共服务ip,成功者继续为脑,但是会制造另一个单点。

Paxos的一致性贡献在于,集群中有部分节点保有了本次事务的正确结果,正确的结果随后以异步方式同步到其他节点上,从而保证了最终一致性。

在回过头说下支付宝的OB如何做到数据库层面的一致性的。在OB体系下,每个数据库实例都具备读写能力,具体的读写可以动态配置。对于某一类数据比如用户号段内的数据,在任意一刻只有一个单元负责写入节点,其他节点要么实时同步数据,要么异步复制数据。

OB采用了Paxos共识,实时库之间同步节点个数至少需要(n/2)+1个,这样可以解决分区容忍性问题。

比如用户最开始请求到A单元,但是这时A单元网络断开产生了分区,我们将A单元某个号段数据交给了B单元,这次用户进行了重试,但是网络断开之前的请求已经进入了A,这样A,B单元里都有了数据,导致了不一致。

在OB体系下这种情况不会发生,因为A单元与其他节点之间失去了联系,其他节点对于它来说是不可达的,A知道自己分区了,所以这个提议被丢弃,之后B会接替A完成写入任务。之后B同步了自己的提议,大部分节点响应了,最终的数据是B写入的数据,A从来没机会写入。

OB节点之间相互通信,进而完成数据同步,如果出现分区问题,OB通过同步部分节点来保证可用性,OB解决了分区容错。

OB事务只需要同步到(n/2)+个节点,允许剩余一小半节点分区,只要(n/2)+1节点存活就是可用的。

OB不能解决强一致性问题,因为分区情况下,部分节点失联了,但是通过共识算法,保障同一时刻只有一个合法值,并且最终会通过节点间同步达到最终一致性。

所以OB没有逃离CAP魔咒,产生分区时,牺牲了C,整体来说还是AP的。

回过头再来看下支付宝在大规模用户请求下做的架构设计:

基于用户分组的RZone设计,让每个用户可以独占一个单元完成请求,解决了系统容量带来的挑战。

RZone在网络分区或灾备切换时,OB的防脑裂设计(Paxos),我们知道RZone是单脑的(读写都在一个单元对应的库),而网络分区时可能产生多个脑,OB解决了此种情况下的共识问题。

基于CZone的本地读设计,很大程度上保障了写读时间差的现象,提升了本地读速度。

剩下的一点情况不能本地读取,只能实时访问GZone的公共配置,也不会造成太大的问题,比如实时库存数据,可以通过“页面展示查询走应用层缓存”+“实际下单时再校验”的方式减少对于GZone的依赖和调用量。

当然除了单元化和OB的方案,支付宝还做了其他一些事情,比如双十一的缓存预热,削峰运营数据,压测容量规划等技术手段。其他互联网公司可以借鉴下。

从支付宝看大用户规模互联网架构发展相关推荐

  1. 大用户规模互联网架构发展

    在大部分互联网公司中业务和技术是这样的关系,公司是业务驱动型的,技术是服务于业务的,在不同阶段技术承担着业务背后的守门员角色. 互联网系统系统发展到一定规模之后需要面对多个层面不同的压力,从资源压力到 ...

  2. 交通银行上海分行信息部总经理吴宇:大数据助力”互联网+金融”发展

    上海,中国的经济.金融.贸易.航运中心,一直以变革.创新引领着中国企业的发展.在"互联网+"浪潮下,上海企业首当其冲,这座城市,一直用信息化手段推动着企业的高速发展.2016年10 ...

  3. 1万条数据大概占多大空间_Java互联网架构-性能优化Mysql索引数据结构详解

    欢迎关注头条号:java小马哥 周一至周日下午三点半!精品技术文章准时送上!!! 精品学习资料获取通道,参见文末 一,索引数据结构红黑树,Hash,B+树详解 索引是帮助MySQL高效获取数据的排好序 ...

  4. 在传统企业做互联网架构是什么感受?

    作者 | 王晔倞 责编 | 郭   芮 最近与某位搞风险投资的朋友聊起中美贸易战,他对未来局势的走向很是悲观,而我却不屑一顾. 在他眼里,当下的美国已将中国列为竞争对手,曾今的大哥摆出了一副 &quo ...

  5. 互联网架构如何促进数字化营销

    2018云栖大会南京峰会的企业级互联网架构专场,数梦工场企业事业部总经理段云飞对互联网架构助力企业数字化营销升级进行了讲解,首先讲述了未来十年的新型互联网时代,然后介绍了新型互联网的架构和两个案例,最 ...

  6. 互联网架构的演变,看了好多这个讲的确实清楚!

    从过去的 OA.CRM.ERP 等单机即可满足要求的系统到现代互联网时代各大公司的分布式.微服务平台,互联网架构正在经历着巨大的变革,技术也在不断的更新迭代. 图片来自 Pexels 这也意味着众多软 ...

  7. 大数据环境下互联网行业数据仓库/数据平台的架构之漫谈

    导读: 整体架构 数据采集 数据存储与分析 数据共享 数据应用 实时计算 任务调度与监控 元数据管理 总结 一直想整理一下这块内容,既然是漫谈,就想起什么说什么吧.我一直是在互联网行业,就以互联网行业 ...

  8. 一文看懂大数据生态圈完整知识体系【大数据技术及架构图解实战派】

    一文看懂大数据生态圈完整知识体系 徐葳 随着大数据行业的发展,大数据生态圈中相关的技术也在一直迭代进步,作者有幸亲身经历了国内大数据行业从零到一的发展历程,通过本文希望能够帮助大家快速构建大数据生态圈 ...

  9. 大数据用户画像系统架构设计

    文章目录 一.用户画像数据仓库搭建.数据抽取部分 二.大数据平台.用户画像集市分层设计.处理 三.离线计算部分 四.实时计算部分 五.Solr/ES搜索引擎部分 六.Java Web毫秒级实时用户画像 ...

最新文章

  1. JBOSS+EJB3之Entity 开发实例
  2. 对学校的希望和寄语_新年元旦寄语【三篇】
  3. Python argparse模块基本用法
  4. Linux 使用ntpdate自动对时
  5. Java工作笔记-AJAX实现整体不变,局部更新(与整体刷新比较)
  6. win10下安装Ubuntu18.4双系统(适合小白)
  7. 【数学信号处理】基于matlab数字信号频谱分析【含Matlab源码 1544期】
  8. VSCode下载安装和配置Java环境
  9. (附源码)基于springboot平衡膳食小程序 毕业设计 250859
  10. android简单计时器源码,Android简单计时器实现
  11. 快速学会CC2530单片机基础点灯
  12. 深度学习中训练迭代次数理解【源码阅读技巧分享】【深度学习循环迭代理解】【for X, y in train_iter:】
  13. 【风马一族_php】NO0_搭建web服务器
  14. 大疆FPGA/芯片开发工程师(A卷)笔试题(含详解)
  15. 天天自习软件测试计划
  16. 在Unity中使用ComputeShader
  17. Android基础之RemoteViews
  18. 让3个线程打印ABC
  19. CSS字体:Webfont在线字体与外部字体及操作系统预装字体使用指南
  20. 一位月薪8000的程序员写的代码,你们觉得值这个价吗?

热门文章

  1. 批量插入数据库语句java_java相关:MyBatis批量插入数据到Oracle数据库中的两种方式(实例代码)...
  2. python文本数据转换数值矩阵_python numpy矩阵的数据类型转换
  3. springmvc + springboot + mybatis java b2b2c电子商城系统源码...
  4. Selenium2+python自动化1(环境安装)
  5. php 处理ftp常用操作与方法
  6. 用GDB调试程序(五)
  7. 51Nod-1046 A^B Mod C【快速模幂】
  8. HTML:基本的标签
  9. 基于TransactionScope类的分布式隐式事务
  10. 这次,让我们捋清:同步、异步、阻塞、非阻塞