负载均衡知识总结前端
参考:mysql
微信公众号:架构师之路linux
什么是负载均衡nginx
负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它一般是指,将请求/数据【均匀】分摊到多个操做单元上执行,负载均衡的关键在于【均匀】。web
常见的负载均衡方案sql
常见互联网分布式架构如上,分为客户端层、反向代理nginx层、站点层、服务层、数据层。能够看到,每个下游都有多个上游调用,只须要作到,每个上游都均匀访问每个下游,就能实现“将请求/数据【均匀】分摊到多个操做单元上执行”。数据库
【客户端层->反向代理层】的负载均衡apache
【客户端层】到【反向代理层】的负载均衡,是经过“DNS轮询”实现的:DNS-server对于一个域名配置了多个解析ip,每次DNS解析请求来访问DNS-server,会轮询返回这些ip,保证每一个ip的解析几率是相同的。这些ip就是nginx的外网ip,以作到每台nginx的请求分配也是均衡的。后端
【反向代理层->站点层】的负载均衡浏览器
【反向代理层】到【站点层】的负载均衡,是经过“nginx”实现的。经过修改nginx.conf,能够实现多种负载均衡策略:
1)请求轮询:和DNS轮询相似,请求依次路由到各个web-server
2)最少链接路由:哪一个web-server的链接少,路由到哪一个web-server
3)ip哈希:按照访问用户的ip哈希值来路由web-server,只要用户的ip分布是均匀的,请求理论上也是均匀的,ip哈希均衡方法能够作到,同一个用户的请求固定落到同一台web-server上,此策略适合有状态服务,例如session(58沈剑备注:能够这么作,但强烈不建议这么作,站点层无状态是分布式架构设计的基本原则之一,session最好放到数据层存储)
4)…
【站点层->服务层】的负载均衡
【站点层】到【服务层】的负载均衡,是经过“服务链接池”实现的。
上游链接池会创建与下游服务多个链接,每次请求会“随机”选取链接来访问下游服务。
上一篇文章《RPC-client实现细节》中有详细的负载均衡、故障转移、超时处理的细节描述,欢迎点击link查阅,此处再也不展开。
【数据层】的负载均衡
在数据量很大的状况下,因为数据层(db,cache)涉及数据的水平切分,因此数据层的负载均衡更为复杂一些,它分为“数据的均衡”,与“请求的均衡”。
数据的均衡是指:水平切分后的每一个服务(db,cache),数据量是差很少的。
请求的均衡是指:水平切分后的每一个服务(db,cache),请求量是差很少的。
业内常见的水平切分方式有这么几种:
1、按照range水平切分
每个数据服务,存储必定范围的数据,上图为例:
user0服务,存储uid范围1-1kw
user1服务,存储uid范围1kw-2kw
这个方案的好处是:
(1)规则简单,service只需判断一下uid范围就能路由到对应的存储服务
(2)数据均衡性较好
(3)比较容易扩展,能够随时加一个uid[2kw,3kw]的数据服务
不足是:
(1)请求的负载不必定均衡,通常来讲,新注册的用户会比老用户更活跃,大range的服务请求压力会更大
2、按照id哈希水平切分
每个数据服务,存储某个key值hash后的部分数据,上图为例:
user0服务,存储偶数uid数据
user1服务,存储奇数uid数据
这个方案的好处是:
(1)规则简单,service只需对uid进行hash能路由到对应的存储服务
(2)数据均衡性较好
(3)请求均匀性较好
不足是:
(1)不容易扩展,扩展一个数据服务,hash方法改变时候,可能须要进行数据迁移
总结
负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它一般是指,将请求/数据【均匀】分摊到多个操做单元上执行,负载均衡的关键在于【均匀】。
(1)【客户端层】到【反向代理层】的负载均衡,是经过“DNS轮询”实现的
(2)【反向代理层】到【站点层】的负载均衡,是经过“nginx”实现的
(3)【站点层】到【服务层】的负载均衡,是经过“服务链接池”实现的
(4)【数据层】的负载均衡,要考虑“数据的均衡”与“请求的均衡”两个点,常见的方式有“按照范围水平切分”与“hash水平切分”
上一篇文章“一分钟了解负载均衡的一切”引发了很多同窗的关注,评论中你们争论的比较多的一个技术点是接入层负载均衡技术,部分同窗持这样的观点:
1)nginx前端加入lvs和keepalived能够替代“DNS轮询”
2)F5能搞定接入层高可用、扩展性、负载均衡,能够替代“DNS轮询”
“DNS轮询”到底是不是过期的技术,是否是能够被其余方案替代,接入层架构技术演进,是本文将要细致讨论的内容。
1、问题域
nginx、lvs、keepalived、f五、DNS轮询,往往提到这些技术,每每讨论的是接入层的这样几个问题:
1)可用性:任何一台机器挂了,服务受不受影响
2)扩展性:可否经过增长机器,扩充系统的性能
3)反向代理+负载均衡:请求是否均匀分摊到后端的操做单元执行
2、上面那些名词都是干吗的
因为每一个技术人的背景和知识域不一样,上面那些名词缩写(运维的同窗再熟悉不过了),仍是花1分钟简单说明一下(详细请自行“百度”):
1)nginx:一个高性能的web-server和实施反向代理的软件
2)lvs:Linux Virtual Server,使用集群技术,实如今linux操做系统层面的一个高性能、高可用、负载均衡服务器
3)keepalived:一款用来检测服务状态存活性的软件,经常使用来作高可用
4)f5:一个高性能、高可用、负载均衡的硬件设备(听上去和lvs功能差很少?)
5)DNS轮询:经过在DNS-server上对一个域名设置多个ip解析,来扩充web-server性能及实施负载均衡的技术
3、接入层技术演进
【裸奔时代(0)单机架构】
裸奔时代的架构图如上:
1)浏览器经过DNS-server,域名解析到ip
2)浏览器经过ip访问web-server
缺点:
1)非高可用,web-server挂了整个系统就挂了
2)扩展性差,当吞吐量达到web-server上限时,没法扩容
注:单机不涉及负载均衡的问题
【简易扩容方案(1)DNS轮询】
假设tomcat的吞吐量是1000次每秒,当系统总吞吐量达到3000时,如何扩容是首先要解决的问题,DNS轮询是一个很容易想到的方案:
此时的架构图如上:
1)多部署几份web-server,1个tomcat抗1000,部署3个tomcat就能抗3000
2)在DNS-server层面,域名每次解析到不一样的ip
优势:
1)零成本:在DNS-server上多配几个ip便可,功能也不收费
2)部署简单:多部署几个web-server便可,原系统架构不须要作任何改造
3)负载均衡:变成了多机,但负载基本是均衡的
缺点:
1)非高可用:DNS-server只负责域名解析ip,这个ip对应的服务是否可用,DNS-server是不保证的,假设有一个web-server挂了,部分服务会受到影响
2)扩容非实时:DNS解析有一个生效周期
3)暴露了太多的外网ip
【简易扩容方案(2)nginx】
tomcat的性能较差,但nginx做为反向代理的性能就强多了,假设线上跑到1w,就比tomcat高了10倍,能够利用这个特性来作扩容:
此时的架构图如上:
1)站点层与浏览器层之间加入了一个反向代理层,利用高性能的nginx来作反向代理
2)nginx将http请求分发给后端多个web-server
优势:
1)DNS-server不须要动
2)负载均衡:经过nginx来保证
3)只暴露一个外网ip,nginx->tomcat之间使用内网访问
4)扩容实时:nginx内部可控,随时增长web-server随时实时扩容
5)可以保证站点层的可用性:任何一台tomcat挂了,nginx能够将流量迁移到其余tomcat
缺点:
1)时延增长+架构更复杂了:中间多加了一个反向代理层
2)反向代理层成了单点,非高可用:tomcat挂了不影响服务,nginx挂了怎么办?
【高可用方案(3)keepalived】
为了解决高可用的问题,keepalived出场了(以前的文章“使用shadow-master保证系统可用性”详细介绍过):
此时:
1)作两台nginx组成一个集群,分别部署上keepalived,设置成相同的虚IP,保证nginx的高可用
2)当一台nginx挂了,keepalived可以探测到,并将流量自动迁移到另外一台nginx上,整个过程对调用方透明
优势:
1)解决了高可用的问题
缺点:
1)资源利用率只有50%
2)nginx仍然是接入单点,若是接入吞吐量超过的nginx的性能上限怎么办,例如qps达到了50000咧?
【scale up扩容方案(4)lvs/f5】
nginx毕竟是软件,性能比tomcat好,但总有个上限,超出了上限,仍是扛不住。
lvs就不同了,它实施在操做系统层面;f5的性能又更好了,它实施在硬件层面;它们性能比nginx好不少,例如每秒能够抗10w,这样能够利用他们来扩容,常见的架构图以下:
此时:
1)若是经过nginx能够扩展多个tomcat同样,能够经过lvs来扩展多个nginx
2)经过keepalived+VIP的方案能够保证可用性
99.9999%的公司到这一步基本就能解决接入层高可用、扩展性、负载均衡的问题。
这就完美了嘛?还有潜在问题么?
好吧,无论是使用lvs仍是f5,这些都是scale up的方案,根本上,lvs/f5仍是会有性能上限,假设每秒能处理10w的请求,一天也只能处理80亿的请求(10w秒吞吐量*8w秒),那万一系统的日PV超过80亿怎么办呢?(好吧,没几个公司要考虑这个问题)
【scale out扩容方案(5)DNS轮询】
如以前文章所述,水平扩展,才是解决性能问题的根本方案,可以经过加机器扩充性能的方案才具有最好的扩展性。
facebook,google,baidu的PV是否是超过80亿呢,它们的域名只对应一个ip么,终点又是起点,仍是得经过DNS轮询来进行扩容:
此时:
1)经过DNS轮询来线性扩展入口lvs层的性能
2)经过keepalived来保证高可用
3)经过lvs来扩展多个nginx
4)经过nginx来作负载均衡,业务七层路由
4、结论
聊了这么多,稍微作一个简要的总结:
1)接入层架构要考虑的问题域为:高可用、扩展性、反向代理+扩展均衡
2)nginx、keepalived、lvs、f5能够很好的解决高可用、扩展性、反向代理+扩展均衡的问题
3)水平扩展scale out是解决扩展性问题的根本方案,DNS轮询是不能彻底被nginx/lvs/f5所替代的
末了,上一篇文章有同窗留言问58到家采用什么方案,58到家目前部署在阿里云上,前端购买了SLB服务(能够先粗暴的认为是一个lvs+keepalived的高可用负载均衡服务),后端是nginx+tomcat。
5、挖坑
接入层讲了这么多,下一章,准备讲讲服务层“异构服务的负载均”(牛逼的机器应该分配更多的流量,如何作到?)。
零、需求缘起
第一篇文章“一分钟了解负载均衡”和你们share了互联网架构中反向代理层、站点层、服务层、数据层的经常使用负载均衡方法。
第二篇文章“lvs为什么不能彻底代替DNS轮询”和你们share了互联网接入层负载均衡须要解决的问题及架构演进。
在这两篇文章中,都强调了“负载均衡是指,将请求/数据【均匀】分摊到多个操做单元上执行,负载均衡的关键在于【均匀】”。
然而,后端的service有可能部署在硬件条件不一样的服务器上:
1)若是对标最低配的服务器“均匀”分摊负载,高配的服务器的利用率不足;
2)若是对标最高配的服务器“均匀”分摊负载,低配的服务器可能会扛不住;
可否根据异构服务器的处理能力来动态、自适应进行负载均衡及过载保护,是本文要讨论的问题。
1、service层的负载均衡一般是怎么作的
“一分钟了解负载均衡”中提到,service层的负载均衡,通常是经过service链接池来实现的,调用方链接池会创建与下游服务多个链接,每次请求“随机”获取链接,来保证service访问的均衡性。
“RPC-client实现细节”中提到,负载均衡、故障转移、超时处理等细节也都是经过调用方链接池来实现的。
这个调用方链接池可否实现,根据service的处理能力,动态+自适应的进行负载调度呢?
2、经过“静态权重”标识service的处理能力
调用方经过链接池组件访问下游service,一般采用“随机”的方式返回链接,以保证下游service访问的均衡性。
要打破这个随机性,最容易想到的方法,只要为每一个下游service设置一个“权重”,表明service的处理能力,来调整访问到每一个service的几率,例如:
假设service-ip1,service-ip2,service-ip3的处理能力相同,能够设置weight1=1,weight2=1,weight3=1,这样三个service链接被获取到的几率分别就是1/3,1/3,1/3,可以保证均衡访问。
假设service-ip1的处理能力是service-ip2,service-ip3的处理能力的2倍,能够设置weight1=2,weight2=1,weight3=1,这样三个service链接被获取到的几率分别就是2/4,1/4,1/4,可以保证处理能力强的service分别到等比的流量,不至于资源浪费。
使用nginx作反向代理与负载均衡,就有相似的机制。
这个方案的优势是:简单,可以快速的实现异构服务器的负载均衡。
缺点也很明显:这个权重是固定的,没法自适应动态调整,而不少时候,服务器的处理能力是很难用一个固定的数值量化。
3、经过“动态权重”标识service的处理能力
提问:经过什么来标识一个service的处理能力呢?
回答:其实一个service能不能处理得过来,能不能响应得过来,应该由调用方说了算。调用服务,快速处理了,处理能力跟得上;调用服务,处理超时了,处理能力颇有可能跟不上了。
动态权重设计
1)用一个动态权重来标识每一个service的处理能力,默认初始处理能力相同,即分配给每一个service的几率相等;
2)每当service成功处理一个请求,认为service处理能力足够,权重动态+1
3)每当service超时处理一个请求,认为service处理能力可能要跟不上了,权重动态-10(权重降低会更快)
4)为了方便权重的处理,能够把权重的范围限定为[0, 100],把权重的初始值设为60分
举例说明:
假设service-ip1,service-ip2,service-ip3的动态权重初始值weight1=weight2=weight3=60,刚开始时,请求分配给这3台service的几率分别是60/180,60/180,60/180,即负载是均衡的。
随着时间的推移,处理能力强的service成功处理的请求愈来愈多,处理能力弱的service偶尔有超时,随着动态权重的增减,权重可能变化成了weight1=100,weight2=60,weight3=40,那么此时,请求分配给这3台service的几率分别是100/200,60/200,40/200,即处理能力强的service会被分配到更多的流量。
4、过载保护
提问:什么是过载保护?
图示:无过载保护的负载与处理能力图(会掉底)
回答:互联网软件架构设计中所指的过载保护,是指当系统负载超过一个service的处理能力时,若是service不进行自我保护,可能致使对外呈现处理能力为0,且不能自动恢复的现象。而service的过载保护,是指即便系统负载超过一个service的处理能力,service让能保证对外提供有损的稳定服务。
图示:有过载保护的负载与处理能力图(不会掉底)
提问:如何进行过载保护?
回答:最简易的方式,服务端设定一个负载阈值,超过这个阈值的请求压过来,所有抛弃。这个方式不是特别优雅。
5、如何借助“动态权重”来实施过载保护
动态权重是用来标识每一个service的处理能力的一个值,它是RPC-client客户端链接池层面的一个东东。服务端处理超时,客户端RPC-client链接池都可以知道,这里只要实施一些策略,就可以对“疑似过载”的服务器进行降压,而不用服务器“抛弃请求”这么粗暴的实施过载保护。
应该实施一些什么样的策略呢,例如:
1)若是某一个service的链接上,连续3个请求都超时,即连续-10分三次,客户端就能够认为,服务器慢慢的要处理不过来了,得给这个service缓一小口气,因而设定策略:接下来的若干时间内,例如1秒(或者接下来的若干个请求),请求再也不分配给这个service;
2)若是某一个service的动态权重,降为了0(像连续10个请求超时,中间休息了3次还超时),客户端就能够认为,服务器彻底处理不过来了,得给这个service喘一大口气,因而设定策略:接下来的若干时间内,例如1分钟(为何是1分钟,根据经验,此时service通常在发生fullGC,差很少1分钟能回过神来),请求再也不分配给这个service;
3)能够有更复杂的保护策略…
这样的话,不但能借助“动态权重”来实施动态自适应的异构服务器负载均衡,还能在客户端层面更优雅的实施过载保护,在某个下游service快要响应不过来的时候,给其喘息的机会。
须要注意的是:要防止客户端的过载保护引发service的雪崩,若是“总体负载”已经超过了“service集群”的处理能力,怎么转移请求也是处理不过来的,还得经过抛弃请求来实施自我保护。
6、总结
1)service的负载均衡、故障转移、超时处理一般是RPC-client链接池层面来实施的
2)异构服务器负载均衡,最简单的方式是静态权重法,缺点是没法自适应动态调整
3)动态权重法,能够动态的根据service的处理能力来分配负载,须要有链接池层面的微小改动
4)过载保护,是在负载太高时,service为了保护本身,保证必定处理能力的一种自救方法
5)动态权重法,还能够用作service的过载保护
明明架构要求高可用,为什么系统中还会存在单点?
回答:单点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是一种很常见的解决单点高可用问题的技术方案。
“影子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)水平扩展也是提高单点系统性能的好方案
准备系统性介绍“技术体系规划”了,这是第一篇。
监控平台,服务治理,调用链跟踪,数据收集中心,自动化运维,自动化测试… 不少要讲,却没想好从哪里入手。
讲Z平台,可能须要提早介绍Y服务;讲Y服务,可能须要提早介绍X知识。
思来想去,准备从技术体系里,最容易被遗漏,很是基础,却又很是重要的“集群信息管理”开始介绍。
因为基础,可能部分同窗会以为简单;因为你们所在公司处于不一样阶段,因此在实现上会介绍不一样阶段的公司应该如何来实现。
仍是一如既往的按照“架构师之路”的思路:
是什么
什么场景,为何会用到,存在什么问题
常见方案及痛点
不一样阶段公司,不一样实现方案
但愿大伙有收获。
1、啥是集群?
互联网典型分层架构以下:
web-server层
service层
db层与cache层
为了保证高可用,每个站点、服务、数据库、缓存都会冗余多个实例,组成一个分布式的系统,集群则是一个分布式的物理形态。
额,好拗口,通俗的说,集群就是一堆机器,上面部署了提供类似功能的站点,服务,数据库,或者缓存。
如上图:
web集群,由web.1和web.2两个实例组成
service集群,由service.1/service.2/service.3三个实例组成
db集群,由mysql-M/mysql-S1/mysql-S2三个实例组成
cache集群,由cache-M/cache-S两个实例组成
与“集群”相对应的是“单机”。
画外音:关于高可用架构,详见文章《究竟啥才是互联网架构“高可用”》。
画外音:缓存若是没有高可用要求,多是单机架构,而不是集群。
2、集群信息
什么是集群信息?
一个集群,会包含若干信息(额,这tm算什么解释),例如:
集群名称
IP列表
二进制目录
配置目录
日志目录
负责人列表
画外音:集群IP列表不建议直接使用IP,而建议使用内网域名,详见文章《小小的IP,大大的耦合》。
何时会用到集群信息呢?
不少场景,特别是线上操做,都会使用到各类集群信息,例如:
自动化上线
监控
日志清理
二进制与配置的备份
下游的调用(额,这个最典型)
这些场景,分别都是如何读取集群信息的?
通常来讲,早期会把集群信息写在配置文件里。
例如,自动化上线,有一个配置文件,deploy.user.service.config,其内容是:
name : user.service
ip.list : ip1, ip2, ip3
bin.path : /user.service/bin/
ftp.path : ftp://192.168.0.1/USER_2_0_1_3/user.exe
自动化上线的过程,则是:
把可执行文件从ftp拉下来
读取集群IP列表
读取二进制应该部署的目录
把二进制部署到线上
逐台重启
画外音:啥,尚未实现自动化脚本部署?还处在运维ssh到线上,手动执行命令,逐台机器人肉部署的刀耕火种阶段?赶忙照着这个方案,作自动化改造吧。
又例如,web-X调用下游的user服务,又有一个配置文件,web-X.config,其内容配置了:
service.name : user.service
service.ip.list : ip1, ip2, ip3
service.port : 8080
web-X调用user服务的过程,则是:
web-X启动
web-X读取user服务集群的IP列表与端口
web-X初始化user服务链接池
web-X拿取user服务的链接,经过RPC接口调用user服务
日志清理,服务监控,二进制备份的过程,也都与上述相似。
3、存在什么问题?
上述业务场景,对于集群信息的使用,有两个最大的特色:
每一个应用场景,所需集群信息都不同(A场景须要集群abc信息,B场景须要集群def信息)
每一个应用场景,集群信息都写在“本身”的配置文件里
一句话总结:集群信息管理分散化。
这里最大的问题,是耦合,当集群的信息发生变化的时候,有很是多的配置须要修改:
deploy.user.service.config
clean.log.user.service.config
backup.bin.user.service.config
monitor.config
web-X.config
…
这些配置里,user服务集群的信息都须要修改:
随着研发、测试、运维人员的流动,不少配置放在哪里,逐步就被遗忘了
随着时间的推移,一些配置就被改漏了
逐渐的,莫名其妙的问题出现了
画外音:ca,谁痛谁知道
如何解决上述耦合的问题呢?
一句话回答:集群信息管理集中化。
4、如何集中化管理集群信息
如何集中化管理集群配置信息,不一样发展阶段的公司,实现的方式不同。
早期方案
经过全局配置文件,实现集群信息集中管理,举例global.config以下:
[user.service]
ip.list : ip1, ip2, ip3
port : 8080
bin.path : /user.service/bin/
log.path : /user.service/log/
conf.path : /user.service/conf/
ftp.path :ftp://192.168.0.1/USER_2_0_1_3/user.exe
owner.list : shenjian, zhangsan, lisi
[passport.web]
ip.list : ip11, ip22, ip33
port : 80
bin.path : /passport.web/bin/
log.path : /passport.web/log/
conf.path : /passport.web/conf/
ftp.path :ftp://192.168.0.1/PST_1_2_3_4/passport.jar
owner.list : shenjian, zui, shuaiqi
集中维护集群信息以后:
任何须要读取集群信息的场景,都从global.config里读取
任何集群信息的修改,只须要修改global.config一处
global.config会部署到任何一台线上机器,维护和管理也很方便
画外音:额,固然,信息太多的话,global.config也要垂直拆分
中期方案
随着公司业务的发展,随着技术团队的扩充,随着技术体系的完善,经过集群信息管理服务,来维护集群信息的诉求原来越强烈。
画外音:慢慢的,配置太多了,经过global.config来修改配置太容易出错了
如上图,创建集群信息管理服务:
info.db :存储集群信息
info.cache :缓存集群信息
info.service :提供集群信息访问的RPC接口,以及HTTP接口
info.web :集群信息维护后台
服务的核心接口是:
Info InfoService::getInfo(String ClusterName);
Bool InfoService::setInfo(String ClusterName, String key, String value);
而后,统一经过服务来获取与修改集群信息:
全部须要获取集群信息的场景,都经过info.service提供的接口来读取集群信息
全部须要修改集群信息的场景,都经过info.web来操做
长期方案
集群信息服务能够解决大部分的耦合问题,但仍然有一个不足:集群信息变动时,没法反向实时通知关注方,集群信息发生了改变。更长远的,要引入配置中心来解决。
配置中心的细节,网上的分析不少,以前也撰文写过,细节就再也不本文展开。
5、总结
集群信息管理,是架构设计中很是容易遗漏的一环,但又是很是基础,很是重要的基础设施,必定要在早期规划好:
传统的方式,分散化管理集群信息,容易致使耦合
集中管理集群信息,有全局配置,信息服务,配置中心三个阶段
6、调研
调研一、对于集群信息管理,你的感觉是:
ca,没考虑过这个问题,一直是分散式管理
在使用全局配置文件
在使用信息管理服务
在使用配置中心
调研二、对于自动化运维,你的感觉是:
ca,啥是运维,都是研发在线上乱搞
有专门的运维,但一直是人肉运维
运维在使用脚本,实现了自动化
运维都下岗了,在使用平台,实现了平台化