前言
本文将总结服务器性能优化的两种基本方法,反向代理和数据缓存,分别会使用到nginx
和redis
,关于反向代理和数据缓存的基础知识暂时不做介绍,本文将以图文并茂的形式详细地记录安装配置nginx
和redis
,以及使用它们来简单实现反向代理和数据缓存的过程。
1、Nginx 安装与 Proxy 的配置
nginx
的安装过程如下,由于部分命令运行后的输出比较长(例如make
),截图比较麻烦,下面我记录了安装过程中更需要用到的命令。首先切换到root
用户方便后续操作。接下来开始安装pcre
库,安装的命令如下所示,安装完成后通过检查版本来判断是否安装成功。然后才是开始安装nginx
,nginx
的安装命令跟安装pcre
的类似,最后也是通过检查版本来判断是否安装成功。
1 | $ sudo su |
安装完nginx
之后,启动nginx
,出现了以下错误。
这是因为nginx
默认是监听80
端口,而我的Linux上80
端口已经被其他程序占用了,解决办法很简单,到nginx
的配置文件中修改端口即可,这里我改成了3000
端口。
继续启动nginx
,在浏览器访问0.0.0.0:3000
,看到如下页面,才能说明nginx
的安装真的成功了,可以用了。
完成nginx
的安装之后。开始来写个简单的服务器方便后面测试。我使用NodeJS写了一个简单的服务器,代码如下所示,很简短(由于只是简单测试,所以就暂时不用Java这么庞大的东西了,方便说明实验过程)。它创建了4
个服务器,分别监听8000、8001、8002、8003
这四个端口。为了方便后面的测试,我设定每个服务器都响应不同的内容。监听8000
端口的服务器对任何请求都响应文本"There is Server-1."
,监听8001
端口的服务器响应文本"There is Server-2."
,以此类推。
1 | var http = require('http'); |
有了服务器之后我们可以开始来配置nginx
了。主要有两个地方需要配置,如下截图。配置upstream
,在里面加入4
个服务器的IP地址和端口号
。配置location
,将请求转发到upstream
配置的服务器上。
完成配置之后就可以开始简单测试了。重启nginx
,继续访问0.0.0.0:3000
,如下截图所示,页面内容不再是刚才那个欢迎界面了,变成了NodeJS服务器提供的内容了。刷新几次页面,会发现页面的内容会发生变化,例如"There is Server-1."
变成"There is Server-2."
,说明nginx
配置成功,能够正常工作。
接下来继续探究nginx
的负载分配策略。在重复刷新浏览器页面的时候,页面中数字的变化是大概是1、2、3、4
这种顺序,大致可以猜想nginx
默认是按照轮询的方式进行负载分配的。为了能够更具体地测试和统计相关数据,我用Python写了下面一个简单的爬虫程序。爬虫程序会访问0.0.0.0:3000
,把响应的内容输出,根据响应内容判断响应是来自哪个服务器并统计次数,最后把统计结果输出。
1 | import urllib |
通过调整程序中的times
参数可以调整爬虫访问网站的次数,我进行了100次、1000次、10000次
的测试,得到的结果如下。可以发现,四个服务器的访问次数都很均衡,所有请求都平摊到各个服务器上去了,这也说明了nginx
可以很好地实现负载均衡。
输出每个响应的内容得到的结果如下,由于输出实在太长了,所以我这里只做了部分截图。由输出可以看出,nginx
默认的负载均衡策略确实是轮询,访问的顺序基本都是按照1、2、3、4、1、2、3、4、...
顺序地访问。
如何控制策略?修改均衡策略其实很简单,只要在配置文件中修改即可,下面是简单示例,将均衡策略改为按照权重分配,weight
越大的服务器分配到的负载越大,最后标注backup
的服务器只有等到其他非backup
服务器忙或者down
的时候才会使用。
1 | upstream nodeservers { |
什么是session stiky
?是指当用户发出第一个request
后,负载均衡器动态的把该用户分配到某个节点,并记录该节点的路由,以后该用户的所有request
都会被绑定这个路由,用户只会与该服务器发生交互,使得session
不会丢失。不采用session stiky
的话可能造成用户session丢失
,而session丢失
的话就会带来很多问题,比如用户登录状态丢失等问题。如果不用session stiky
的话可以使用session复制
的方法来解决,即在多个节点之间复制session
,实现不同服务器之间的用户状态同步。
2、Redis 安装
redis
的安装过程如下,比较简单。下载tar包解压之后通过makefile
编译,完成之后在src文件夹下即可找到服务器和客户端两个可执行程序,redis.conf
是配置文件。到这里算是完成了,可以自己再把它们添加到环境变量,就不用每次都进来src文件夹下面启动程序了。
1 | $ wget http://download.redis.io/releases/redis-3.2.5.tar.gz |
启动redis
服务器,如下所示。看到以下输出说明安装成功,能够正常启动服务器。
我们再启动一个客户端,使用redis cli
命令启动。如下所示,启动之后输入ping
进行测试,输出PONG
的话表明服务器能够正常工作,客户端可以连接到服务器。
在redis-cli
下面我们可以直接对服务器进行配置,下面截图简单演示了配置的过程。其实就是简单地输入一下配置命令,没有什么特别的地方。还有另外一种方式是通过修改redis.conf
文件来进行配置。
然后是操作主要类型的数据。下面我在redis-cli
下面使用命令简单操作了string、hashmap、set
这几种数据类型,其他数据类型的操作基本相似,就只是命令不同而已,查阅文档之后可以很顺利完成。
最后,简单了解了一下Redis Sentinel
的知识。Redis-Sentinel
是Redis官方推荐的高可用性(HA)
解决方案,当用Redis做Master-slave
的高可用方案时,假如master
宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel
本身也是一个独立运行的进程,它能监控多个master-slave集群
,发现master宕机
后能进行自动切换。它的主要功能有以下几点:
- 不时地监控redis是否按照预期良好地运行;
- 如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);
- 能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave(如果有超过一个slave的话)中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。
大概知道了Redis Sentinel
是个什么东西,关于如何配置Sentinel
,这里暂时不做深究。
3、共享数据缓存
在实验1的基础上,每个应用都使用同一 Redis 缓存,验证数据共享。首先将实验1中的代码进行小小修改,让它支持redis。修改代码后,服务器接收到请求之后会先检查redis里面是否有"tmp_string_key"
的缓存,如果有的话就将其值读取出来响应给客户端,没有的话就设置一个。下面截取的是服务器1的代码,其他3个服务器的代码也是类似的改法。
然后启动redis服务器、启动实验服务器、启动nginx。继续使用之前的爬虫来进行验证。输出的信息如下,所有的服务器相应的文本内容都是服务器4缓存的值,证明缓存数据是共享的。即第一次请求被转发到服务器4,然后服务器4设置了一个缓存键值对,后续不管请求被转发到哪个服务器,都会共享使用这个键值对,所以爬虫每次请求得到的内容都是一样的。
实验到此结束。