高并发与负载均衡——nginx反向代理与负载均衡

一、反向代理

1.面向服务开发

模块化,解耦的开发,提高团队合作效率,现阶段的开发。

2.正向代理与反响代理的区别

代理是的方向是就客户端而言的,对于翻墙来说,是正向代理,Client访问不了服务器,这时候需要一个代理服务器代理我们访问服务器,这就是正向代理,代理服务器代理客户端。对于分布式架构业务服务,来说反向代理服务器其实做的是反响代理的工作,因为反响代理服务器代理的是Client访问的后台服务器而不是Client本身,这就是反向代理。

3.存在的意义

在面向服务编程角度来考虑,则是将整体服务进行解耦,模块化。即便于开发,也便于维护和扩展。而这最终的体现就是成本的降低。

4.可以做反向代理的服务器:

(1).httpd(tomcat):httpd是可以做反向代理,但是tomcat是一个容器级别服务器,不是一个轻量级,在高并发性能瓶颈上有着不可避免的缺陷,虽然可以通过硬件强行提升,但是对于成本有着非常高的需求。所以httpd不适合做反向代理

(2).nginx:nginx是很适合做反向代理,官方给出的并发量是5w,但是阿里封装的nginx——>tengine可以达到10w很轻松(这是业务需求,硬件匹配,服务器参数调优等多方面因素设置得当才可以达到)。

5.Nginx和Apache(tomcat)

(1)Nginx和apache的优缺点:

(2)Nginx和apache的模型对比

进程对比:

Nginx是CPU有多少个核心,就有多少个进程,而apache则是一个连接一个进程。那么在进程切换对cpu和IO是有损耗的,在高并发情况下,apache会开辟非常多进程,对cpu和io有非常大的损耗,进程切换又有着额外开销,所以这是apache的弊端;而Nginx则是一个cpu有多少核心,就有多少进程,那么进程数量很少,一个或者两个进程对应多个客户端Client,那么Nginx是如何在单进程面对多Client请求下做到数据发生不发生交互错误,又高效处理呢?答案就是异步非阻塞IO。

首先我们要知道网络IO流的速度是很慢的(ms级别),而CPU的速度是很快的(ns级别)。CPU比IO速度要快100w倍!!!而Apache使用的是同步阻塞IO,也就是在等连接建立完成后,CPU会等待1ms的时间来等待数据包从客户端传输过来。这个1ms的时间被浪费了,CPU被占用等待了。而Nginx则不是这样,当连接建立后,Nginx不会让CPU进行等待,而是让CPU不断询问linux系统中的连接文件,问是否有数据传输过来了,如果没有,则询问下一个,如果有则挂起别的进程立刻执行有数据的进程。这种轮询的方式后续又得到了改善,变成一旦这个连接文件有数据传输过来,会立刻向CPU发送中断请求,而CPU会立刻去处理该连接的数据,更大效率提高了IO速度和CPU的使用率。

加载部署:

nginx支持热加载与热部署,在nginx服务启动的时候,依然能够修改配置文件,让其重新加载配置文件与继续服务。tomcat则没有。nginx这一点得益于它的模块化开发。

nginx为什么能这样,我们首先要知道一个基础概念,程序本质上没有运行的时候,就是一个文件。而当程序被加载到内存中,则才是程序。这个时候如果我们删除或者程序的原本文件,是不会影响内存的,因为内存已经加载到了程序文件。windows不可以这样是因为windows在运行程序时,会给程序文件加锁,如果打开了锁,windows也可以。linux显然也可以这样去做。那对于nginx的热加载,linux是如何处理的呢?

如下图所示,nginx启动后,会开启两个进程。一个是manager,一个是worker。manager进程从属于root,它会读取nginx.conf来创建一个worker进程,并将它交给nobody权限用户。所有连接处理和转发,都是交给worker进程来处理的。一旦发生热加载,那么manager进程会重新读取配置文件,并等待老worker进程处理完所有任务后,创建新worker进程,杀死老worker,从而平滑的不用停止服务器就实现了服务器加载和更新。

 

二、nginx做反向代理搭建实战

(1)Nginx.conf文件分析与配置

