需求背景
面对大量用户访问,多任务执行,系统负载会持续升高,目前共有三类解决方案
- 硬件升级:
CPU
升级,多核心,内存扩充,这一类纯粹靠资本,升级成本极高 - 软件层面:采用高效率开发语言,比如
C/Go/Rust
等底层开发语言,可以编译为操作系统直接执行的二进制文件,不像Java/Python
等解释型语言需要安装一个语言解释器,导致内存占用较大(尤其是Java
吃内存很严重),同时速度也不快 - 业务拆分与分布式:负载均衡,解决高并发访问与多任务执行问题,技术难度与硬件成本角度权衡较为均衡
负载均衡概述
将负载(前端的访问请求,后台执行的任务)进行平衡,通过负载均衡算法分摊到多个服务器上进行执行,是解决高性能,单点故障高可用,水平伸缩的终极解决方案
效果
- 增加吞吐量,解决高并发压力(高性能)
- 提供故障转移,解决单节点故障问题(高可用)
- 通过添加或减少服务器数量,提供网站水平伸缩性(扩展性)
- 网络入口安全防护,在负载均衡设备上做一些过滤,黑白名单等处理,最大程度上保证集群系统的安全性
负载均衡实现技术
负载均衡在OSI
网络层次中,层级越低,性能越好,但是技术复杂度也越高
DNS
负载均衡(七层负载均衡)
最早的负载均衡技术,利用域名解析实现负载均衡,在DNS
服务器,配置多个DNS
记录,这些记录对应的服务器构成集群,大型网站总是部分使用DNS
解析,作为第一级负载均衡
比如在不同网络环境下,ping baidu.com
命令执行获取到目标设备的IP
是不一样的
优点
- 简单:负载均衡工作交给
DNS
服务器处理,不需要专门的服务器维护 - 性能高:可以支持基于地址的域名解析,解析成距离用户最近的服务器地址,避免长链路网络传输,加快访问速度
缺点
- 可用性差:新增/修改
DNS
后,解析时间较长,域名DNS
服务器发生变更后,需要等待本地DNS
中域名DNS
服务器的TTL
缓存失效,本地DNS
才会重新发起递归查询,然后全国各地DNS
才能同步到最新的域名DNS
服务器名称,该过程需要一到两天的时间 - 扩展性低:
DNS
负载均衡的控制权在域名商,扩展性有限
Nginx HTTP
负载均衡(七层负载均衡)
可以使用配置实现
根据URL
、浏览器类别、语言来决定是否要进行负载均衡
优点
- 对网络稳定性的依赖非常小
- 承担高负载压力且稳定,在硬件不差的情况下一般能支撑几万次的并发量
缺点
- 仅能支持
http
、https
和Email
协议,在适用范围上面较小
LVS
负载均衡(四层负载均衡)
用Linux
内核集群实现的一个高性能、高可用的负载均衡服务器,具有很好的可伸缩性,可靠性和可管理性
四层负载均衡服务器在接受到客户端请求后,通过修改数据包的地址信息(IP
+端口号)将流量转发到应用服务器
优点
- 抗负载能力强,在负载均衡软件里的性能最强的,对内存和
cpu
资源消耗比较低 - 工作稳定,自身有完整的双机热备方案,如
LVS+Keepalived
,但是项目实施中用得最多的还是LVS/DR+Keepalived
- 无流量,
LVS
只分发请求,而流量并不从它本身出去,这点保证了均衡器IO
的性能不会收到大流量的影响 - 应用范围比较广,工作在
OSI
4层,所以它几乎可以对所有应用做负载均衡,包括http
、数据库、在线聊天室等等
缺点
- 软件本身不支持正则表达式处理,不能做动静分离
- 实施操作复杂,技术难度高
HAProxy
负载均衡(七层/四层负载均衡)
免费的负载均衡软件,可以运行于大部分主流的Linux
操作系统上,HAProxy
提供了四层(TCP)
和七层(HTTP)
负载均衡能力,具备丰富的功能
优点
- 支持
TCP
协议的负载均衡转发 - 支持
Session
的保持,Cookie
的引导,同时支持通过获取指定的url
来检测后端服务器的状态 - 支持虚拟主机的
- 支持负载均衡策略非常多
缺点
- 不支持
HTTP cache
功能 - 重载配置的功能需要重启进程
- 多进程模式支持不够好
IP
负载均衡(三层负载均衡)
负载均衡服务器对外依然提供一个浮动IP
,但集群中不同的机器采用不同的IP
地址,当负载均衡服务器接受到请求之后,根据不同的负载均衡算法,通过IP
将请求转发至不同的真实服务器,在网络层通过修改请求目标IP
地址进行负载
优点
- 在内核进程完成数据分发,比在应用层分发性能更好
缺点
- 所有请求响应都需要经过负载均衡服务器,集群最大吞吐量受限于负载均衡服务器网卡带宽
链路层负载均衡(二层负载均衡)
负载均衡服务器对外依然提供一个浮动IP
,配置真实物理服务器集群所有机器虚拟IP
和负载均衡服务器IP
地址一致,集群中不同的机器采用相同IP
地址,但机器的MAC
地址不一样,当负载均衡服务器接受到请求之后,通过改写报文的目标MAC
地址的方式将请求转发到目标机器实现负载均衡,达到不修改数据包的源地址和目标地址,进行数据分发的目的
优点
- 性能好
缺点
- 配置复杂
负载均衡算法
负载均衡器通过负载均衡算法决定请求转发到哪台设备
轮询
Round Robin
顺序循环将请求一次顺序循环地连接每个服务器,以轮询的方式依次请求调度不同的服务器;实现时,一般为服务器带上权重
优点:服务器请求数目相同;实现简单、高效;易水平扩展
缺点:服务器压力不一样,不适合服务器配置不同的情况;请求到目的结点的不确定,造成其无法适用于有写操作的场景
应用场景:数据库或应用服务层中只有读的场景
- 比率
Ratio
给每个服务器分配一个加权值为比例,根椐这个比例,把用户的请求分配到每个服务器
- 优先权
Priority
给所有服务器分组,给每个组定义优先权,当最高优先级中所有服务器出现故障,将请求送给次优先级的服务器组,这种方式,实际为用户提供一种热备份的方式
- 最少连接
将请求分配到连接数最少的服务器
优点:根据服务器当前的请求处理情况,动态分配
缺点:算法实现相对复杂,需要监控服务器请求连接数
- 最快模式
Fastest
传递连接给那些响应最快的服务器
观察模式
Observed
连接数目和响应时间这两项的最佳平衡为依据为新的请求选择服务器
- 预测模式
Predictive
利用收集到的服务器当前的性能指标,进行预测分析,选择一台服务器在下一个时间片内,其性能将达到最佳的服务器相应用户的请求
- 动态性能分配
Dynamic Ratio-APM
根据收集到的应用程序和应用服务器的各项性能参数,动态调整流量分配
- 动态服务器补充
Dynamic Server Act
当主服务器群中因故障导致数量减少时,动态地将备份服务器补充至主服务器群
- 服务质量
QoS
按不同的优先级对数据流进行分配
- 服务类型
ToS
按不同的服务类型(在 Type of Field
中标识)负载均衡对数据流进行分配
基于主机资源的系统负载均衡
前述所有负载均衡和算法策略,都是针对负载均衡器的,应用于短期执行任务(普遍是10秒或者1分钟这样短期内做出应答的服务),对于长期执行的任务,同时会消耗大量资源的负载均衡不是很适用于上面的负载均衡技术,最佳的解决方案是参考k8s pod
调度策略的基于主机资源的系统负载均衡(全球最强的超大规模集群编排解决方案,有着谷歌数十年的超大规模集群运维系统经验与验证,是集群编排技术的大一统)
k8s
调度器
在 Kubernetes
中,调度是指将Pod
放置到合适的节点上,以便对应节点上的 Kubelet
能够运行这些Pod
调度器通过 Kubernetes
的监测Watch
机制来发现集群中新创建且尚未被调度到节点上的Pod
, 调度器会将所发现的每一个未调度的Pod
调度到一个合适的节点上来运行
pod
调度步骤
过滤阶段:过滤阶段会将所有满足
Pod
调度需求的Node
选出来,例如,PodFitsResources
过滤函数会检查候选Node
的可用资源能否满足Pod
的资源请求,在过滤之后,得出一个Node
列表,里面包含了所有可调度节点;通常情况下,这个Node
列表包含不止一个Node
,如果这个列表是空的,代表这个Pod
不可调度执行的过滤规则
PodFitsHostPorts
:检查Node
上是否不存在当前被调度Pod
的端口,如果被调度Pod
用的端口已被占用,则此Node
被Pass
PodFitsResources
:检查Node
是否有空闲资源(如CPU
和内存)以满足Pod
的需求CheckNodeMemoryPressure
:对于内存有压力的Node
,则不会被调度Pod
CheckNodePIDPressure
:对于进程ID
不足的Node
,则不会调度Pod
CheckNodeDiskPressure
:对于磁盘存储已满或者接近满的Node
,则不会调度Pod
打分阶段:在过滤阶段后调度器会为
Pod
从所有可调度节点中选取一个最合适的Node
,根据当前启用的打分规则,调度器会给每一个可调度节点进行打分,最后,kube-scheduler
会将Pod
调度到得分最高的Node
上,如果存在多个得分最高的Node
,kube-scheduler
会从中随机选取一个打分规则
SelectorSpreadPriority
:优先减少节点上属于同一个Service
或Replication Controller
的Pod
数量InterPodAffinityPriority
:优先将Pod
调度到相同的拓扑上(如同一个节点、Rack
、Zone
等)LeastRequestedPriority
:节点上放置的Pod
越多,这些Pod
使用的资源越多,这个Node
给出的打分就越低,所以优先调度到Pod
少及资源使用少的节点上MostRequestedPriority
:尽量调度到已经使用过的Node
上,将把计划的Pods
放到运行整个工作负载所需的最小节点数量上BalancedResourceAllocation
:优先平衡各节点的资源使用