大型网站技术架构演进

文章目录

  • 系列文章目录
  • 前言
  • 1 构建 型网站:分布式改造.. ... .… .. .. .…. ..... ... .. .. .. .. .. .. .. .. .. .. .. 1
    1.1 为什么要做分布式化... ...... ... ... ... …. ...... ……… ……… .. .… .... .. .... 1
    1.2 典型的分布式架构 .. .. .. .. ... .. ..... ... .. ...... ... .. .. .. .. ....... ........... .. ...... ... ... 2
    1.3 布式配置框架. ..... ............ .. .. ... .. ... .. ....... .. ... .... .. ... ...... .. .. ...... .. .......... ..... 4
    1 4 分布式 RP 框架..... ... ….. ... ..… …. .......… …·· ····… ........... .. .….. .. ... ...... 6
    1.5 分布式消息框架………… .. .. .. .………… .... .. ..…···· ······· ···… …… .......…............... 8
    1.6 分布式数据层 .........….. ... .. ...... .. .. ........... .. .. .. ........ ... ... .. .. .. ........ .. 11
    1. 7 分布式文件系统.......…....... ......... ……· ··· ··· …............. ... ........ .. ... 12
    1. 8 应用的服务化改造………………… ………… ………… …… …........ .. .. .. .. .. ..... 15
    1.9 分布式化遇到的典型问题... ... …… ······ ·· ·…….........… ············· …………
    1.10 分布式消息通道服务的设 计· ·· ·· ··· ······· ·· ··· ·············· ··· …… ...... 19
    1.11 典型 分布式集群设 思路... ... ..… ............ .. ....... ... .... ... .. ... .... ...... ... ..... 2 1
    1.1 2 总结................ ......…… ......... .. .....……………… ..............…. ........ .......... 24

前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、大型网站技术架构演进与性能优化?