(2)小实验1:将更改配置文件,实现nginx的虚拟服务器功能

前提:修改windows的host文件,设置ip与域名的映射关系

结果演示:

(3)关于server方法中location字段方法的分析和设置

(4)小实验2:解决nginx的链接跳转问题

  • 问题描述:我们通过nginx反向代理访问www.baidu.com,如果我们通过http来访问,则会发生页面跳转问题
    • 现象
      • nginx的location配置
      • 访问www.wymnode01.com/oxox,发现发生了页面跳转,跳转到www.baidu.com
    • 结果分析:由于Client通过反响代理和http访问百度,请求也确实经过了nginx到达了百度,但是由于现在的大网站都是https的协议。百度服务器收到http请求后,会给Client返回一个跳转连接,那么Client通过跳转连接则会和百度服务器直接建立连接而跳过nginx。所以我们要避免这种情况
    • 问题解决:在114行将http改成https就可以了

nginx.conf的相关知识还非常非常多,查看视频和翻阅资料博客,继续整理

 

 

 

三、高并发

1.用别的可以做反向代理的服务器做反向代理存在高并发的问题

  • 从业务分布式解决高并发:我们假设存在一种反向代理服务器(A)也可以承担5w的并发量,并根据业务功能的不同对搭载不同业务的tomcat做服务分发,这从一定角度上解决了高并发的问题,但是只是从服务业务的不同角度来解决了高并发问题。

  • 从业务分布式解决不了的高并发:如果客户端有2000个都是搜索方面的请求,那么这些流量和请求都会由A转发给搜索服务器的tomcat,tomcat承受不了2000的并发量,所以会崩溃。这时候就需要在反向代理服务器和搜索服务器tomcat之间搭建负载均衡,并将搜索服务器配置成tomcat集群。

2.使用nginx做反向代理服务器可以解决负载均衡和反向代理的问题

nginx的特点和可以解决的问题:nginx不仅仅可以做反向代理,还可以做负载均衡,也就是说他是反向代理+LVS。nginx这一特点就可以从业务分布式角度、单一业务的流量对该业务服务器造成压力的角度,这两个角度来解决高并发问题,算是一举两得。

3.高并发的体会和理解

高并发问题绝对不是一个从单一角度就可以解决的问题,我们现在所讨论的是从服务器架构角度解决高并发问题,这个角度的解决的出发点是客户端的大量流量会给服务器造成巨大压力,也会给服务器造成巨大性能损耗,同时也考虑到了I/O速度和数据传输流量等问题。高并发的问题会出现在服务器架构和软件架构的各个分层之间,比如dubbo是解决软件层面表示层和业务层之间的并发问题,redis则是在业务层和持久层这两层来解决并发与效率问题,而sql索引和分库分表和sql语句的书写则是在持久层这一层解决效率问题。而我们的LVS和nginx则是在网络流量如何均摊这一层来解决,属于是在软件层面外,在操作系统这一层面,网络传输这一层面来解决高并发问题(因为LVS本身就是linux内核所带的,nginx工作在应用层也就是要建立TCP连接的)。

 

四、LVS+nginx负载均衡

1.知识补充

nginx工作流程:如图1所示,也就是1——4的过程,更加说明nginx是要和客户端建立握手连接的,这点与LVS是不同的!

用户体验:互联网对3秒比较敏感,如果请求的数据能够在3秒之内发送到,则用户体验会很好,这3秒客户端和RealServer(RS)之间发生的交互首先是客户端先和nginx建立连接成功,然后nginx在此基础上对url进行解析并交给后面RS做业务处理,最后RS将结果返回给nginx,nginx再返回给客户端。整个过程要3秒内完成。

2.LVS+nginx的优点

  • 突破nginx性能瓶颈:nginx是5w,如果并发量是50w呢,这时候则需要部署nginx集群,并在nginx集群前部署LVS,nginx数量(10台)*5w,就可以实现50w的并发量了,如图1。
  • 改善LVS瞎子负载缺点:LVS由于是4层技术,不能建立TCP连接,也就解析不了URL,那么就不能根据客户的实际请求做正确的负载均衡(有时候会碰巧碰到LVS做出了正确的负载均衡,是因为LVS碰巧把数据包转发给了正确的RealServer,因为LVS会保持握手>>数据传输>>挥手的原子性,所以后续的数据包如果连接没有中断,是会正确的返还给客户端的,但是如果一开始LVS在握手包建立过程中就将数据包发送给了不相匹配的业务的RealServer,则整个连接就错误的),而nginx的反向代理技术则解决了这一点。

