我们该如何让代理将请求均衡至全部实例当中?答案是不用——我们并不需要执行特别的操作。
正常来讲,如果我们不使用Docker Swarm功能,则可使用以下配置方式:
backend go-demo-be server instance_1 <INSTANCE_1_IP>:<INSTANCE_1_PORT> server instance_2 <INSTANCE_2_IP>:<INSTANCE_2_PORT> server instance_3 <INSTANCE_3_IP>:<INSTANCE_3_PORT> server instance_4 <INSTANCE_4_IP>:<INSTANCE_4_PORT> server instance_5 <INSTANCE_5_IP>:<INSTANCE_5_PORT>
然而在新的Docker网络当中,我们将不再需要进行上述配置。原本的作法只会在新副本添加或者删除时,给我们的实例监控与代理更新工作造成麻烦。
现在,Docker会帮助我们完成全部负载均衡工作。更准确地讲,当该代理将某条请求重新定向至go-demo时,其实际将其发送至Docker网络并由后者执行跨越全部服务副本(实例)的负载均衡。这套方案的意义在于,代理负责将端口80(或者443)重新定向至网络中的正确服务处,其它任务则全部由Docker完成。
大家可以随意向该服务发送更多请求,并检查其中一套副本的日志记录。在这里,大家会发现其接收到的请求约为总体请求数量的五分之一——与我们的服务实例数量恰好吻合。
总结
Docker网络与Docker 1.12及更高版本提供的Swarm相结合,无疑开启了一道通向更多新机遇的大门。不同容器与负载均衡之间的内部通信只是其中的一小部分,我们亦可以更为轻松地配置公开代理。另外,我们需要确保面向API进行公开的全部服务皆以代理形式接入同一网络。在此之后,我们要做的就是进行配置以将所有请求重新定向至目标服务名称。这样所有来自代理的请求都将指向Docker网络,并由后者跨越全部实例执行负载均衡。
但新的问题在于,这套方案的具体效率是否理想。毕竟我们在体系中引入了新的层。尽管过去我们也会使用代理以及服务,但现在Docker网络会在二者之间建立负载均衡机制。答案是,由此带来的运行负担非常有限。Docker利用Linux IPVS实现负载均衡,其作为Linux内核的组成部分已经拥有超过15年历史,而且事实证明其是一种极为高效的负载均衡实现方式。事实上,其速度表现远远优于nginx或者HAProxy。
下一个问题是,我们是否需要代理机制。是的,当然需要。DOcker所使用的IPVS只负责实现负载均衡。我们还需要一套代理以接收来自端口80与443的请求,并根据其实际路径将其重新定向至各目标服务。在此基础之上,我们还可以利用它执行多种任务,包括SSL握手以及验证等等。
那么这种作法存在哪些缺点?首先想到的肯定是粘性会话。如果我们希望同一用户向同一实例发送请求,那么这套方案显然并不适用。另一个问题是,我们是否应当在服务之内实现粘性会话,或者应该将其作为独立实体。这个问题我们在本文中暂时不作讨论,只需要明确这里提到的方案并不适用于粘性会话即可。
那么其具备哪些优势?首先,整个实现过程非常简单。我们用不着在部署新副本时对代理进行重新配置。如此一来,整个流程将非常便捷。由于我们不需要包含全部端口IP及端口的列表,因此也就无需使用Registrator以及Consul Template之类的工具。过去,我们需要利用Registrator以监控Docker事件,并将IP及端口保存在键值存储方案(例如Consul)当中。信息存储完成后,我们会利用Consul Template重新创建代理配置。虽然不少项目都能简化这一流程,但Docker Swarm与Docker网格的再现从根本上降低了其实施难度。