单点系统架构的可用性与性能优化

一、需求缘起

明明架构要求高可用, 为何系统中还会存在单点?

回答:单点 master 的设计,会 大大简化系统设计,何况有时候避免不了单点

在哪些场景中会存在单点?先来看一下一个 典型互联网高可用架构 。

典型互联网高可用架构:

( 1 ) 客户端层 ,这一层是浏览器或者 APP ,第一步先访问 DNS-server ,由域名拿到 nginx 的外网 IP

( 2 ) 负载均衡层 , nginx 是整个服务端的入口,负责反向代理与负载均衡工作

( 3 ) 站点层 , web-server 层,典型的是 tomcat 或者 apache

( 4 ) 服务层 , service 层,典型的是 dubbo 或者 thrift 等提供 RPC 调用的后端服务

( 5 ) 数据层 ,包含 cache 和 db ,典型的是主从复制读写分离的 db 架构

在这个互联网架构中,站点层、服务层、数据库的从库都可以通过冗余的方式来保证高可用,但至少

( 1 ) nginx 层是一个潜在的单点

( 2 )数据库 写库 master 也是一个潜在的单点

再举一个 GFS ( Google File System )架构的例子。

GFS 的系统架构里主要有这么几种角色:

( 1 ) client ,就是发起文件读写的调用端

( 2 ) master ,这是一个单点服务,它有全局事业,掌握文件元信息

( 3 ) chunk-server ,实际存储文件额服务器

这个系统里, master 也是一个单点的服务, Map-reduce 系统里也有类似的全局协调的 master 单点角色。

系统架构设计中,像 nginx , db-master , gfs-master 这样的单点服务,会存在什么问题,有什么方案来优化呢,这是本文要讨论的问题。

二、单点架构存在的问题

单点系统一般来说存在 两个很大的问题 :

( 1 ) 非高可用 :既然是单点, master 一旦发生故障,服务就会受到影响

( 2 ) 性能瓶颈 :既然是单点,不具备良好的扩展性,服务性能总有一个上限,这个单点的性能上限往往就是整个系统的性能上限

接下来,就看看有什么优化手段可以优化上面提到的两个问题

三、 shadow-master 解决单点高可用问题

shadow-master 是一种很常见的解决单点高可用问题的技术方案。

“ 影子 master” ,顾名思义,服务正常时,它只是单点 master 的一个影子,在 master 出现故障时, shadow-master 会自动变成 master ,继续提供服务。

shadow-master 它能够解决高可用的问题,并且故障的转移是自动的,不需要人工介入,但不足是它使 服务资源的利用率降为了 50% , 业内经常使用 keepalived+vip的方式实现这类单点的高可用 。

以 GFS 的 master 为例, master 正常时:

( 1 ) client 会连接正常的 master , shadow-master 不对外提供服务

( 2 ) master 与 shadow-master 之间有一种存活探测机制

( 3 ) master 与 shadow-master 有相同的虚 IP ( virtual-IP )

当发现 master 异常时:

shadow-master 会自动顶上成为 master ,虚 IP 机制可以保证 这个过程对调用方是透明的

除了 GFS 与 MapReduce 系统中的主控 master , nginx 亦可用类似的方式保证高可用,数据库的主库 master (主库)亦可用类似的方式来保证高可用,只是细节上有些地方要注意:

传统的一主多从,读写分离的 db 架构,只能保证读库的高可用,是无法保证写库的高可用的,要想保证写库的高可用,也可以使用上述的 shadow-master 机制:

( 1 )两个主库设置 相互同步的双主模式

( 2 )平时只有一个主库提供服务,言下之意, shadow-master 不会往 master 同步数据

( 3 )异常时,虚 IP 漂移到另一个主库, shadow-master 变成主库继续提供服务

需要说明的是,由于数据库的特殊性,数据同步需要时延,如果数据还没有同步完成,流量就切到了 shadow-master ,可能引起小部分数据的不一致。

四、减少与单点的交互,是存在单点的系统优化的核心方向

