由Tomcat入手LVS+Nginx集群

相信学过javaEE的都做过几个web项目,将项目打包为war文件(或者直接在eclipse中),在Tomcat中发布即可通过浏览器访问。写这篇文章,争取表达最通俗的意思,由这个过程引到集群的概念,整明白现在用的几个热门的技术是做什么的,不求具体及其原理,包括LVS、Nginx、Keepalived、memcached。

(我也是刚起步学习,将现在的理解整理为一篇文章,略显浅显,如果有共同学习的读来可以当做入门,先明白这些东西是什么、有什么用,之后再去查阅更专业的资料。如果有地方理解错误,也请大佬们指正~)

Tomcat

我们刚开始学习web时,肯定接触tomcat比较多,以tomcat作为搭载一个web
项目应用的服务器。客户端向服务端发送Request,服务器端处理后返回Response。
由Tomcat入手LVS+Nginx集群_第1张图片


现出现情况一:
在一个时刻,同时1000个用户向服务器请求资源

情况分析:Tomcat的抗并发量在百数量级,就是说来几个百并发访问还可以应付一下,1000个并发来了,一个Tomcat肯定应付不过了,导致响应极慢甚至服务器崩溃。这就是接下来要考虑的抗并发问题


一昧的去提升服务器的硬件性能成本太高,况且Tomcat本身的也不是专门的抗并发服务,称为瓶颈。既然纵向提高单台服务器的性能有局限性,那为何不横向的增加服务器的数量呢?

假设我们准备10台完全相同的服务器,让这1000个用户在这一个时刻去分散到不同的服务器访问资源,那么平均每台服务器仅需处理100的并发量,对Tomcat来说是绰绰有余的。
由Tomcat入手LVS+Nginx集群_第2张图片

看来这是一个解决方案。但再想,这个方案无疑是给用户增加了不必要的工作,需要去选择访问哪一台。既然做的是服务,用户才是一切,给用户带来了不变是致命的;服务器当然也是如此。用户要的就是在浏览器输入网址,给我相应的信息就好了,后端多么复杂,不关用户的事。

既然选择用哪一台服务器的工作不能留给客户端,那不妨还是把锅丢给服务端。自然而然,可以想到,把这几台服务器放在一个内网当中,再另外做一个面向用户的服务,专门来“暗地里指挥”用户请求去向哪一台服务器。这个服务一方面面向客户端拉客,另一方面安排服务器接客。
由Tomcat入手LVS+Nginx集群_第3张图片至此,这就成了一个简单的负载均衡集群。中间的服务器就叫做负载均衡服务器,后面的几个Tomcat实际就是集群中的真实服务器。而负载均衡的服务也不用我们自己开发,在linux系统内核中已经集成了这个功能,也就是LVS(Linux Virtual Server)

LVS(Linux Virtual Server)


我们常用的负载均衡可分为四层负载均衡和七层负载均衡,这涉及到了网络的知识,第四层为网络层,第七层为应用层。简单来讲,四层负载均衡是指这个服务仅仅看到四层的东西(即源IP、目标IP、端口等)依此来安排负载;七层则是看到了七层的东西(即uri等,也就是我们学java所接触的http协议那一套)来安排负载。

LVS可以实现四层负载均衡。

LVS是Linux内核自带的功能服务,就是说在它是集成在linux系统内的,装上系统配置配置就能用。

LVS有三种工作模式(即整体上是怎么实现负载均衡的,几种方式各有优劣)

  • NAT(地址转换方式)
  • DR(直接路由方式)
  • TUN(隧道方式)

LVS还是多种调度策略(即用个什么算法去分配RS)

LVS的工作的大体流程可以概括为:
LVS工作在四层,与TCP协议打交道,客户端发出的HTTP包前会有TCP包,将包发给LVS,LVS会根据配置的调度策略,选择一个RS,处理一下TCP包,扔出去,让RS收到去拆开看HTTP包,处理请求。对于NAT模式,是将TCP包的目标IP改成RS的IP,还需同样处理RS返回来的包;对于DR模式,同NAT模式的处理方式,但不用处理RS返回来的包,RS中配置了一个隐藏的VIP,可以直接返回给客户端,但LVS要与RS集群在一个局域网内;对于TUN模式,是将这个包作为内容封装为一个新的TCP包发给RS。