图1

图2(为图1的再简化抽象)

LVS将客户端请求发送给lvs后的所有镜像一致的web server。webserver为轻量级的nginx,拥有反向代理(转发)+负载均衡的能力,再将LVS负载过来的数据包进行负载均衡和转发,从而实现了业务架构的拆解。

3.LVS+nginx的缺点

在之前的LVS:DR模型我们可以知道的是,RealServer可以直接向客户端返回数据包,解决了网络流带宽数据传输的瓶颈问题。但是LVS+nginx则不可以,数据包只能由nginx返回。因为LVS:DR模型我们通过MAC地址欺骗和隐藏VIP等方式可以让客户端和RealServer直接建立握手连接,那么Client——RS之间的握手>>数据传输>>挥手整个过程是完整独立的。但是LVS+nginx的负载均衡模型中,客户端是和nginx之间建立握手连接,nginx和RS之间建立握手连接,那么客户端没有和RS建立TCP连接,则RS不能直接将数据发送给客户端,只能转交给nginx,由nginx发送给客户端,那么流量的限制就体现在nginx服务器的个数和端口上了,而不是nginx后面数以万计RS身上了。

 

三、Nginx做负载均衡搭建实战

 

实验一、nginx做负载均衡

1.vi /usr/local/nginx/conf/nginx.conf  ———>进入nginx.conf文件中

2.添加location字段,让nginx对匹配的url做转发,这里配置在了63——68行

3.将keepalive_timeout 0打开,将keepalive_timeout 65注释掉,原因在脚本注释中写的很清楚

4.添加upstream方法,方法名称随便,里面添加服务器列表,表示nginx可以将请求转发给那些服务器。

5.测试

刷新

 