既然知道单点存在性能上限,单点的性能(例如 GFS 中的 master )有可能成为系统的瓶颈,那么, 减少与单点的交互,便成了存在单点的系统优化的核心方向。

怎么来减少与单点的交互,这里提两种常见的方法。

批量写

批量写是一种常见的提升单点性能的方式。

例如一个利用数据库写单点生成做 “ID 生成器 ” 的例子:

( 1 )业务方需要 ID

( 2 )利用数据库写单点的 auto increament id 来生成和返回 ID

这是一个很常见的例子,很多公司也就是这么生成 ID 的,它利用了数据库写单点的特性,方便快捷,无额外开发成本,是一个非常帅气的方案。

潜在的问题是:生成 ID 的并发上限,取决于单点数据库的写性能上限。

如何提升性能呢?批量写

( 1 )中间加一个服务,每次从数据库拿出 100 个 id

( 2 )业务方需要 ID

( 3 )服务直接返回 100 个 id 中的 1 个, 100 个分配完,再访问数据库

这样一来,每分配 100 个才会写数据库一次,分配 id 的性能可以认为提升了 100倍。

客户端缓存

客户端缓存也是一种降低与单点交互次数,提升系统整体性能的方法。

还是以 GFS 文件系统为例:

( 1 ) GFS 的调用客户端 client 要访问 shenjian.txt ,先查询本地缓存, miss 了

( 2 ) client 访问 master 问说文件在哪里, master 告诉 client 在 chunk3 上

( 3 ) client 把 shenjian.txt 存放在 chunk3 上记录到本地的缓存,然后进行文件的读写操作

( 4 )未来 client 要访问文件,从本地缓存中查找到对应的记录,就不用再请求 master 了,可以直接访问 chunk-server 。如果文件发生了转移, chunk3 返回 client 说“文件不在我这儿了”, client 再访问 master ,询问文件所在的服务器。

根据经验,这类缓存的命中非常非常高,可能在 99.9% 以上(因为文件的自动迁移是小概率事件),这样与 master 的交互次数就降低了 1000 倍。

五、水平扩展是提升单点系统性能的好方案

无论怎么批量写,客户端缓存,单点毕竟是单机,还是有性能上限的。

想方设法水平扩展,消除系统单点,理论上才能够无限的提升系统系统。

以 nginx 为例,如何来进行水平扩展呢?

第一步的 DNS 解析,只能返回一个 nginx 外网 IP 么?答案显然是否定的, “ DNS轮询”技术 支持 DNS-server 返回不同的 nginx 外网 IP ,这样就能实现 nginx 负载均衡层的水平扩展。

DNS-server 部分,一个域名可以配置多个 IP ,每次 DNS 解析请求,轮询返回不同的 IP ,就能实现 nginx 的水平扩展,扩充负载均衡层的整体性能。

数据库单点写库也是同样的道理,在数据量很大的情况下,可以通过水平拆分,来提升写入性能。

遗憾的是, 并不是所有的业务场景都可以水平拆分 ,例如秒杀业务,商品的条数可能不多,数据库的数据量不大,就不能通过水平拆分来提升秒杀系统的整体写性能(总不能一个库 100 条记录吧?)。

六、总结

今天的话题就讨论到这里,内容很多,占用大家宝贵的时间深表内疚,估计大部分都记不住,至少记住这几个点吧:

( 1 ) 单点系统存在的问题 : 可用性问题,性能瓶颈问题

( 2 ) shadow-master 是一种常见的解决单点系统可用性问题的方案

( 3 ) 减少与单点的交互 ,是存在单点的系统优化的核心方向,常见方法有 批量写,客户端缓存

( 4 ) 水平扩展 也是提升单点系统性能的好方案

如果有收获,帮忙随手转发哟。

==【完】==

http://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959480&idx=1&sn=337bd74410a6bef616128fd17abd08a8&scene=0&utm_source=tuicool&utm_medium=referral

posted @ 2016-07-20 13:32  欣欣点灯  阅读(215)  评论(0编辑  收藏  举报