(以上不展开了,大体知道LVS是做什么就好,具体可以再查找其他的资料)

下面用
LB(Load Balance)表示负载均衡
RS(Real Server)表示真实服务


现在我们的项目成了下面的样子:
由Tomcat入手LVS+Nginx集群_第4张图片到这肯定会有疑问,LVS也是做一个服务器,大量的并发来了后,它怎么不崩。原因很简单,LVS只是工作在四层的TCP包,根据配置,处理一下这个包,扔出去就行了;因此它的坑并发能力高的很。

但还有一点缺陷:


现出现情况二:
用户使用的时候,经常退到登录界面,提示没有登录

情况分析:这个原因很清楚了,因为做成了Tomcat的集群,用户每一次访问,可能并不是同一台服务器,因此session就成了一个问题


对于这个,Tomcat倒是给出了一个解决方案,Tomcat自身就可以配置存放及拿取SessionID的地方,默认是本地内存中。我们只要改一下Tomcat的配置,将所有的RS的SessionID保存在同一个地方不就可以了。

在网络中,不妨保存在同一台服务器上。但再想,sessionID可是每一次请求都有去取一次的,如果将它保存在数据库或是文件中,通过IO拿取,势必会浪费很多时间。

这就引出接下来要出场的memcached

memcached

memcached可以理解为存在内存里的数据库。

只有在某一台服务器安装memcached,并配置所有的Tomcat的sessionID保存路径都为这一台服务器的memcached中,每次client的访问,Tomcat的存取Session都通过这台服务器,上面的问题不就解决了吗。

当然,memcached的用处远不止解决session问题。在这不再深入。

现在整个集群变成了如下的样子:
由Tomcat入手LVS+Nginx集群_第5张图片


现出现情况三:
LVS服务器因为某种原因崩了
或者某台RS因为某种原因崩了

情况分析:
虽然LVS的抗并发问题不大,但是保证不了这台服务器不出问题,万一LVS服务器出现硬件故障宕机或者其他原因崩了,即使所有的RS都正常工作也无济于事了。因为LVS这一个节点造成了整个集群的瘫痪,当然是不合适的。
同样,某台RS崩了,LVS若不及时得知消息,还不断的让这台RS出来接客,必定影响用户体验。
这就引出了接下来要解决的单点故障问题,实现高可用。


很容易想到,一台LVS崩了,再找一台顶上去呗。但这台顶包的LVS服务器应该和原来的服务器保持完全一致才行。这就是要为LVS搞一个主备模型。正牌正常工作时,备胎在一边候者,正牌有情况不在,备胎马上顶上,为了让客户有完全一样的体验,备胎时时刻刻要跟正牌学习,做到和正牌完全一样;当正牌回来了,备胎可以一脚踢开了。这就是主备机工作的方式。

一台RS崩了,那就把这台剔除掉,等恢复了再加进来呗。

整个的这一个过程也不用我们自己开发相应的程序,现有很成熟的软件供我们使用,即Keepalived

Keepalived

keepalived与LVS配套使用,可以看做LVS的一个“管家”,管理LVS的配置、开关、同步主备机,更重要的是实现一个LVS集群的高可用。

假设有两台LVS服务器,每个LVS服务器上都请这么一个管家(安装一个keepalived),其中一个keepalived将自己的LVS配为主机,另一个配为备机。那么LVS安心干活就是了,剩余的问题处理交给各自的keepalived管家。(下面称主机的keepalived为主K,备机的为备K)

主K比较忙,一方面要定时向备K发送LVS的健康状态广播,就是告诉备K你先老老实实的,我们家LVS还正常干着活呢;另一方面,主K要定时向集群RS发送请求,验证每台RS的健康状况(都收到响应码200就是存活,这叫心跳检测),并将宕机的RS剔除,不再使用,当能收到200了(即修复了),再添加进来。