1.1 为什么要做分布式化
一个网站的技术架构早期很多都是 Linux+Apache+MySQL+PHP 的系统,随
着业务的扩展和流 的爆发式增长,该系统很快达到了瓶颈,是不是 定要对它做分
布式改造呢?其实我们在早期也尝试用过 些高端的服务器( IOE ,但一方面价格昂
贵,另 方面即便这样也阻挡不了瓶颈的到来,分布式改造成为必由之路
所谓分布式改造,就是尽 让系统元状态化,或者让有状态的信息封装在一定范
围内,以免限制应用的横向扩展 简单来说,就 个应用的少数服务器岩掉后,
不会影响整体业务的稳定性
要实现应用的分布式改造必须先解决好以下几个问题 大型网站技术架构演进与性能优化
,应用需要微服务化 即将大量粗粒度的应用逻辑拆小做服务化改造
,必须先建立分布式服务框架 必须具备分布式配置系统、分布式 RPC
架、异步消息系统、分布式数据层、分布式文件系统、服务的发现、注册和管理
,必须解决状态 致性问题
下面我们将围绕以上问题展开描述
1.2 典型的分布式架构
分布式架构与传统的单机架构最大的区别在于分布式架构能解决两个方向的扩
展问题 一是横向扩展, 是纵向扩展
横向扩展,主要用来解决应用架构上的容 问题 由于单台服务器能支撑的服务
能力始终是有限的,所以我们在架构上就必须做到能够支持横向服务能力的扩展
典型的横向扩 是图 1.1 所示的 Web API 接人层,它在支持 PY 10 PY 时所
需要的服务器数 必然是完全不 样的,因此要考虑当服务器不够用时,它也能支撑
PY 的无限增长 因此这两层一般都属于无状态的服务
纵向扩展,主要解决业务的扩展问题 当业务不断扩展时,业务逻辑的复杂度也
会不断上升,所以在架构上要能根据功能的划分进行纵向层次的 划分 例如, Web/API
层只做页面逻辑或者展示数据的封装,服务层做业务逻辑的封装等 业务逻辑层还可
以划分成更多的层次,以支持更细的业务的组合
个典型的分布式网站架构如图 1.1 所示 它将用户的请求通过负载均衡随机分
配给 Web 机器, Web 机器再通过远程调用请求服务层 但是数据层一般都是有
状态的,而数据要做到分布式化,就必须保证数据的 致性 要保证数据的一致性,
一般都需要对最细粒度的数据做单写控制,因此要记录数据的状态、做好数据的访问
控制等
个有状态的分布式架构如图 1.2 所示 分布式集群中一般都有 Master 负责
管理集群中所有机器的状态和数据访问的规制等,为了保证高可用 Master 也有备份,
Master 通常会把访问的路由规则推给实际的请求发起端,这样 Client 就可以直接和实
际要访问的节点通信了,避免中间再经过一层代理
2 构建大型网站 :分布式 改造
圄圃圆圄圆 圃圈 噩圈圃 b/
r-1 圄跚 固; 服务层
噩噩 一一 噩噩 一一 噩噩 -:
慰据层
典型的分布式架构
国国- ..
J
\
圈圈
.I
有状态的分布式架构
还有 种分布式架构 是非 Master-Slave 模式而 Leader 机制,即分布式 集群
中没有单独的 Master 角色,每个节点功能都是一样的,但是在集群的初始 化时 会选取
Lea der 承担 Maste 的功能 。一 旦该 Lea der 失效,集群会重新选择一个 Leader
这种方式的好处是不用单独考虑 Master 的节点的可用性,但是也会增加集群维护的复
杂度
1.2
( 1 )需要分布式中间件
从前面典型的分布式架构上可以看出,要搭建一个分布式应用系统必须要有支持
分布式架构 的框 例如首先要有 个统一的负载均衡系统( LB/LVS )帮 助平均分
外部请求的流量,将这些流 量分配 到后端的多台机器上,这 类设备一般 都是工作在第
3
\回 大型网站技术架构演进与性能优化
四层,只做链路选择而不做应用层解析;应用层的负载均衡可以通过出来实现,例
如可以根据请求的 URL 或者用户的 Cookie 精准地调度流
请求到达服务层,就需要解决服务之间的系统调用了 这时, 需要在 服务层构
一个典型的分布式系统,包括同步调度的分布式 RPC 框架、异步调度的分布式消息、
框架和解决静态配置信息的分布式配置框架 个分布式框架就像人体的骨髓和经
络,把整个服务层连接起来 我们会在后面详细介绍这 个典型的分布式框架(分布
式框架的开源产品有很 多, 例如 Dubbo RocketMQ 等)
请求到达数据层 数据层需要解决以下问题:第 屏蔽不 同数据库的差异性,
使底层数据库的切换不影响上次应用代码;第二,屏蔽应用层代码对数据分布的感知,
使对数据的分区或者分片不 会影 响应用代码的编 由于一般来说数据层都是有状态
的,所以用数据层解决分布式问题会更 复杂 、难度也更大 开源的 DRDS 等都是用于
解决这类问题的
( )服务化和分布式化
我们在网站升级中 般会接触到两个概念:一是服务化改造;二是分布式化改造
那么它们是一回事吗?
服务化改造更多 从业务架构的角度出发,目的 是将 业务做更细粒度的功能拆分,
使业务逻辑更加清晰 、边界更 加清楚且易于维护;服务化的另 一个好 处是收敛业务逻
辑,通过接口标准化提供统 的访问方式 分布式化更 多是 从系统架构层面的角度出
发,更多是看请求的访问路径,即一个请求必须先访问什么再访问什么、一次访问要
经过哪些步骤才能最终有结果等……因此,这是两个不同层面的工作
1.3 分布式配置框架
分布式配置框架可以说是其他分布式框架的基础,因为在分布式系统中要做到所
有机器节点都完全对等几乎是不可能的,必然有某些机器或者集群存在某些差异,但
同时又要保证程序代码是 份,所以解决这些差异的唯 办法就是差异化配置一一配
置框架就承担着这些个性化的定制功能 :它把 差异性封装到配置框架的后台中,使集
群中的每台机器节点的代码看起来都是一致的,只是某些配 置数据有差
配置框架的原理非常简单,即向 个控制台服务端同步最新的 KN 集合、
JSON ML 或者任意 个文件,配置信息可以是在内存中的也可以是持久化的文件
4 1 构建大型网站:分布式改造
它的最大难点在于 集群管理 机器数 量的能力和配置下发 的延时
如图 1.3 所示,分布式配置框架一般有以下两种管理方式
其一,拉取模式 拉取模式就是 Client 集群主动向 ConfigServer 机器询问配置信
息是否有更新,如果有则拉取 最新的信息更新自己 这种模式对配置集群来说比较简
单,不需要知道 Client 的状态也不需要管理它们,只需处理 Client 的请求就行了,是
典型的 模式 缺点是 ConfigServer 没法主动及时更新配置信息,必须等 lient
求时再更新 。一 Client 都会设置 个定时更新周期,通常是几秒钟
其二,推送模式 这种模式是当 ConfigServer 感知到配 置信 息变化时主动把信息
推送给每个 Client 它需要 ConfigServer 感知到每个 Client 的存在,需要保持和它们
之间的心跳,这使得 ConfigServer 的管理难度增加了,当 Client 的数据很大时,
ConfigServer 有可能会成为瓶颈
lilJ 一一~ ,.
一一一一一一回疆
llG ~
¥-
管理集群
1.3
分布式配置框架
在实际的应用场景中,一般而言,如果对配置下发延时率比较敏感而且 lient
据不是太大(千级别)时,推荐使用推送模式,像 Zoo Keeper 就是这种框架(我们在
后面的小节会介绍几种分布式管理的场景);而 lient 数据在万级以上时推荐使用
拉取模式 不过,不管运用哪种模式我们都要考虑以下两个问题
( I )由于是典型的 Master/S !aver 模式,要求在数据下发时要控制节奏,不要让
ConfigServer 的网卡成为瓶颈,尤其是当下发的数据量较大时
( )要保证配置下发的到达率,即 ConfigServer 需要精确地知道每个 Client 是否
5 大型网站技术架构演进与性能优化
已经是最新的配置数据 般解决这个问题的办法是给每次配置信息的更新增加一个
版本号,然后 Client 在每次要更新时都用这个版本号和 ConfigServer 的最新数据比较,
如果小于 ConfigServer 再自我更新
分布式配置框架是最简单的管理 lient 器及相应配 下发功能的框架,因此,
它也很容易发展成带有这两种属性的其他的工具平台,如名字服务、开关系统等
1.4 分布式 RPC 框架
应用系统要做分布式改造,必须先要有分布式 RPC 框架,否 将事倍功半,为
什么呢?这就像盖楼一样,如果没有先搭好骨架的话,很可能就是给自己“埋坑”
要做好分布式 RPC 框架需要实现服务的注册、服务发现、服务调度和负载均衡、统
一的 DK 当前 Java 环境中分布式 RPC 框架如 Dubbo HSF 都是 较成熟的框
架,但是其他语言像 PHP ++还不多
一个通常意义上的 RPC 框架 般包含如图 1.4 所示的结构
\\
i~
-~’
1.4 RPC 框架
( 1 )服务注册
服务要能被发现,必须先注册 服务的注册对 Java 程序来说非常简单,只需要在
应用启动时调用 RPC 框架直接向服务端注册就行, 般需要传递类名、方法名、参
数类型以及版本号
由于语言上的一些限制,用 PHP 来做服务的注册和发现相比之下要困难很多
PHP 不像 Java 那样很容易地支持长连接,所以在 PHP 文件启动时很难像 Java 程序
那样在初始化函数里完成注册 PHP 来说目前有两个办法:第一个办法是写一个
FPM 的扩展,在第一次 FPM 初始化时完成服务的注册 但是如果一个 FPM 部署了多
6 仅供非商业用途或交流学习使用
1 构建大型网站 :分布式改造
个服务模块,那么如何区分也是一个难题;第 个办法是在 PHP 模块里手动配置一个
要注册的 服务 名录列表,在 PHP 打包发布时进行注册
务注 册后,服务发布者所在的机器 需要和注 册中心保持心跳以维持自己处于
可以提供服务的状态,否则 注册中 心就会踢 掉机器 PHP 来说,维持 RPC 连接
是个麻烦事,所以一般会在本机另外再起一个 proxy agent 或者直接发送 HTTP 请求,
但是这样做 较消耗性能
( )服务发现
服务发布方注册服务后,服务调用方就要能够发现服务 服务发现(如图 1.5
示)最重要的一个目标就是要把服务和提供服务的对应机器解锢,而不是通过机器的
IP 寻找服务
服务调用方只需要关心服务名,不用关心该服务由谁提供 、在哪 儿提供 是否可
用· …· ·服务发现的组件会把这些信息封装好
1.
服务发现
Java 语言来说 服务发现就是把对应的服务提供者当前能够存活的机器列表推
给服务调用者的 机器的内 存,真正发起调用时随机选取一个 IP 就可以发起 RPC 调用
PHP 来说,如何把服 务发布者的机器列表推给调用方也很麻烦,目前的解 决方
案更 倾向于在本机的 Agent 中完成地址列 表的更新,然后真正调用时再查询 gent
新的本地文件,并从本地文件中查找相应的服务
( )服务调度和负载均衡
服务注册和发现完成后,就要处理服务的调度和负载均衡了(如图 1.6 所示)
务调用有两个关键点 一是要 摘除故障节点, 是负载均衡
7 仅供非商业用途或交流学习使用
大型网站技术架构演进与性能优化
摘除故障节点 这对 Java 来说比较容易处理:一旦有机器下线后,很容易更新
地址列表 但对 PHP 来说就只能定期从 Agent 中拉取 最新的 地址列表,做不
到像 Java 那样实时
负载均衡 负载均衡需要将调用方的请求平均分布到不同的服务提供者的机器
上,一个最简单的算法就是随机选取,做得复杂一点可以给每个提供者 IP
置一个权重,然后根据权重选取
1.6 服务调度与负载均衡
( )统一的 SDK
服务框架需要提供 个统一的客户端和服务端的标准接口规范,这样可以减少业
务开发的重复工作量,例如 SDK 会统一封装通信协议、失败重试 以及封装 一些隐式
参数传递( trace 信息)
Java 通过提供 一个统一的 jar 包,封装了服务发布和调用的接口,业务层只 要做
些简单的配置就能方便地调用服务,例如 Java 一般都会配置一个 Spring Bean
对其他语言来说,运用 IDL 规范是个好选择 thri 仕的 基础上,修改 code gen,
生成 struct ( class )的 read write ,生成 Cli nt server 插件框架,并基于 thri 玩的
lib 提供 Binary Protocol TCP Transport
1.5 分布式消息框架
个分布式应用系统中,除了 RPC 调用之外,还需要在应用之间传递一些消息
数据,这时分布式消息中间件就成为必需品 消息中间件主要用于异步和一个 Provider
多个 onsumer 的场 景中 消息可分为实时消息和延时消息
8 仅供非商 用途 交流学 使用
1 构建大型网站:分布式改造
1 .实时消息
消息就是当消息发送后,接受者 消费 消息( 1.7 示) 很多开
消息 中间件如开 RocketMQ Apache Kafka 等都是 的消 中间件
Sender node
R eceiver
I MQr
I
I MO
I
1.
消息
( I )异步解搁
异步解祸的好处体现在多个方面 可以分开调用者和被调用者的处理逻辑,降低
系统稠合,解决处理语言之间的差异、数据结构之间的 异以及生产消息和消费者的
速度差异(削峰填谷)
紧视台系统
秘台系统
·’
……
消息队列
1.8
异步消息
通过中 的消息队列服务,可以做很多事情,但是要保证以下两点
最终的一致性 致性 求不能丢消息,保证消息最终可达,如果最终不可达
要反馈给发送方
消息的有序性 有序性是指消息的先后顺序,先后的顺序是按消息的发送时
排序
( )多消费端
个消息被多个订阅者消费是典型的 种应用场 (如图 l.9 所示),多消费端非
常适合用在单一事情触发的场 例如当一个订单 游会对这 订单做很
9 仅供非商业用途或交流学习使用
大型网站技术架构演进与性能优化
多额外的处理,而消息的生产者对这些消息的消费者根本不会关心,非常适合用在一
个大型的异构系统中
田三 2年
订阅消息
---一
组噩消
一一一”
确认消息
阜----
汀阅消息
-
投型消息
-一一-
确认消息
阜----
1.9
多端订阅消费
场景中我们会遇到下面这些典型问题
确认消息是否被消费 当出现多个消费者时,需要确定哪些消息发送成功,哪
些消息发送失败,是否要重新发送……所以消息队列中需要增加消费确认标识,
以确定哪些消 费端已经成功消费了消息,而投递失败的需要重新投递
消息队列需要有容错能力 当某 个消息失败后,需要消息队列有容错能力,保
证消 费端恢复后能重新投递消息,所以消息 队列 要有 能力保存 一定的消息量
2. 延时消息
除了实时消息外,延时消息、用得也比较广泛 典型的例子比如 张电影票的订单
产生后,用户在 15 分钟 后仍然没有付款,那么系统会要求在 15 分钟后取消该订单,
释放座位(如图 1.10 示) 这种场景非常适合用延时消息队列来处理
延时队列
.....
3i
…口
…款信息
||:…
I. I 0 延时消息队列
10 仅供非商业用途或交流学习使用
1 构建大型网站 分布式改造
延时消息在技术实现上比实时消息队列要更难,因为它需要增加 个触发事件,
而这个触发事情有时候不 一定是 时间触 发事件,还有可能是其 消息事件触发,这样
导致它所承担的业务逻辑会更重,架构也会更复杂
延时消息的核心是需要有 个延时事情的触发器,此外还必须解决消息的持久
存储问题,其他方面和实时消息队列差不多 总体来说,所有的消息队列都必须要解
决最终一致性、高性能和高可靠性问题
3. 几种常见的消息中间件
p: // qu ues.io /上 几乎列出了 当前大部分开源的消息 队列 ,每个产品各有特点,
适用于不同应用场景,适合的才是最好的
1.6 分布式数据层
分布式数据层主要解决数据的分库分表、主备切换以及读写分离等问题,统一封
装数据库的访问细节,如建立连接中的用户名和密码、连接数、数据类型的转换
等信息
( 1 )分库分表
分布式数据层最重要的功能是对数据做分库分表处理(如图 1.11 所示),尤其对
互联网公司来说,数据量的不断增长要求切分数据是相当平常的任务
~§8-.EjE
EE-. e1a
阳启 gs _. 自露
EB_. 8RIE3
分库分表
条或者一批 SQL 提交给分布式数据层,井根据某些标识进行规制运算后,应
该将这些 QL 分发 给规 则被命中的机器 去执行并返回结果 这里最重要的是数据分片
的规制要对开发透明,即写 SQL 的同学不用关心他要请求的数据到底在哪台机器上,
当我 改变数据分片规制时,只需要修改路由规 则而 无须修改 SQ
所以很显 然该分布式数据层需要解析 用户的 SQL 并且有可能会重写 SQL (例如
11 仅供非商业用途或交流学习使用
大型网站技术架构演进与性能优化
修改表名或者增加一些 HINT 等信息)
( )主备读 写分离
数据库的读写分离是常见的操作,如图 1. 12 所示 由于数据库资源非常宝贵,为
了保证数据库的高可用 般都会设置一主多备的架构;为了充分利用数据库资源,都
会进行读写分离,即写主库读从库 在同机房的场景下,数据库主从复制的延迟非常
低,对应用层没有什么
12 数据库读写分离
在原理上主从的读写分离比较简单,就是拆开用户的写请求和读请求,并分别路
由到不同的 DataSource 在这种场景下要注意读写 致性的问题 在某些场景如双
11 抢单时,用户下 完单立即查询下单是否成功,如果查询从库延时会比较大,用户很
可能看不到下单成功界面从而重复下单,要有保障机制避免此类问题发生
1.7 分布式文件系统
有些应用需要读写文件数据时,如果只写本机的话那么就会和本机绑定,这样这
个应用就成为有状态的应用,那么就很难方便地对这个应用进行迁移,水平扩展也变
得困难
不仅是文件数据, 些缓存数据也存在类似问题 现在很多的分布式缓存系统
Red is Memcache 等就是用于解决数据的分布式存储 问题的
当前开源的分布式文件系统很多,像开源的 TFS FastDFS GF 等,它们 主要
解决的是数据的高可用性和高性能问题 ,下面我们介绍 个分布式文件系统
Seaweedfs 的设计,它的设计比较巧妙,很有启发性(如图 13 示)
12 仅供 非商 业用途或交流学习使用
构建大型网站:分布式改造
一一 回国 一--
·回回国
团团 ~--- 回国 --- :
画圈圈圈
1.13
一种 布式文件系 统架构
Seaweedfs 件系 统有 个非常重要 组成 ster VolumeServer
Volume
Master 管理多个 VolumeSer er ,它的 工作是分配某文件到 VolumeServer 中,
并维 件的 副本,它通过 Ra ft 议保 一致性
VolumeServer 管理多个 Volume Volume 包含固定大 小的 存储空 ,每
Volume 可存储 Volume 存储空 被写满 为止 Master
VolumeServer Volume 只是逻 辑上的划分 可以 运行在 台机器上
Volume 表示一 固定大 小的存储
Volume 30GB 的容 ,被分配一个唯 bit YolumeID
YolumeServer 多个 Volume 和每个 Volume 剩余可写的存储 ,并上 Master;
Master 集群 当前 写的 Volume 列表,一旦 Volum 满就标识为
果整个集群 没有可写的 Volum ,那么整个集群都将不可写,只能通过扩容增
YolumeServer
Client 上传 首先需要 Master 阳, Master 前可
Volume 中随机选 和大多数分 式文 系统 样,这个 fid 就是 示文
在集群 中的 存储 地址 ,最重要的是 的前 32bi ,代表的是 YolumeID ,表示该文件具
体存储在哪个 Volume 中井返回 此创 应该存储的 VolumeS ve 的机器
个上 传文件请求如 curl -F ”自 le= tmp es
t.jp
””
92.
16
8.
:9333
/ submit
,
返回{ ”自d Olf83e45 泞’ leNam ”.” te t.jpg ","丑 le Uri
1 92
.1 68.
0 .
1 : 8
08113,0
lf83e45
缸”
12315 Client 到自 Uri 再将文件实际上传 192.1 0.1 :8 VolumeSer er
13 仅供非商业用途或交流学习使用
大型网站技术架构演进与性能优化
文件的多副本也是在 Mas ter 管理 ,巧妙的 地方在于文件的 多副本不是 以单个
用户的文件为单位而是以 Volume 为单位进行管理 例如上面的飞 01 f83e45ff' '这个刷,
它是存在 Volume 中,那么这个 Volume 会有 个副本,即在其他的 Volumes 巳凹 er
上也有 的飞 lolume ,那么当 test.jpg 上传到 192.168.0. l :8081 时,它会 查询 Master
这个 Vo lume 的副 本在哪台机器上,然后由这台机器把文件 co py 到对应的机器上,再
返回结果给用户 目前还是采用强一致性来保证多副本的一致性,如果某个副本上传
失败则返回用户失败的结果
扩容比较简单,当 群中所有的 Volume 都写满时,再增加 一些 VolumeServer
增加若干 Volume, Master 会收集新增的 VolumeServer 空闲 Volume 并加入到可写
Volume 列表中
如果有机器挂掉的话,由于 Volume 是有备份 Volume 的,所以只 要存在一
Volume, Master 都会保证能够返给用户正确的请求 这里 需要注意的是 Vol um 巳的多
备份管理并没有主次的概念,每次 Mas ter 都会在可用的多备份中随机选择一个返回
假设 这个 Volume 的副本分别在 192.168.0.2:8081 192.168.0.3 :8081 上,那么如果
192.168.0.3 :8081 机器“ 岩”掉 ,那么这个 应的 Vo um 就会被设置为只读,实际
192.168.0 .3:808 上所 有对应的 Vo lume 会被设置为只读 一一 只要某个 Volume
副本数减少,都会禁止再写
综上,这个文件系统的设计思路可以总结成以下两点
第一,通过 Vol ume 作为 基本的存储管理单元,类似作为一个“集装箱”, 旦“集
装箱”装满了,就不再写入而转为只读 每个存人的文件都被放在一个 Vo lume ,并且
返回 个文件名;存储系统不再维护原始文件名与生成的文件名的对应关系 文件系
统的 致性是以 Vo lum 巳的 单位进行保证的,并且每个 Vo lume 可以独立存储和移动
第二,分布式文件的路由信息是由 Master 来管理和分配的,而且每次请求都需要
强依赖 Master, Master 的高可用则由 Raft 来协调
到目前为止,该文件系统 0.7 的版本还不是太完 ,表现在没有 个很完
Client 程序来处理 Master VolumeServer 之间的跳转,一般需 要自己写 但是它最吸
引人的地方就是 Volume (集装箱式的设计),这个设计比较简单和独立,尤其是管理
比较方便 当然,大部分分布式系统的设计也都有相似之处
14 仅供非商业用途或交流学习使用
1 构建大型网站:分布式改造
1.8 应用的服务化改造
解决好跨应用的连接和数据访问后,我们的应用也要做好相应的改造,如应用分
层的设计、接口服务化拆分等
( 1 )应用分层设计
应用分层设计很有必要 例如最起码要把对数据库的访问统一抽象出来形成数据
层,而不是直接在代码里写 SQL 一一 这会使重构 用和水平拆分数据库非常困难
我们通常从垂直方向划分应用,分成服务层、业务逻辑层和数据层,每 层尽量
做到解搁:上层依赖下层,而下层不要反向依赖上层
应用分层最核心的目的是每个层都会封装 些信息、完成 些特定的功能需求,
层与层之间通过接口交互,而且交互的数据是清晰和固定的,做到隔离和交互 可以
从以下两个方向判断分层是否合理
第一,如果我要增加一些新需求或者修改某些需求时,是否能清楚地知道要到哪
个层去完成,换句话说,这些分层的职责是否清晰
第二,如果每个层对我的接口不变,那么每个层内部的修改是否会导致其他层也
发生修改,即每个层是否做到了收敛
分层设计中最怕的就是在接口中设计一些超级数据结构,如传递一个对象,然后
把这个对象一直传递下去,而且每个层都可能修改这个对象 这种做法导致两个问题:
一是一旦该对象更改,所有层都要随之更改;二是无法知道该对象的数据在哪个层被
修改,在排查问题时-会比较复杂 因此,在设计层接口时要尽 使用原生数据类型如
String Integer Long
( )微服务化
微服务化,是从水平划分的角度尽 把服务分得更细, 个业务只负责一个功能
单元,这样可以把这些微服务组合成更大的功能模块 也就是有目的地拆小应用,形
成单一职责从而提升系统可维护性、扩展性和开发效率
1.14 所示是基于 Spring Boot 构建的 个典型的微服务架构,它按照不同功能
将大的会员服务和商品服务拆成更小原子的服务,将重要稳定的服务独立出来,以免
经常更新的服务发布影响这些重要稳定的服务
15 仅供非商业用途或交流学习使用
大型网站技术架构演进与性能优化
做应用 ~~~ 主] 鸣明
1. 微服务架构
1.9 分布式化遇到的典型问题
在大型分布式互联网系统中, Session 问题是典型的分布式化过程中 会遇到的难题
因为 Sess ion 数据必须在服务端的机器中共享,并要保证状态的 致性 该问题在《深
入分析 Java Web 技术内幕(修订版) 的第 10 章中有详细的介绍
Zoo Keeper 个分布式的 ,开放源 码的分布式应用程序协调服务,它是 个为
分布式应用提供一致性服务的软件,所提供的功能包括:配置维护、域名服务、分布
式同步、组服务等 下面我们介绍 一下典型 的分布式环境下遇到的 一些典型 问题的解
决办法
1 .集群管理 CG oup Membership)
Zoo Ke per 能够很容易地实现集群 理的功能,如图 1.15 所示 如果多台 Se er
组成-个服务集群,那么必须有 个“总 ”知道 集群中每台 机器的服务状态
一旦有 机器 能提供服 务,就 必须知 会集群中 集群,并重新分 配服 务策略
样,当集群 的服务能力 加时,就 会增 一台或多台 Server ,这些也必须让“总管”
知道
16 /
/
/
~
/
/
/
仅供非商业用途或交流学习使用
1 构建大型网站:分布式改造
Re 险,.,
cli ~
Clien t3
.15 集群管理结构图
Zoo Keeper 不仅能够维护当前集群中机器的服务状态,而且能够选出 个“总 管”,
让“总管”来管理集群一一这就是 Zoo Keeper 的另 个功能 Leader Election
它的实现方式是在 Zoo Keeper 上创建 EPHEMERAL 类型的目录节点,然后
每个 Server 在它们创建目录节点的父目录节点上调用 getChildren( String path , Boolean
watch )方法并设置 watch true 由于是 EPHEMERAL 目录节点,当创建它的 Server
死去时,这个目 录节点 也随之被删除,所以 Children 会变 化;这时· getChildren 上的
Watch 将会被调用,通知其他 Server 某台 Server 已死了 新增 rver 也是同样的原理
那么, Zoo Keeper 如何实现 Leader Election ,也就是选出 Master Server 呢?
和前面的 一样,每台 Server 创建 EPHEMERAL 录节点,不同的是它还是一个
SEQUENTIAL 目录节点,所以它是个 EPHE RAL_SEQUENT 目录节点 之所以
它是 EPHEMERAL_ SEQUENTIAL 目录节点,是因为我们可以给每台 Server 编号
我们可以选择当前最小编号的 Server Master ,假如这个最小编号的 Server 死去,由
于它是 EPHEMERAL 节点,死去的 Server 对应的节点也被删除,所以在当前的节点
列表中又出现一个最小编号的节点,我们就选择这个节点为当前 Master 这样就实现
了动态选择 Master ,避免传统上单 Master 容易出现的单点故障问题
2. 共享锁( Locks)
在同 个进程中,共享锁很容易实现,但是在跨进程或者不同 Server 的情况下就
不好实现了 然而 Zoo Keeper 能很容易地实现这个功能,它的实现方式也是通过获得
锁的 rver 创建 EPHEMERAL_ SEQUENTIAL 目录节点,再通过调用 getChildren
方法,查询当前的目录节点列表中最小的目录节点是否是自己创建的目录节点,如果
是自己 创建的,那么它就 获得了这个锁;如果不是,那么它就调用巳 ists(String path,
17 大型网站技术架构演进与性能优化
Boolean watch )方 法,并监控 ooKeeper 上目 节点列 化, 直到使自己 建的节
点是列表中最小编号的目录节点,从而获得锁 。释 放锁很简单,只要删除前面它自己
所创建的目录节点即可,如图 1.16 所示
要获得锁的 lient
L =c rea te (/Locks/
i
Lock_i,EP 阻脏 RAL_SEQUENTIAL) I
不存在
1.16
ZooKeeper 实现共享锁的流程图
3. 队列管理
Zoo Keeper 可以处理以下两种类型的队列
其一,同步队列 即当一个队列的成员都聚齐时,这个队列才可用,否则一直等
待所有成员到达
其二,队列按照 FIFO 方式进行人队和出队操作,例如实现生产者和消费者模型
Zoo Keeper 实现同步队列的实现思路如下
创建 个父目录/ synchronizir 毡,每个成员都监控标志( Set Watch )位目录
synchronizing/start 是否存在,然 个成员都加入这个队列;
加入队列的方式就是创建 ynchronizing member 的临时 目录节点,之后每个
成员获取 synchronizing 目录的所有目录节点,也就是 member i;
18 1 构建大型网站 分布式改造
判断 的值是否已经是成员的个数,如果小于成员个数等待/ synchronizing/start
的出现,如果已 经相等就创建/ synchronizing/start
我们用图 1.17 的流程图来直观地展示该过程
创建/ 尬。 nizing
exists (/syn chroru zi n g/s tart , true)
每个成员加入队列
create (/syn chroni z in g/
member _, EPHEMERAL _ SEQUENTIAL )
L=getChi ldren ( / synchronizi ng/
memb e r , false)
创建
I
./
._._
'
I . /.
~~
...
I
等待
create( synchronizing/r
陡刷、于成员个敛
>一
~exists
watc 通知
start, EPHEMERAL)
I
~
'
'
. 17 同步队列流程图
Zoo Keeper 实现 FIFO 队列的思路如下
在特定的目录下创建 SEQUENTIAL 类型的子目录/ queue_i ,这样就能保证所有成
员加入队列时都是有编 号的 ;出队列时通过 getChildren ()方 法返回当 前所有队列中的
素,再消费其 中最小的 个,这样就能保证 FIFO
1.10 分布式消息通道服务的设计
分布式消息通道广泛应用在很多公司,尤其是在移动 App 和服务端需要上传、推
送大 的数据和消息时 比如打 pp 每天要上传大量的 置信息, 端也有很
订单 要及 时推送给司机;此外,由于司机是在 高速移动 过程中,所以网络连接的稳定
性也不 是很好一一 这类场 景给消息通 道的 高可 用设计带来很 的挑战
19 大型网站技术架构演进与性能优化
如图 1.18 所示是 个典型的移动
App 的消息通道的设计架构图,这种设计比较
适合上传数据量大,并且高速移动导致网络不太稳定的链路
-
飞/ νJ
1.1 分布式消息通道设计
链路 li 和整个服务端的长连接链路,一般采用私有协议的 TCP 请求
果是第一次请求还会通过 做链接认证,认证通过后会把该 ient 和接人集群的某个
服务器做个 KN 对,并记录到路由表里 一一 这可以方便下发消息时找到该链接
经过链路 ,上行消息处理集群会将 TCP 请求转成普通的 HTTP 请求,再调用后
端业务执行具体的业务逻辑,或者只是上传一个数据而己,不做任何响应 如果业务
有数据需要下发,会经过链路 ,把消息推送到消息下发处理集群,由它 消息推送
lient
消息下发集群会查询链接路由表,确定当前 Clie nt 链接在哪台机器上,再通过
该服务器把消息推送下去 这里常见的 问题 是当前 lient 的网 络不可达,导致消息元
法推送 在这种情况下,消息下发处理集群会保持该消息,并定时尝试再推送;如果
lient 重新建立连接 ,连接的服务器也会随之变化 那么消息下发 集群会去查 询链接
路由表再重新连接新的 KN
链路 是为了处理 li nt 端的一些同步请求而设计的 例如 lient 需要发送一个
HTTP 请求并且期 望能返回结果,这 Client 中的业务层可能 直接请求 TTP ,再经
Client 中的网络 模块转成私有 TCP 协议,在上行长链请求 集群转成 HTTP 请求,调
用后端业务并将 HTTP response 转成消息发送到消息下发处理集群,异步下发给
lient ,到达 li nt 再转成业务的 HTTP response 这种设计的主要考虑是当 HTTP
应返回时,如果长链已经断掉,该响应就没法再推送回去 ,这种上行同步请求
20 构建大型网站:分布式改造
而下行异步推 送是一种更高可用的设计
从整体架构上看,只有接入集群是有状态的,其他集群都是元状态的,这也保证
了集群的扩展性 如果接人点在全国有多个点,并且这些点与服务端有专线网络服务,
接入集群还可以做到就近接入
典型的分布式集群设计思路
前的分布式集群管理中通常有两种设计思路: 种是 Maser Slaver 模式(如图
1.19 所示); 种是无对等的设计思路(如图 1.20 所示) 两种思路各有优缺点
1.11
如图 19 示是一个典型的 Mase Slaver 模式的架构,它的优点是 Mast 节点
是固定集中式的,管理着所有其他节点,统 指挥 、统一 调度,所有信息的一致性都
由它控制,不容易出错,是一种典型的集权式管理 它的缺点也很明显: Master
挂了,整个集群就容易崩溃;另外,由于它控制了所有的信息,所以也容易成为性能
瓶颈
主主~ 固.一圈髓;
\
回回
种分布式集群设计
对等的集群管理模式中,最典型就是 Cassandra 的集群 管理 它的特点是每个节
点的功能都是 一样 的,所以每个节点都有能力成为 Master 节点 在一个集群中要实现
这一点,要求整个集群中所有机器的状态都要保持 一致, 那么 Cassandra 是如何做到
的呢? Cassandra 利用了 Gossip 协议(谣 协议): 一个节点 状态发生变化很快被传播
到机器中的所有节点,于是每个节点发生相应的变更 这种管理方式是通过节点之间
充分的信息交换来实现管理的,因此信息的及时、充分交互是必要前提 但这会导致
机器之间交互控制信息过 多,并且集群越大信息越多,管理越复杂,在出 bug
太容易排查
21
1 9 大型网站技术架构演进与性能优化
1.20
无主 Master 集群设计
下面我们以开源的 Tair 集群管理为例着重介绍 Maser/Slaver 的一种管理模式(如
1.21 所示),它的设计比较巧妙
一一一 一三
1.21
一种 aster/S laver 集群设计
群的架构上可以看出通常有 个角色: Client ConfigServer DataNode,
整个集群通过一个路由信息对照表来管理,如表 1-1 所示
Bucket
22
1-1
路由对照表
Node
192.168.0.1 1 构建大型网站 分布式改造
续表
Bu cket
Node
1
192. 1 68.0.2
2
192. 1 68.0 . 1
3
192.168 . 0 .2
4
19 2 . 1 68. 0 . 1
5
1 92. 1 68.0.2
Bucket Data Node 上数据管理的基本单位,通过 Bucket 可以将用户的数据划分
成若干个集合 1-1 中分成 cket ,那么所有用户的数据可以对 取模,这样
每条数据都会存储在其中的一个 cket 中,而每个 Bucket 也会对应 一台 DataNode
只要控制这张列表就可以控制用户数据的分布
ConfigServer DataNode 保持心跳,并根据 DataNode 的状态生成对照表, li ent
主动向 ConfigServer 请求最新的对照表并缓存 ConfigServer 最重要的责任就是维护
对照表,但从实际的数据交互角度看,它并不是强依赖 一一 正常的数据请求不需要和
ConfigServer 交互,即使 ConfigServer 挂掉也不会立即影响整个集群的工作 原因在
于对照表在 li ent 或者 Da aNo 上都有备份,因 Co figServer 不是传统意义上的
Mas er 节点,也就不会成为集群的瓶颈
下面介绍一下它们如何解决集群中的状态变更:扩容和容灾
( 1 )扩容
假如要扩容一台机器 19 2. 68. .3 么整个集群 对照表需要重新分配,而重新
分配对照表 然也会伴随着数据在 aN od 的移动 数据的重新分配必须基于
两个原 :尽可能地保持 有的对照关系,均衡地分布到所有节点上 新的对照表
1-2 所示
1-2 扩容的新对照表
Bucket
Node
192 . 16 8. 0 . 1
1
192 . 16 8. 0 . 2
2
1 9 2.16 8 .0 . 1
3
192 . 168 . 0 . 2
4
192.16 8. 0.3
5
1 92 . 168 . 0 . 3
时只需将 Buck et 数据移动到新机器上
23 大型网站技术架构演进与性能优化
( )容灾
容灾模式 比扩 容更复杂一些 ,除了上面两个 则以外 ,还需要考虑数据的备份情
假如保存了 份数据,则对照表如表 所示
1-3
容灾的新对照表
Bucket
Node
Node
Node
192.168.0.1
192.168.0.2
192.168.0.3
1
192 . 168.0.2
192 . 168.0.3
192 . 168.0.l
2
192 . 168.0.1
192.168 . 0.2
192.168.0.3
3
192.168.0.2
192.168 . 0.l
192 . 168.0.3
4
192 . 168.0.3
192.168 . 0.l
192.168.0.2
5
192.168.0 . 3
192.168.0.1
192 . 168.0 .2
列的 Node 作为主节点,如果主节点挂掉,那么第 列的备份节点就会升级
节点;如果备份节点挂掉则不会受影响,而是再重新分配 个备份节点以保证数
据的备份数
DataNo de 节点发生故障时, Co nfigServer 要重新生成对照表,并把新的对照表
同步给所有的 DataNode Client 是如何获取最新对照表的呢?每份对照表都有 个版
本号,每次 lient DataNode 请求数据时, DataNo de 会把自己对照表的版本号返
回给 Client ,如果 Client 发现自己的版本低,则会从 ConfigServer 拉取最新的对照表
这种方式会 产生一 个问题:当对照表发生变更时, Client 有可能会更新不及时导致请
求失败 为何 Co nfigServer 不把对 照表主动推送给 lient ?当然可以,但这会导致
ConfigServer 保持对 Client 的心跳,加 ConfigServer 的负担,尤其当 Client
量非常大 的时候,容易给 ConfigServer 造成 管理瓶颈 因此,上面的设计其实是取中
考虑,即在 Client 的数量和 DataNode 发生故障的概率之间选择一个
综上,集群管理中最大的困难就是当 DataNode 数量发生变化、涉及的数据发生
迁移时,既 要保 证数据的 致性,又要保证高可用
1.12 总结
网站的分布式化改造是非常重要的 步,从刚开始的单应用单层级的结构转换成
多应用多层级的分布式应用需要解决前面我们提到的众多问题,而最核心的是要解决
以下问题
24 构建大型网站 分布式改造
第一,纵 向业 务逻辅 的分 层拆分,要方便不 工种的程序开发人员的 协作,如前
端和后端开发人员的协作效率,业务开发人员与偏技术的中间件开发人员的分 工等
第二,横 同业 务系统的拆分,如商品和会员系统独立,交易与支 付系 统的独
立等 种拆分 更多是 务领域知识 业化,同时也为 系统 稳定性 和扩 展性提
更好的支持 般而 ,业务系统的拆分也会引起组织结构的
,系统的横 向和 纵向的拆分必须首先解决好系统之间的连接问题,而这些系
之间如何连接就是分布式系统必须解决的问题 本章主要介绍了在这些环节的一些
通用的解决办法
最后 我们用图 1.22 、图 1.23 来总结单应用系统向分布式系统演进的过程
用户
负载均衡
「~~- r• 噩噩噩- E!J
业务集群
回国-
敏据层
1.22 单应用集群架构
③雪
用户
踉据层
1.23 典型的分布式集群架构

你可能感兴趣的:(架构)