当前位置:   article > 正文

Openresty Redis正确使用连接池(set_keepalive)_openresty redis连接池

openresty redis连接池

最近在做一个openresty项目,每次访问需要通过openresty读取redis,判断是否可以允许访问。

问题:

如果每次访问就要与redis建立连接,当并发量大时,连接数会直接爆炸。影响性能和系统。

方案一:

在init_by_lua中先创建redis连接,在access_by_lua中直接使用:

init.lua:

  1. local redis = require "redis"
  2. client = redis.connect('127.0.0.1', 6379)

filter.lua(演示:简单的黑名单功能,如果request的remoteip在redis中存在key,就返回403):

  1. client = red;
  2. function redisHasKey(client,keyname)
  3. if(client:get(keyname))
  4. then
  5. return true;
  6. else
  7. return false;
  8. end
  9. end
  10. local keyname = ngx.var.remote_addr;
  11. if(pcall(redisHasKey,client,keyname))then
  12. if(redisHasKey(client,keyname))
  13. then
  14. ngx.exit(403);
  15. else
  16. return
  17. end
  18. else
  19. return
  20. end

在nginx启动时,就创建了连接,并只使用这个连接。就不会出现连接数过多问题。

方案一问题:

1、在使用中redis故障会导致功能不可用,即使重启redis还需要重启nginx才能重新获取连接。

2、linux tcp连接不能保证长时间不中断。中断后不能修复。

3、单连接在高并发多请求情况下,会阻塞请求,多个请求会等待连接空闲后再进行操作,甚至直接报错。

方案二:

连接池,针对连接数管理

openresty官方本身有连接池管理(set_keepalve)

语法:syntax: ok, err = red:set_keepalive(max_idle_timeout, pool_size)

我就来试着用下,这次只使用filter.lua:

  1. local redis = require "resty.redis"
  2. local red = redis:new()
  3. red:set_timeouts(1000, 1000, 1000)
  4. red:set_keepalive(1000, 20)
  5. red:connect("127.0.0.1", 6379)
  6. client = red;
  7. function redisHasKey(client,keyname)
  8. if(client:get(keyname))
  9. then
  10. return true;
  11. else
  12. return false;
  13. end
  14. end
  15. local keyname = ngx.var.remote_addr;
  16. if(pcall(redisHasKey,client,keyname))then
  17. if(redisHasKey(client,keyname))
  18. then
  19. ngx.exit(403);
  20. else
  21. return
  22. end
  23. else
  24. return
  25. end

问题:

使用之后发现更大的问题,连接数量没有被连接池控制,同时出现大量报错:

  1. 2021/05/19 13:57:57 [error] 2734932#0: *2019 attempt to send data on a closed socket: u:00000000401F79D0, c:0000000000000000, ft:0 eof:0, client: 127.0.0.1, server: , request: "GET / HTTP/1.0", host: "127.0.0.1:8082"
  2. 2021/05/19 13:57:57 [error] 2734932#0: *2019 attempt to send data on a closed socket: u:00000000401F79D0, c:0000000000000000, ft:0 eof:0, client: 127.0.0.1, server: , request: "GET / HTTP/1.0", host: "127.0.0.1:8082"
  3. 2021/05/19 13:57:57 [alert] 2734932#0: *2019 socket() failed (24: Too many open files), client: 127.0.0.1, server: , request: "GET / HTTP/1.0", host: "127.0.0.1:8082"
  4. 2021/05/19 13:57:57 [error] 2734932#0: *2019 attempt to send data on a closed socket: u:00000000401F6290, c:0000000000000000, ft:0 eof:0, client: 127.0.0.1, server: , request: "GET / HTTP/1.0", host: "127.0.0.1:8082"

连接在被使用的时候已经中断了。

解决:

看下官方对于set_keepalive的用法说明

set_keepalive

syntax: ok, err = red:set_keepalive(max_idle_timeout, pool_size)

Puts the current Redis connection immediately into the ngx_lua cosocket connection pool.

You can specify the max idle timeout (in ms) when the connection is in the pool and the maximal size of the pool every nginx worker process.

In case of success, returns 1. In case of errors, returns nil with a string describing the error.

Only call this method in the place you would have called the close method instead. Calling this method will immediately turn the current redis object into the closed state. Any subsequent operations other than connect() on the current object will return the closed error.

简单来说,set_keepalive使用时是用来替代close的,如果使用了set_keepalive之后再对连接进行任何除了connect的操作都会报错。

看来看官方文档很重要啊!

改进下:

  1. local redis = require "resty.redis"
  2. local red = redis:new()
  3. --red:set_timeouts(1000, 1000, 1000)
  4. --red:set_keepalive(1000, 20)
  5. red:connect("127.0.0.1", 6379)
  6. client = red;
  7. function redisHasKey(client,keyname)
  8. if(client:get(keyname))
  9. then
  10. return true;
  11. else
  12. return false;
  13. end
  14. end
  15. local keyname = ngx.var.remote_addr;
  16. if(pcall(redisHasKey,client,keyname))then
  17. if(redisHasKey(client,keyname))
  18. then
  19. red:set_keepalive(1000, 200)
  20. ngx.exit(403);
  21. else
  22. red:set_keepalive(1000, 200)
  23. return
  24. end
  25. else
  26. red:set_keepalive(1000, 200)
  27. return
  28. end

虽然用起来还挺恶心,但确实解决了我们的问题。

在使用ab测试时连接数虽然不会被严格控制在set_keepalive的pool_size数值内,但能够与测试的并发量相关。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/550849
推荐阅读
相关标签
  

闽ICP备14008679号