9.1 负载均衡的原理
kong 为后端服务器节点提供了2种负载均衡策略,一种是直接基于dns的策略,另外一种是动态的环形均衡器策略,其中后者无需dns服务器
即可进行服务的注册与发现。
9.1.1 基于 DNS 的负载均衡
当服务中的host属性不能被解析为上游名称或此host属性的名称并不在本地的 DNS host 文件中,且服务中的host属性是名称而不是ip地址时,
kong会自动选择基于dns的负载均衡策略。
当使用基于dns的负载均衡策略时,后端服务的注册是在kong外部完成的,此时kong仅查询来自dns服务器的更新。在dns记录中,ttl决定了信息的
刷新频率。当将它设置为0时,表示每一次请求都会对dns服务器发起查询操作,这显然会有性能问题。
dns 主要有A记录和SRV记录两种解析方式,分别对应简单的负载均衡策略和加权轮询策略:
1.A记录
包含一个或者多个ip地址。因此,当域名解析为A记录时,每个后端服务必须具有自己独立的ip地址。又因为A记录没有附加权重信息,所以
所有的ip地址均按同等权重对待,我们称为简单常规的负载均衡策略。
2.SRV记录
包含ip地址的权重和端口信息。我们可以通过ip地址和端口的组合的方式来唯一标识一个后端服务,单个ip地址可以在不同的端口上托管同一
服务的多个实例。这不同于A记录,SRV记录有内置权重属性,所以每个ip地址和端口的组合都可以设置不同的权重值,称为加权轮询策略。
需要注意的是,任何本地指定的端口信息都将被dns服务器中的端口信息所覆盖。假设我们的服务的属性配置为 host=wwww.aa.com和port=123,但将
www.aa.com 域名进行 DNS解析的SRV记录为 127.0.0.1:456,此时如果采用SRV记录,则该请求将会被代理到 http://127.0.0.1:456,原来的123端口
会456所覆盖。
进行dns解析时,将按照下面的顺序进行:
1.上次成功解析的类型
2.SRV记录
3.A记录
4.CNAME记录
此顺序可以根据需要进行调整,具体可以通过kong配置文件中的 dns_order 属性来修改。
我们在进行dns解析时,还需要特别注意以下几点:
1.无论何时刷新dns记录,都会生成一个列表以正确处理权重信息。kong会尝试将多个权重值保持为彼此的倍数以保持算法的性能,例如将权重17
和31将生成具有527个条目的结构,而权重16和32(对应最小相对权重1和2)将生成只有3个条目的结构。
2.受udp数据包大小的限制,某些dns服务器不会返回所有条目,这样kong节点将仅能使用的dns提供的少数上游服务实例。这表明实际使用的与真实
的上游服务实例的数量可能不一样。因为dns提供的信息有限,所以kong节点不能全部接收并感知这些上游服务实例的存在。
3.当dns返回 3 name error时,这对于kong是有效响应。如果这是你未预期的响应,请先检查服务中host名称是否正确,再检查dns的配置。
4.首次从dns记录(A或SRV)中选择的ip地址不是随机的。因此,当ttl为0时,dns会随机化这些上游节点条目。
9.1.2 基于环形均衡器的负载均衡
当我们使用环形均衡器时,kong内部会自动管理所有的后端上游服务实例,并不需要外部dns。这里kong会充当服务注册中心的角色。你可以使用任何一个
kong节点的admin api或Konga,发起http请求来添加上游实例节点,然后这些节点将自动加入负载均衡器,呈立即启用状态,并接收来自外部的流量请求。
我们可以通过目标和上游节点实例对象来构建环形均衡器:
1.target
后端上游服务实例节点所在的ip地址/域名与端口的组合,例如 192.168.1.16:80。每个目标节点都有附加权重属性,它用来表示目标节点
上游服务实例可承受的相对负载,这里的ip地址可以采用ipv4或ipv6。
2.upstream
可以包含多个target,这些target共同组成一个"虚拟主机".例如,名为 www.a.com的上游主机将接收来自服务和路由中属性为 host =
www.a.com 的所有请求。
1.上游服务器的原理
每个上游对象都有自己的环形均衡器,都可以附加多个目标节点条目。当请求被代理到"虚拟主机"后,将在多个目标节点之间进行负载均衡。环形均衡器
内部具有预定数量的插槽,它们基于目标节点的权重创建,还将关联分配到上游服务的目标节点。
我们可以通过konga或者admin api的http请求来添加和删除目标节点,此操作相对轻量且成本较低。相反,如果我们修改了上游对象,则成本较高,
这是因为如果插槽发生了变化,环形均衡器就需要完全重建。另外,kong内部在清理目标节点的历史记录时也会自动重建环形均衡器,所以通常我们在通过
api操作时,会先删除再添加,以避免重建环形均衡器。
环形均衡器内部有位置信息,目标节点会根据槽的数量信息随机分布在环上,这种随机性使得它在运行时更轻量。另外,这些位置信息有助于提高一个
分布均匀且加权的轮询目标节点,并且使后期插入/删除目标节点时的开销更小。每个目标节点使用的槽的数量建议至少在100个,以确保槽能够被正确均衡的
分配。例如,如果预期最多有8个目标节点,但初期仅有2个,也需要将上游对象槽的数量至少定义为800。这样的规划和设置是为了使槽数量足够多,随机分布
更均匀,但是也不要太大,因为在添加/删除目标节点时,更改开销也会相对较大。
2.目标节点的原理
kong内部的上游对象因为维护着一个目标节点的变更历史记录,所以只能添加目标节点,而不能修改或者删除目标节点。如果要修改目标节点,只需为
它添加一个新目标节点条目,并更改权重值即可,而系统会将自动使用最后一个目标节点,并忽略以前的目标节点。如果将权重设置为0,则表示要禁用目标
节点,这意味着将会从环形均衡器中删除此节点,使之不在参与负载。kong内部会自动检测,当非活动的目标节点比活动的多10倍时,这些非活动的目标节点
将被自动清除。由于清除操作涉及重新构建环形均衡器,因此开销要比添加一个目标节点高。
目标节点可以是域名而非ip地址。在这种情况下,域名将被解析,被解析的所有条目都将添加到环形均衡器中。例如,添加权重为100的域名
www.a.com:123(假设有2个后端服务器),它将被解析为一个含有2个ip地址的A记录,然后这2个ip地址都将作为目标节点添加到环形均衡器中,并且每个
ip地址和端口的组合都有相同的权重值100.
如果域名被解析为SRV记录,那么kong将会从dns记录中获取端口和权重属性,并覆盖之前指定端口123和权重值100.
环形均衡器遵守dns记录的ttl设置,在过期时将会重新查询并更新均衡器。例外情况是:当dns记录的ttl等于0时,域名将作为单个目标节点添加设置,
并具有指定的权重,每个代理发出请求时,Kong都将再次查询dns服务器。
3.负载均衡策略的原理
在默认情况下,环形均衡器使用的是加权轮询策略。当然,我们也可以使用基于一致性散列策略。散列策略的输入值可以是 none,consumer,
header 和 cookie。
1.none
2.consumer
3.ip
4.cookie
散列策略有2个选项,一个是主选项,另外一个是主选项发生故障时的备用选项。一致性散列算法本质上是一个带虚节点的散列环形算法,此算法可确保
在更改目标节点(即修改环形均衡器,添加或者删除或者更改权重)时,只发生最小数量的散列损失,使上游缓存命中率最大化。另外,环形均衡器被设计成
既能在单个节点上工作,又能在集群中工作,这对于加权轮询来说,没有太大的区别。但是在使用基于散列的策略时,所有节点都必须构建完全相同的环形均衡器,以确保它们的工作行为完全相同。
9.2 健康检测的原理
9.2.1 健康检测的原理
健康检测功能的最终目的是动态的将目标节点标记为健康或者不健康。被最新标识的目标节点的健康情况并不会同步给kong集群中其他节点,即每个kong节点
各自判断其目标节点的运行情况。这是因为在Kong集群中,可能会出现一个集群节点成功的连接到了目标节点,而另外一个集群节点却无法连接的情况,这是第一个
集群节点将会把目标节点标记为健康,而另外一个集群节点则会将它的目标节点标记为不健康,请求的代理流量只会被路由到健康的目标节点。
无论是主动探测(针对主动健康检查)还是代理请求(针对被动健康检查),都会生成用于确定目标是否健康的数据,例如请求可能产生tcp错误,超时或者http
状态码等数据。kong基于这些数据,由健康检测器更新一系列内部计数器。
1.如果返回的状态码是监控状态码配置范围内的,那么为此目标节点增加success计数器,并清除所有其他计数器。
2.如果连接失败,那么为目标节点增加TCP failures 计数器,并清除success计数器。
3.如果超时,那么为目标节点增加 timeouts 计数器,并清除success计数器。
4.如果返回的状态码是不健康状态码配置范围内的,那么为此目标节点增加HTTP failures 计数器,并清除success成功计数器。
判断规则:
只要 TCP failures,HTTP failures 和 timeouts 这三个计数器中的任意一个达到了其配置的阈值,目标节点就会被标记为不健康。而如果
success计数器达到了其配置的阈值,目标将被标记为健康。
关于健康检查,需要注意的是:
1.健康检查仅对工作进程的目标节点进行操作,不会修改kong数据库中目标节点的状态;
2.不健康的目标节点不会从负载均衡器中移除,但是会被跳过,因此在使用散列算法时,不会对环形均衡器的结构和性能造成任何影响
3.如果使用dns域名作为目标节点,请确保dns服务器始终返回的是域名所对应的,完整的ip地址列表,并且不限制响应大小,否则很可能导致无法执行
健康监测
4.当由于dns问题而无法在环形均衡器中激活目标时,其状态将显示为 DNS_ERROR
5.当上游配置中未启用健康监测时,活动目标的健康状态显示为 HEALTHCHECKS_OFF
6.当启用健康监测并确定目标为健康状态时,其状态将显示为 HEALTHY,即健康状态。这意味着此目标在负载均衡器中会参与负载
7.当目标被主动或者被动健康监测(断路器)或手动禁用时,其状态将显示为 UNHEALTHY,即不健康状态。这意味着目标在负载均衡器中不会参与负载。
9.2.2 健康检测的类型
1.主动健康检测
当上游实体启用主动健康监测时,kong将定期向每个目标节点所配置的路径发出http或者https请求。
2.被动健康监测
也称为断路器,因为这是基于当前用户正在代理的请求而执行的健康监测,不会产生额外的流量。
当不健康的目标节点的问题被解决并再次准备接收流量时,kong 管理员可以通过admin api 手动通知检测器再次启用目标:
curl -i -X POST http://localhost:8001/upstreams/www.a.com/targets/192.168.1.20:9000/healthy
HTTP/1.1 204 No Content
此命令将会在整个集群范围内发出广播消息,将目标节点的健康状态传播到整个kong集群,kong节点收到此广播消息后,将重置所有工作进程正在运行的
健康检测器中的健康计数器,从而允许kong再次将流量路由到恢复的目标节点。被动健康监测的优点是不会产生额外的流量,缺点是它们不能将不健康的目标
节点再次标记为健康的。因为"电路已经断开",所以需要系统管理员,手动开启。
总结,两类健康检查的优缺点:
1.主动可以做到,在环形均衡器中当目标节点恢复健康后自动重新启用,被动的不能。
2.被动健康监测不会产生额外流量,主动的会
3.主动健康监测需要一个已知的可以访问的url路径作为健康监测的探测端点(默认为/),被动不需要
4.为健康检测设置自定义探测端点。只要应用程序提供了此端点,健康监测就可以判断目标是否健康。此探测端点既可以服务于被动健康监测,也可以
服务于主动健康检查。
我们可以将主动和被动结合起来一起用。可以先由被动健康监测来探测目标节点是否健康,在它不健康时就禁用,之后再使用主动健康监测自动将其启用。
9.3 集群机制的原理
kong 集群允许我们横向扩展系统。所有的节点都指向相同的数据库,因此它们将共享相同的配置。指向同一数据库的Kong节点被归属为一个kong集群。
建立一个kong集群并不意味着客户端的流量立即会在所有的kong节点之间实现负载均衡,我们还需要在kong集群前面再部署一个前置负载均衡器,并以此在所有
可用的kong节点之间均匀的分配流量,比如LVS,HAProxy,Keepalived,F5等。
出于对性能的考虑,kong在代理请求时会避免建立数据库连接,内部在启动的时候会预热,并将数据库的内容缓存在内存中。缓存的实体包括服务,路由,消费者,
插件和凭证等。kong 内部有集群传播机制,因此通过一个节点的admin api 进行的所有更改都会传播到其他节点。
9.3.1 单节点 Kong
连接到数据库的单个kong节点即单节点Kong,通过该节点的admin api 所做的任何更改都将立即生效。
9.3.2 多节点 Kong 集群
在多个节点的kong集群中,如果通过节点A删除了一个已注册的服务,那么与其连接到同一数据库的另一个节点B并不会立即生效。也就是说,虽然此服务已经
不在数据库中了,但是它可能仍然存在于B的内存中。kong内部会定期执行后台任务已保证各个节点的信息都会同步给其他节点,从而保证集群中各节点的数据一致
性,我们可以通过配置参数 db_update_frequency 来需改数据库的同步频率,该参数的默认值是5s。
每当经过 db_update_frequency 参数设置的时间后,所有运行中的 kong 节点就会轮询数据库是否已经有更新,并在必要时从其缓存中清楚相关实体。
如果我们从节点a中删除了一个服务,那么这个更改并不会立即在节点b中生效,而是直到节点b的下一次数据库轮询,它将在 db_update_frequency 时间后,
触发更改,kong 保证集群数据的最终一致性(CAP)。
不过值得注意的是,在 kong 的混合模式下,将通过控制平面和数据平面结合的方式,以websocket 策略机制自动实时下发变更信息至其他节点。
9.3.3 数据库缓存
我们可以在kong的配置文件中配置3个属性:
1.db_update_frequency(默认5s)
2.db_update_propagation(默认10s)
3.db_cache_ttl(默认0s)
9.4 缓存管理
最常用的缓存管理库有如下3种:
9.4.1 lua_shared_dict
共享内存词典。
lua_shared_dict 在内存中只有一份,占用空间少,支持的指令较多,在kong重新载入时数据不会丢失,但存在锁竞争。存取复杂的数据类型时,
需要进行序列化和反序列化操作。
9.4.2 lua-resty-lrucache
lua-resty-lrucache 是基于 LuaJIT FFI 的 LUR 缓存,因为lur缓存完全处于 Lua VM 的控制中,所以它不能跨出进程的边界进行多进程共享,
只能在当前的进程内使用,也不存在锁竞争。我们可以用它来缓存任意复杂的Lua对象,直接缓存不需要序列化和反序列化操作。
lua-resty-lrucache 中的每个工作进程都有一份数据,属于工作进程级别,支持更为复杂的数据类型存储,存取复杂数据类型时不需要序列化和反序列化,
不存在锁竞争,支持的指令较少,在kong重新载入时数据会丢失。
9.4.3 lua-resty-mlcache
lua-resty-mlcache 是基于前面所讲缓存的多级分层缓存,用来缓存,操作多层级缓存。
它有如下特点:
1.使用ttl进行缓存和负缓存
2.支持命中和未命中缓存的队列
3.使用 lua-resty-lock(互斥锁),可以防止当缓存未命中时,大量并发的请求对数据库或后端产生狗堆效应,引起缓存风暴
4.内置工作进程,可以在工作进程间传播失效的缓存信息,通知更新L1缓存中的数据
5.可以创建多个隔离的缓存实例,并依赖 lua_shared_dict L2 缓存来同时保存各种类型的数据
缓存级别的层次结构如下:
1.L1: lua-restry-lrucache。各个工作进程自己使用Lua VM 缓存区,采用最近最少策略,查询速度最快
2.L2: lua_shared_dict。所有工作进程共享的内存缓冲区,当L1未命中时才会使用。
3.L3: 一个自定义的回调函数,当L1和L2都未命中时使用。并发时仅有一个工作进程运行,其他工作进程则等待,避免对数据库/后端产生狗堆效应。
9.5 定时器
9.5.1 ngx.timer.at
在请求阶段,如果有些特殊的高延迟业务逻辑或非关键性逻辑需要运行,那么为了减少客户端等待的时间,不阻塞当前请求,我们可以创建一个零延时的
nginx.timer.at。在此定时器中进行后台处理,它将创建于当前请求完全分离的轻线程,并让两者互不影响,这种方式不会增加客户端请求的响应时间。语法
如下:
hdl, err := ngx.timer.at(delay, callback, user_arg1, user_arg2 ...)
9.5.2 ngx.timer.every
ngx.timer.every 用于周期性的执行某些业务逻辑,如周期性的从数据库刷新数据至本地缓存,检查数据是否正确等。它一般放在
init_work_by_lua_block 阶段,并且通过设置指定的工作进程(ngx.worker.id)或者共享内存词典设置锁的方式来限定同一时刻只有某个工作进程来运行
它。如果做的原因是服务器通常是多核的,ngx.timer.every 将与每个核进行绑定,所以每个核的工作进程都会运行它,我们要避免。语法如下:
hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2 ...)
9.5.3 参数控制和优化
1.lua_max_running_timers
2.lua_max_pending_timers
9.6 进程管理
进程分类:
1.主进程
不处理任何用户请求,仅对信号进行响应,主要用于读取和加载配置信息,启动控制工作进程等。
2.工作进程
用于对外处理用户的连接请求,接收来自主进程的信号。
3.单进程
创建生命周期并且对外处理客户端的连接请求,仅用于开发调试。
4.辅助进程
有两种---缓存管理进程和缓存加载进程,用于缓存管理。
5.信号进程
用于向工作中的进程发送信号。
6.特权代理进程
由OpenResty创建,不对外处理客户端的连接请求,继承主进程,有设置权限,控制,重载等功能。
9.6.1 主 / 工作进程
nginx 采用了主进程与工作进程池的事件驱动机制,即多个工作进程从属于一个主进程,多个工作进程共同构成一个进程池。主进程管理多个进程池,
它负责处理系统信息,加载配置,管理工作进程的生命周期(包括工作进程的启动,停止,重启,监控),读取验证配置和绑定端口等。
被主进程创建出来的多个工作进程彼此平等且独立,工作进程对外接收客户端用户请求,然后采用并行非阻塞策略处理这些请求,具体包括处理网络
请求,读取请求,解析请求,处理请求,与上游服务器通信,读取和写入内容到磁盘等。
9.6.2 单进程
在单进程模式下,nginx启动后,全局就一个进程,需要设置 master_process 为off,它负责处理所有工作,包括网络连接,读取请求,解析
请求,处理请求,与上游服务器通信等。该模式一般只在开发和调试阶段使用。
9.6.3 辅助进程
辅助进程用来管理缓存。缓存加载进程在启动时运行,把基于磁盘的缓存元数据信息加载到内存中,然后退出。缓存管理进程周期性的运行,用于削减
磁盘缓存中的文件数量,以使其使用量保持在配置范围内。
9.6.4 信号进程
信号进程用于关闭,重启等操作,即由它向正在工作的工作进程发送信号。主要有4种信号:stop,quit,reload和reopen。
stop 发送 SIGTERM 信号,表示强制要求退出;quit 发送 SIGQUIT 信号,表示 "优雅的"退出。两者的区别在于,sigterm 信号是直接关闭
进程,而 sigquit 信号则会先关闭监听的套接字(socket),关闭当前的空连接,然后处理所有的定时器时间等,最后才退出。
reload 向主进程发送 SIGHUP 信号,当主进程收到该信号后,会先重新加载配置文件,解析配置文件,申请共享内存等,然后启动全新的工作进程,
之后再向所有的旧进程发送 SIGQUIT 信号,那么新的请求将由新的工作进程接收并处理,旧的工作进程则会处理完当前已经接收到的请求再关闭,整个
过程用户是无感知的。
reopen 向主进程发送 SIGUSR1 信号,当主进程收到该信号后,会重新打开所有已经打开的文件,然后向每个工作进程发送此信号,当工作进程收到
该信号后,会执行与主进程同样的操作。reopen 可用于日志切割。
9.6.5 特权代理进程
特权进程是 OpenResty 1.11.2.5 提供的新功能,通过 procss_module.enable_privileged_agent() 在 init_by_lua 阶段启动。在
默认情况下,nginx/openresty 以 root 权限启动主进程,然后以指定的普通用户权限启动工作进程。如果需要重新加载或者启动,则必须使用root权限。
为了解决普通工作进程的特权问题,openresty 提供了一个特权代理补丁,结合定时器,共享内存可以实现远程重启等管理方面的特殊操作。
9.7 协程管理
lua-nginx-module 提供了3种API(ngx.thread.spawn,ngx.thread.wait 和 ngx.thread.kill)来管理协程。
9.7.1 ngx.thread.spawn
ngx.thread.spawn 用于产生新的用户轻线程,语法如下:
co = ngx.thread.spawn(func,arg1,arg2...)
其中,co表示此轻线程的Lua线程(协程)对象。ngx.thread.spawn 将生成新的轻线程,由ngx.lua模块管理调度,它是一种特殊的lua线程。多个轻
线程可以同时并发异步进行。需要注意的是,轻线程不是以抢占方式进行调度的,也不会自动执行时间片,而是在cpu上独占运行。
创建轻线程的对象称为父协程,轻线程的运行优先级比它的父协程要高,当它优先运行时,父协程会暂停运行。轻线程一旦运行起来,直到运行完毕返回或
出现了错误才会停止。
9.7.2 ngx.thread.wait
ngx.thread.wait 用于等待一个或者多个子轻线程,并返回第一个轻线程完成或者终止的结果。
ok,res1,res2 = ngx.thread.wait(thread1,thread2...)
9.7.3 ngx.thread.kill
ngx.thread.kill 用于杀死 ngx.thread.spawn 创建的正在运行的轻线程。只有父协程或者创建它的轻线程才能杀死子线程。此外,由于nginx核心的
限制,无法杀死正在运行且尚未完成nginx的子请求。
ok,err = ngx.thread.kill(thread)
9.8 Kong 参数优化
9.8.1 惊群效应
在linux3.9及以上的系统中,若在Kong中开启了 reuseport,则 qps(每秒查询率)将至少提高3倍左右甚至更多。reuseport 是一种套接字复用机制,
此选项允许主机上的多个套接字同时绑定到相同的ip地址/端口上,可以实现多个服务进程或者线程接收到同一个端口的连接,这种方式皆在提供在多核系统之上
运行的多线程服务器应用程序的性能和吞吐量。
原来的mutex锁这种技术的问题在于,如果有多个工作进程/线程 在accept()调用中等待,当有新连接建立时,对各个工作进程/线程的唤醒是不公平的,
会导致惊群效应出现。在高负载下,这种不均衡会导致cpu内核的利用率不足。虽然可以通过增加锁的方式来解决,但这样由于有锁竞争又会导致性能下降。相比
之下,采用reuseport 方式后,SO_REUSEPORT 连接均匀的分布在同一端口,在内核层面实现了cpu之间的均衡处理,这样当有新连接建立时,内核只会唤醒
一个进程/线程,并且保证每次唤醒的均衡性。
开启 reuseport,vim /etc/kong/kong.conf,定位到 nginx 节:
proxy_listen = 0.0.0.0:80 reuseport 0.0.0.0:443 reuseport
9.8.2 参数优化
参数优化主要针对工作进程的优化,对客户端与kong服务器端之间的长连接的优化,对kong服务器与上游服务器之间的长连接优化,对linux最大进程和
最大文件打开数量的优化以及对linux操作系统tcp连接参数的优化。
9.9 Kong 与 HTTP2
http2 的特性:
1.基于google的开源协议
2.二进制协议,数据分帧传输
3.多路复用,单个连接可以同时发起多个请求
4.流量控制,避免窗口拥塞
5.独有的HPACK(头部压缩算法),以压缩冗余的头部信息
6.服务端推送,服务器可以主动向客户端发送信息
7.为请求划分优先级,会更快响应高优先级的请求
8.支持全双工通信,服务器端与客户端可以同时双向通信
vim /etc/kong/kong.conf :
proxy_listen = 0.0.0.0:80 reuseport backlog=16386, 0.0.0.0:443 ssl http2 reuseport backlog=16384
9.10 Kong 与 WebSocket
很多站点都实现了自己的推送技术,所用的技术大都是ajax轮询或者长轮询。
长轮询的原理跟 ajax 轮询非常相似,也是采用轮询的方式,但不同的是它采用了阻塞模型。也就是说,在客户端发起连接后,如果服务端没有新消息返回,
则当前建立的连接就会被挂起在服务端并继续等待,直到服务器有消息才返回;如果在设定的超时时间内服务端依然没有返回,那么此连接就会断开,然后客户端继续
发起新连接的请求,并且返回如此。这利用了http1.1 的长连接特性以保持连接不断。这种方式的弊端也很明显,那就是当用户够多时,有大量空闲的连接被挂起,
服务端需要维护这些连接的状态,这会占用资源,影响性能。
websocket 是一种应用层的新协议,在与服务端握手的请求中,会在http的基础上多出两个请求头:Upgrade=websocket(升级为websocket协议)和
Connection=Upgrade(连接需升级),之后服务器返回101,表示连接建立成功,此连接建立在tcp连接之上,实现了客户端与服务端之前的全双工双向异步通信,
使得客户端和服务端之间的数据交换变得简单,快速。
9.11 Kong 与 gRPC
gRPC 是由 google 提供的一个高性能rpc通信开源框架,面向移动应用开发并基于http2协议标准设计。它使得应用程序可以轻松的互相通信,当客户端访问
服务端时,遵守从服务契约,数据契约模型,客户端就像本地程序一样调用服务端提供的服务。gRPC使用了高效的二进制消息格式 protobuf 对消息进行序列化操作,
二进制组帧和压缩技术使传输数据变得更小,这让发送和接收过程简捷高效。
9.12 Kong 与 LVS
9.12.1 基本概念
负载均衡分类:
1.二层负载均衡(MAC)
工作在链路层。负载均衡器对外提供一个VIP(虚拟ip地址),同一集群中的不同节点虽然采用相同的ip地址,但它们的MAC地址不同。当负载
均衡器接收到客户端请求后,通过改写请求报文中的目的MAC地址将请求转发到实际的目标服务器,而MAC地址采用的正是用来标识同一链路中不同
服务器的一种标识码。
2.三层负载均衡(IP)
负载均衡器对外提供一个VIP,集群中各节点的ip地址各不相同。当负载均衡器接收到来自客户端的请求后,根据不同的负载均衡算法和策略,
为这些请求分配实际的目的ip地址,通过该ip地址将请求转发到实际的目标服务器。
3.四层负载均衡(TCP/UDP)
在三层负载均衡器的基础上,不仅包含源ip地址和目的ip地址,还包含源端口和目的端口。四层负载均衡器在接收到客户端请求之后,通过修改
报文中的地址信息,即修改目的ip地址和目的端口,将请求转发到实际的目标服务器。
4.七层负载均衡(HTTP/FTP)
根据应用提供的信息进行负载均衡,即除了可以根据ip地址和端口进行负载均衡之外,还可以根据数据包中的应用信息(如域名,路径,参数,
请求头和请求体等)决定实际的目标服务器。
LVS:
LVS体系之所以高效,本质上是利用了 tabples(netfilter)的四表五链机制,直接对数据链路层报文,ip报文和tcp报文进行过滤,修改或者
封装。具体过程如下:
1.客户端向调度器发起请求,调度器将这个请求发送至内核
2.PREROUTING 链会首先接收到用户请求,通过判断,在确定请求报文的目的ip地址是本机ip地址后,将请求报文发往 INPUT 链
3.当请求到达 INPUT 链后,调度器通过判断报文中的目的端口来确定这个访问是不是要访问集群,如果是,就强制修改这个报文的目的ip地址,
然后将报文发往 POSTROUTING 链。
4.POSTROUTING 链接收到报文后,如果发现目的ip地址正是自己所需的后端服务器,那么通过选路,将报文发送给最终的后端服务器。
LVS组成:
由两部分组成:
1.IPVS (IP虚拟服务器)
它实现了第四层的负载均衡调度算法,运行在内核态,在真实的服务器集群前面充当均衡器。它可以基于tcp和udp的服务请求转发到
真实的服务器上。
2.ipvsadm
LVS的管理工具,运行在用户态并提供用户操作命令接口,负责管理LVS的配置,为IPVS编写规则并配置管理虚拟服务器以及真实服务
集群。
Keepalived:
是基于 VRRP(虚拟路由冗余协议)实现的服务高可用方案,可以利用它来避免ip单点故障。Keepalived的目的是模拟路由器的高可用性,常用的
前端高可用组合的有 lvs+Keepalived,nginx+Keepalived,HAProxy+Keepalived。
9.12.2 LVS 的三种模式
DS :Director Server,lvs负载均衡器
RS :Real Server,后端真实的服务器
VIP : DS 暴露在外部直接面向用户请求的虚拟目的ip地址
DIP :Director Server IP,DS 用于和内部真实服务器通信的ip地址
RIP :Real Server IP,后端真实服务器的ip地址
CIP :Client IP,客户端的ip地址
1.NAT 模式
先是客户端远程调用DS,DS 通过改写请求报文中的第三层(网络层)完成ip地址的映射转换,并且重写报文的目的IP地址(或第四层/传输层的端口);
然后DS根据配置中预先设置好的负载均衡策略算法,将请求再分配给RS,RS响应报文处理后,再把响应结果返回给客户端的过程中必须经过DS,经过DS时
报文的源地址又会被重写为之前的VIP,之后返回给客户端。
2.DR 模式
DR 模式是通过改写请求报文中第二层(数据链路层)的目的MAC地址将请求直接发送给RS,RS处理之后,将响应结果直接返回给客户端,而不必再RS。
DR技术可以极大的提高集群系统的并发处理能力,但同时也要求DR与RS必须在同一个物理网段,不可以跨越子网环境。
3.TUN 模式(IP隧道模式)
TUN 模式 与 DR 模式完全不同,DR模式是基于现有的数据报文重写的,而TUN 模式是基于ip隧道的,后者重新封装了数据报文。Ip隧道是将一个
完整的ip报文重新封装成另外一个ip报文,并通过路由器转发到指定的地点。在这个过程中,路由器并不在意被封装的原始协议的内容,因为原始协议只是
所传输报文的附加内容。在到达目的地后,目的服务器对ip隧道协议的支持会自己"解开"传过来的封装报文,并取得原始报文的协议数据。这种特殊的模式
就是为了跨子网传输而准备的。
9.12.3 LVS 负载均衡算法
9.12.4 Keepalived LVS Kong实践
LVS 有如下两种主备模式:
1.LVS + Keepalived 双机主备模式
2.LVS + Keepalived 双机主主模式
1.首先,在ip地址为 10.129.80.100 的 LVS 主服务器上安装 keepalived
2.接着,在ip地址为 10.129.80.101 的 LVS 备服务器上安装 keepalived
9.13 Kong 与 Consul
9.13.1 整体框架结构图
主要流程如下:
1.当微服务Traning.rest启动时,会自动向Consul集群或者客户端代理发送注册请求,并告知当前服务的IP地址,端口,服务信息及健康检查的
地址等信息。
2.Consul集群在接收到微服务Traning.rest的服务注册后,每个10s向此服务发送一次健康检查请求,以检验它是否处于健康状态
3.当客户端发送的业务请求经过LVS负载均衡器后到达Kong时,kong内部将使用dns协议,通过consul客户端从consule服务端中取得健康可用的
服务节点并缓存下来,之后将业务请求经过负载均衡器后转发到可用的上游服务器。
9.13.2 Kong Consul 实践
9.14 Kong 与 Kubernetes
kong 不仅可以用作 Kubernetes 的外置负载均衡器,还可以作为 Kubernetes 内部入口 Ingress 的负载均衡器。
9.14.1 基本概念
Kubernetes 中的 Ingress 公开了从集群外部到集群内部服务的http和https路由,路由的规则和策略在Ingress资源上定义,Ingress可以配置外部
可访问的url路由,负载均衡流量,ssl/tls,后端服务ip和端口以及基于域名的虚拟主机等,并结合Ingress Controller 将客户端请求路由至后端服务的pod。
Kong Ingress 自定义资源是对现有的 Kubernetes Ingress 的扩展,可以重新定义增加或者覆盖原有的Ingress行为,提供更为强大和细粒度的扩展机制。
9.14.2 安装 Kong Ingress Controller ..
9.14.3 验证 Kong Ingress Controller ..
9.15 Kong 的安全
9.15.1 通过 3 层或者 4 层网络控制 ..
9.15.2 Kong API 本地回环
9.16 火焰图
火焰图及其工具可以实时采集运行时调用堆栈的数据,直观展示各函数的调用关系,帮助我们快速定位性能问题。
9.16.1 概念
火焰的颜色没有特殊含义,只是表示cpu比较繁忙:
1.y轴表示调用栈,火焰越高,表示调用栈越深,其中每一层各代表一个单独的函数,顶部是当前正在运行的函数,下发则是它的父函数。
2.x轴表示采用的数量,而不是时间,是所有的调用栈合并后按字母顺序排列的。函数在x轴上占用的空间宽度越宽,表示采用的次数越多,执行时间也越长。
9.16.2 安装火焰图工具
9.16.3 生成火焰图