香蕉云编原创发布日期:2019-6-22
今天要说的是,对于spring cloud的负载均衡我不使用zuul,而是使用nginx+spring boot(多tomcat实现)。
为什么不使用zuul呢?使用zuul确实方便了我们的开发,他集成了spring session,使得多个微服务之间可以共享session。但是,恰恰是因为这种机制,使得每个请求至少查询两次redis或多次redis,从而加重了redis的压力和系统的N个通信环节。
spring cluod 的session共享机制是这样的,zuul将sessionId的cookie传递到下一个微服务A,微服务A通过cookie值得出sessionId,然后根据sessionId查询redis,读取到所有的session值;当微服务A调用微服务B的时候,同样是将cookie传递到微服务B,微服务B通过同样的流程从redis得到所有的session值。也就是我们的微服务使用session前,我们的框架读取了两三次redis甚至更多。
这样redis可能就会成为了系统的瓶颈,因为每个请求上来都必须读写几次redis,无论从瓶颈或者延时来考虑,这种机制都有点不太好。在我的理解,微服务就应该只做微服务的工作,不应该有状态。不应该去管理session,管理session的工作,还是交给web层来实现,即使spring cloud的微服务是通过web服务来实现的。
我下面要说的框架是,在微服务之前前置一个spring boot的web服务网关,通过web服务来调用微服务。所有的session读写工作,都通过前置web层来实现。微服务需要用到的session值,在前置web层里读出来(比如验证码或用户ID),然后作为参数传递给下一级的微服务,微服务不再需要自己去redis读取session,而是从接口参数里面获取session。下面是我推荐的架构。
为了让web服务网关减少单点问题,采用多个tomcat web服务网关的方式来实现。避免web服务在高并发的情况下出现单点问题或者在系统维护的时候出现整个系统拒绝服务,为实现7*24的运行机制,采用多web服务的方式实现。多个web服务之间使用redis进行session共享
因为有了多个web服务,nginx的配置例子如下(重点部分代码,非全部代码):
http
{
upstream jiqun1 {
server 127.0.0.1:8080;
server 192.168.0.2:8080;
}
upstream jiqun2 {
server 192.168.0.2:8081;
server 192.168.0.3:8081;
}
server
{
location ~^/(images|Jquery)/ {
root /usr/local/tomcatxxx/webapps/ROOT/;
expires 60d;
}
location ~^/(css|js)/ {
root /usr/local/tomcatxxx/webapps/ROOT/;
expires 2d;
}
location ~^/(order)/ {
proxy_pass http://jiqun2;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
proxy_pass http://jiqun1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
上述代码表示,静态文件是nginx直接输出,/order二级目录路径则使用集群2的tomcat集群处理,其他的路径使用集群1处理。这样就可以指定不同的二级路径通过不同的集群处理,使系统解耦。
有很多人可能会问,现在机器的处理速度这么高,为什么前端web网关要拆分这么多的机器来处理呢?其实,即使单点处理速度能达到要求,一个高可用的系统,负载均衡还是必须的,一旦某个网关宕机,或者是需要做升级维护,我们只需要重启某个小项目即可。假如将所有的接口或页面都暴露在同一个web网关,那么一旦需要更新某个小功能,可能会导致整个系统重启。大部分优秀的门户网站更新的时候,用户是没有感觉到他们在更新。