聊服务器集群,最初的出发点很简单,就是单台服务器扛不住访问压力。网站流量上涨,CPU跑满、内存耗尽,硬盘读写跟不上,很多人第一反应是换一台配置更强的机器。但高配硬件本身有性能上限,采购成本也极高,于是就换了思路,拿多台普通服务器用网络串联起来协同工作,对外整体表现如同一台设备,这就是集群。
集群基础概念
集群内每一台独立服务器被叫做节点,节点依靠高速网络互相通信。调度层负责分配用户请求,共享存储模块保证所有节点可以读取同一套数据。某个节点故障离线,调度程序就会把它手上的请求转移到其余正常节点,终端用户基本感知不到异常,也就是常说的高可用。访问请求持续增加,直接新增节点扩容,整体处理能力随之提升,即可扩展。高可用和可扩展,构成集群技术的两大基础,其余各类方案都是基于这两点延伸出来的。

集群不是简单网线把多台机器连在一起就能生效。节点之间要同步状态,选出主节点统筹协调,保证多节点的数据保持一致,这里面隐患不少。网络分区、主节点失联、数据冲突都是高频问题,所以集群体系内置各类协议与算法处理故障场景,Paxos、Raft、Gossip都属于这类。这些名字看着偏向学术,解决的却是现实问题:多台独立服务器,在没有绝对中心管控的前提下,如何达成统一状态。
各类集群应用场景
Web服务是集群最普遍的落地场景。大型网站的访问请求不会交给单台服务器处理,而是由一整个集群承载。负载均衡器放在最前端,把请求分发到后端几十甚至数千台Web服务器。空闲节点优先承接请求,响应速度更快的节点分配更多流量;一旦节点无响应,负载均衡检测到后就不再派发新请求。用户全程不会感知自己的请求交由哪一台服务器处理,也不需要关心这一点。
数据库集群是另一个核心场景。单库到达性能瓶颈,读写分离是最常规方案,一台主库承担写入操作,多台从库负责读取,主库的数据变更会同步下发给从库。读请求上涨就新增从库;写入压力过高,则需要分库分表。分库分表就是把一张超大数据表拆分成大量小表,分散存储到不同数据库实例,单实例承载的数据量下降,压力随之分摊。但拆分之后,跨库查询与事务会变得麻烦,需要在应用层编写额外代码适配。
缓存集群应用同样广泛,Redis、Memcached都原生支持集群模式,缓存数据分片存放于多个节点。单台缓存服务器内存容量有限,一旦宕机,整套缓存直接失效,全部请求会直接打到数据库,极易瞬间压垮数据库。使用集群之后,缓存分片存储,单个节点故障只会影响部分缓存数据,其余缓存条目依旧可以正常命中。
存储集群用来应对海量数据存储需求。单台服务器硬盘容量存在上限,一旦存储服务器硬件损坏,数据有丢失风险。分布式文件系统会将文件切分成数据块,分散存储在多台服务器,同时保存多份副本,HDFS、Ceph、GlusterFS都属于这类系统。上传文件时,系统自动完成切块,每一份数据块保存三份副本到不同机器,单台设备损坏,其余副本保留完整,数据不会丢失。
计算集群是完全不同的使用方向。Hadoop、Spark这类框架,把体量巨大的计算任务拆解成大量子任务,分发到集群内多台服务器并行运算,全部子任务跑完之后汇总最终结果。天气预报、基因测序、金融风控模型训练,这类需要海量算力的业务都依靠计算集群支撑。它和Web集群逻辑不一样,Web集群处理大量独立的小型请求,计算集群处理一个能够拆分的巨型任务。
容器集群是近些年兴起的类别,Kubernetes是代表性项目。它管理对象不是物理机或者虚拟机,而是容器。容器相比虚拟机更加轻量化,启动速度更快,单台物理机可以同时运行几十甚至上百个容器。Kubernetes负责调度容器的运行主机,容器崩溃自动重启,业务负载升高自动扩容。它将集群调度能力封装成API,开发者只需要声明业务需求,例如“运行该服务,保留三个副本”,剩下的调度工作由平台自动处理。
集群如今已经不是可选方案,大规模业务系统基本都会采用这种架构。单台服务器能够承载的业务规模存在明显天花板,但凡需要高可用、高并发、海量数据的场景,最后基本都会搭建集群。但集群架构本身会带来新麻烦,网络延迟、数据一致性排查、故障定位、成本管控都是实实在在的难题。选型搭建集群之前,先要定位系统瓶颈,确认是CPU资源不足、存储容量不够还是并发连接数受限,不同瓶颈匹配不同集群类型,盲目增加服务器无法解决所有问题。