备K就很轻松了,定时收一下主K发来的健康报告,如果没有收到,说明主机宕机,马上安排自家的LVS要出来干活了。这个安排的过程是keepalived基于VRRP协议(虚拟路由协议)实现的IP偏移,说白了就是将自己的IP改为主机的IP,这样访问主机的请求自然就来了备机。当主机修复后,备K会重新收到主K发来的健康报告,则再将IP改回来即可。

现在这个集群变成了下面这样:
由Tomcat入手LVS+Nginx集群_第6张图片现在的结构,能很多程度的解决并发问题及单点故障问题。但这个项目继续做大做强,又出现新的问题。


现出现情况四:
项目做到了很大,把整个项目放在一台服务器上,Tomcat扛不动了
即使少量的并发访问,服务器也运作不快

情况分析:这种情况难免发生,首先可以考虑不是有Tomcat,另选一个更强大的Web应用服务器,但这治标不治本,因为项目理论上可以无限增大,但服务器却也就那么多。因此要从项目本身下手。


这时,应考虑能不能把项目细分,每个Tomcat只搭载整个项目的一部分,通过客户端的请求类型,来判断去访问那个Tomcat。

这就是所谓的面向服务开发。

访问一个网页,一般都会有图片、文字等多种信息的呈现,假设把将视频、音乐、图片、文字分别放在集群中不同的Tomcat上
由Tomcat入手LVS+Nginx集群_第7张图片
因为集群是在一个内网中的,我们不可能让客户端根据自己的需求,重定向来拿相应的信息(就是不可以直接访问RS),因此,我们还可以搞一个联系RS的服务,来代替客户端从RS集群中拿取数据。即客户端向这个服务器发送请求,这个服务器会分析需要什么(假如需要一段视频和一段文字),就将请求转发给视频和文字的Tomcat,等待两个Tomcat响应后,再把响应转发给客户端。这样的服务器叫做反向代理服务器。(对比用的代理服务器,是请求一个服务器代替客户端去拿数据;而这的反向代理服务器,是代理RS集群,从内网向客户端响应数据,其实都差不多一个意思)

能够充当这个反向代理服务器的,就是所谓的Nginx

Nginx

先抛开刚才的LVS,现在的集群成了:
由Tomcat入手LVS+Nginx集群_第8张图片看到这里,这个框架的弱点仍然是Nginx结点的并发问题和单点故障

对于Nginx的抗并发能力,官方给出的是5w并发量,即轻轻松松处理5w的并发访问。对比tomcat,之所以有这么大抗并发,主要原因有两个,一是Nginx只做请求和响应的转发而没有业务逻辑处理,大部分的时间花在与其他计算的I/O上;而是Nginx的I/O采用的是单线程或少线程、异步非阻塞的模式(Tomcat是一个连接一个线程,同步阻塞的模式),避免了打开I/O通道等待数据传输的过程(仅仅是在数据传到了,再来接收即可),极大的缩短了线程调度和I/O处理的时间。

对应Nginx的单点故障,仍然可以用keepalived解决,这里为了画图方便先不加上了。


现出现情况五:
客户端赶巧在都是访问了视频资源
这是Nginx将1000条并发访问都转给了视频Tomcat
这个Tomcat还是会崩

情况分析:这又成了最开始的tomact并发问题


面对这个问题,首先想到当然要有负载均衡技术,再在Nginx和RS直接添加LVS显得太繁杂。强大的Nginx已经为我们考虑好了,它自身就带有七层负载均衡的功能。同样配置一下就可以用了。则整个集群变为了
由Tomcat入手LVS+Nginx集群_第9张图片因此,Nginx实际可作为一个反向代理服务器,同时具有七层服务均衡的能力。


现出现情况六:
现在的并发量再一次提升,超过了5w,Nginx的效率也到了瓶颈

情况分析:不说了,再把LVS揉进来就是了


由Tomcat入手LVS+Nginx集群_第10张图片
这里LVS采用了DR的模式,让Nginx将响应直接发给client。
到此,这个集群基本成熟,下一篇将整理一下用虚拟机搭出这个集群的过程。

你可能感兴趣的:(Cluster)