实验二、:nginx给两台tomcat的RealServer做负载均衡,返回Session不同并解决Session一致性的问题

  • 问题描述:假设nginx后面RealServer集群(R1和R2)搭载tomcat,并有着用户登录和用户主页访问的功能,那么如果我们的Client先访问R1并登录获取了R1发送的Session,这时候连接断开,Client携带Session访问RealServer集群,但是nginx将这个请求负载给了R2,由于R2的Session和R1的Session不一样,就会引发登录重定向,要求用户重新登陆。这样的情况和京东淘宝的登陆情况是不同的,因为两个网站都没有需要重复登陆的问题,在解决问题之前我们先将问题复现
  • 问题复现
    • 将R1与R2(node02和node03)装上,并进入tomcat的主页文件进行修改,将之前的主页index.jsp备份成为index.jsp.bak,对主页进行如下修改
      • node02
      • node03
    •  在node01也就是nginx.conf中给R1和R2配置负载均衡,并监听8080端口,防火墙也放开8080端口
      • 添加upstream
      • 添加location
    • 结果演示:两者session不同
      • 负载给node02
      • 刷新后负载给node03
    • 问题解决session不同的问题我们可以在RealServer集群后加一台服务器(S1),让RealServer集群将Session统一写到S1中,即使负载均衡给了不同的RealServer,那么这台RealServer只需要查询S1的Session表中是否有对应的Session,不需要和自己产生的Session进行匹配了。但是问题又会出现,这台S1会承载大量的RealServer的IO请求,如果S1是一台mysql,则会非常慢,因为IO速度成为了限制瓶颈(硬盘IO速度很慢)。我们可以使用Redis集群来解决这个问题,将IO速度提升为内存IO速度,从而提升了性能。我们这里先不用Redis,先用memcached来实现,后续引出Redis。因为session不一致问题不是出现在nginx,所以我们只需要将缓存服务器搭建在tomcat的集群之外的服务器就可以了,这里我们选择搭建在nginx服务器上。
      • 解决步骤:
        • 安装memcahed:这里下图的蓝色IP就是nginx服务器的IP,我改成了我的192.168.88.123
      • 启动memcached,如上图红色指令
      • 修改RealServer集群中tomcat文件夹下的context.xml文件,让tomcat将Session写到memcached服务器中,只需要在Context字段下添加Manager字段
      • 给RealServer集群添加响应的jar包,添加到tomact的lib目录下,也就是Mananger字段中的所提到的jar包
      • 结果演示
        • node02
        • node03
        • 遗留问题:这里应该刷新过后session是不变的,但是还是发生了变化,没有导入jar包会报404错误,导入jar包后不会出现404错误但是出现了session变化问题,具体原因还有待商榷,初步判定应该是没有导入正确版本的jar包。
          • ​​​​​​​遗留问题解决:
            • ​​​​​​​1.首先考虑到的是jar包版本问题,重新翻阅博客找到了新的jar包,但是还是出现了session变化问题。所以
            • 2.后来考虑到了RealServer的集群时间,nginx的服务器时间以及客户端时间是否是一致的问题,因为如果客户端时间或者nginx时间比RealServer的时间早,那么RealServer会判定这个session已经过期了。就会发送新Session,那么就会出现session变化,但是发现nginx服务器的时间不会影响结果。但是还是要保证当前项目下服务器的时间一定要是一致的。
            • 3.之后怀疑是否是session本身存活时间过短,但是查看tomcat的server.xml发现session存活时间默认是30分钟,所以排除
            • 4.最终原因memcached的端口11211没有打开,最后发现是这个原因,也就明白了,因为session结果是从memcached中查询得到的,那么如果没有打开11211端口,RealServer就不能对memcached进行读写操作,那么一旦发生负载均衡出现Client拿着R1的Session去访问R2,RealServer不能访问memcached,只能自己生成新Session给Client。也就发生了即使配置了memcached,也会存在session不一致的情况
              • ​​​​​​​解决后结果演示
                • node02​​​​​​​
                • 刷新后node03
        • 补充点:集群时间很重要,一个集群的机器的时间一定要设置成为一样的。不然session会出现过期的现象,这样服务器就会重新创建一个session,那又会出现之前的重复登陆问题了!!

四、LVS和nginx的缺陷——keepalived的引出

1.问题

  • 1.LVS或者nginx的单点故障问题,会导致后面整个RealServer集群无法访问
  • 2.RealServer的单点故障,会造成一部分客户端的不可用

​​​​​​​2.解决——主从配置

(1)解决LVS单点故障

给当台LVS配置多个从属服务器,主服务器会给从属服务器定期广播一个数据包,来证明它还活着。一旦主服务器没有在规定时间点发送数据包,从属服务器不会立刻判定主服务器死亡,而是会再次等待主服务器发送广播数据包(这样做是为了防止网络延迟和IP冲撞,丢包等问题造成的主服务器还活着,但是发送的广播数据包从属服务器并没有接受到)。一旦确定主服务器死亡,则从属服务器会选举出一个主服务器来继续工作,并将挂掉的过去的主服务器的IP地址VIP继承过来——这就是IP漂移

(2)解决RealServer的单点故障

我们会监控RealServer的健康状态通过shell脚本来让LVS对RealServer做心跳检测),一旦RealServer出现故障,则在LVS的负载表中暂时删除掉故障的RealServer的IP,这样就可以保证客户端访问不到故障的RealServer,同时对RealServer做修复,以及LVS可以试探去访问RealServer来验证是否修复成功。等修复成功后再添加到LVS的负载表中。

  1. 如何验证检测RealServer是健康状态

需要注意的是,我们要验证RealServer是否存活,本质上是验证RealServer上的搭载我们服务的服务器软件是否运行正常——也就是tomcat,这是对网络层第7层的验证我们如果通过linux的ping指令来验证是不行的,因为ping指令验证的是第三层IP层,连握手都没有建立。所以我们可以写shell脚本来让LVS给RealServer发送http请求,查看tomcat返回的服务器状态码,如果是200则健康。我们也可以使用keepalived来做这件事情。

 

 

 

  • 9
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值