阿里云个人服务器搭建项目笔记七:nginx lua脚本实战

一、nginx为什么高性能

epoll多路复用

1.传统模型:基于缓冲区的传输
首先,假设这里有两台主机进行通信
client ----- server
当client要向server传输数据的时候:数据不会直截了当地发到server处,而是先进行一个socket.write操作,并将要发送的数据包放到缓冲区中。
如果有一个数据包要发送,这时候缓冲器被占满了,那么tcp/ip会先将缓冲区里面的数据全部传输完成,才能让新的数据包进入缓冲区,然后再进入服务器。这样的操作效率不够高

2.linux select模型:变更触发轮询查找
select多路复用是server阻塞自己的同时监听多个客户端的连接,一旦有连接发生变化,那么就唤醒自己,循环遍历100个连接,找到发生变化的一个或者多个,执行read操作。缺陷:遍历的效率很低,并且有1024的数量上限

3.epoll多路复用模型:根据回调函数唤醒自己
同样,server阻塞自己同时监听多个客户端的连接。并且设置回调函数。若发生变化直接唤醒自己执行回调函数。

master-worker进程模型

启动nginx之后,会产生一个nginx的master进程,这个master可以产生多个worker进程,通过ps -ef | grep nginx可以看到:nginx启动了两种进程,一个是master process,一个worker process,并且可以发现master是worker的父进程。也就是说master进程可以管理一切worker进程中的内存,堆栈,函数……
而worker进程就是真正的处理多个客户端连接的一个进程,也就是客户端的请求是由worker进程去连接和管理的,而在并发情景下,nginx设置了内存中的锁,worker进程抢占锁的速度就会很快。并且每个worker进程是单线程的,进程的内部没有任何多线程的阻塞所以效率很高。

协程机制

1.协程是比线程更小的一个概念,一个线程可以有多个协程,协程之间的切换不是cpu管理的,而是在内存中切换,切换开销非常小。
2.协程遇到阻塞归还执行权给其他协程,代码自动同步,无需手动处理,无需加锁。

二、开始优化

1.第一尝试了配置nginx的proxy cache,第一次拿到热点数据之后将数据存储在nginx服务器上,下一次就从nginx获取,这样反而变慢了,tps在1200左右,这是因为nginx的proxy cache不是在内存中的,而是在磁盘中的!,所以他的性能反而不如再去tomcat服务器的内存里面获取快一些。

2.第二次尝试编写lua脚本,配置shared dictionary
nginx的shared dictionary,顾名思义就是共享字典,他是所有worker进程可见的,并且具有lru淘汰策略,最重要的是它将数据存储在内存中。

配置shared dictionary:

  • 打开nginx.conf
    添加以下内容
    lua_shared_dict my_cache 128m;
    这一行的作用是给shared dictionary分配内存大小

location处添加:

location /luaitem/get{
	default_type "application/json";
	content_by_lua_file = ../lua/itemshareddic.lua;
  • 进入nginx的lua文件夹,编写itemshareddic.lua
function get_from_cache(key)
	local cache_ngx = ngx.shared.my_cache
	local value = cache_ngx:get(key)
	return value
end

function set_to_cache(key, value,exptime)
	if not exptime then
		exptime = 0
	end
	local cache_ngx = ngx.shared.my_cache
	local succ,err,forcible = cache_ngx:set(key,value,exptime)
	return succ
end

local args = ngx.req.get_uri_args()
local id = args["id"]
local item_model = get_from_cache("item_"..id)
if(item_model == nil) then
	local resp = ngx.location.capture("/item/get?id="..id)
	item_model = resp.body
	set_to_cache("item_"..id,item_model,1*60)
end
ngx.say(item_model)

三、继续优化

上面的优化是非常吃内存的,最大的缺陷更新不方便,所以这里继续配置openresty 的 redis支持,即将nginx服务器连接到redis数据库上面,可以只读不写。若redis没有对应的数据,那么就回到应用程序服务器上面去获取并存入redis,那么下一次ajax请求到达nginx服务器处,就直接从redis上面进行读的操作。甚至可以直接设立一个slave的redis,只负责读操作。

进入nginx服务器,打开lua文件夹,新建一个itemredis.lua

local args = ngx.req.get_uri_args()
local id = args["id"]
local redis = require "resty.redis"
local cache = redis:new()
local ok,err = cache:connect("redis服务器的ip",端口号)
local item_model = cache:get("item_"..id)
if item_model == ngx.null or item_model == nil then
	local resp = ngx.location.capture("/item/get?id="..id)
	item_model = resp.body
end

ngx.say(item_model)

打开nginx.conf
将上一个步骤中配置的location从itemshareddic.lua改为itemredis.lua
重启nginx服务即可

你可能感兴趣的:(项目)