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

问题:

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

方案一:

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

init.lua:

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

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

client = red;function redisHasKey(client,keyname)if(client:get(keyname))thenreturn true;elsereturn false;end
endlocal keyname = ngx.var.remote_addr;
if(pcall(redisHasKey,client,keyname))thenif(redisHasKey(client,keyname))thenngx.exit(403);elsereturnend
elsereturn
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:

local redis = require "resty.redis"
local red = redis:new()
red:set_timeouts(1000, 1000, 1000)
red:set_keepalive(1000, 20)
red:connect("127.0.0.1", 6379)
client = red;function redisHasKey(client,keyname)if(client:get(keyname))thenreturn true;elsereturn false;end
endlocal keyname = ngx.var.remote_addr;
if(pcall(redisHasKey,client,keyname))thenif(redisHasKey(client,keyname))thenngx.exit(403);elsereturnend
elsereturn
end

问题:

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

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"
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"
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"
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的操作都会报错。

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

改进下:

local redis = require "resty.redis"
local red = redis:new()
--red:set_timeouts(1000, 1000, 1000)
--red:set_keepalive(1000, 20)
red:connect("127.0.0.1", 6379)
client = red;function redisHasKey(client,keyname)if(client:get(keyname))thenreturn true;elsereturn false;end
endlocal keyname = ngx.var.remote_addr;
if(pcall(redisHasKey,client,keyname))thenif(redisHasKey(client,keyname))thenred:set_keepalive(1000, 200)ngx.exit(403);elsered:set_keepalive(1000, 200)returnend
elsered:set_keepalive(1000, 200)return
end

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

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

Openresty Redis正确使用连接池(set_keepalive)相关推荐

  1. springboot2整合redis使用lettuce连接池(解决lettuce连接池无效问题)

    lettuce客户端 Lettuce 和 Jedis 的都是连接Redis Server的客户端程序.Jedis在实现上是直连redis server,多线程环境下非线程安全(即多个线程对一个连接实例 ...

  2. java redis集群连接池_(08)redis之使用java客户端、spring连接redis、redis集群示例...

    一.java代码连接 1.新建工程,并引入以下包: jedis-2.7.0.jar.commons-pool2-2.3.jar.junit-4.10.jar 2.单实例连接 /*** 单实例连接*/@ ...

  3. Redis之jedis连接池

    jedis连接池的代码: public class JedisPoolTest {//Redis服务器IPprivate static String ADDR = "127.0.0.1&qu ...

  4. Redis中的连接池以及在Springboot中的使用

    1.为什么要使用连接池以及常用客户端的区别     众所周知,Redis是单线程的,那为什么还要使用连接池?首先Redis也是一种基于内存数据库,有着很高的性能,但是我们的系统使用Redis服务时需要 ...

  5. Redis:Jedis连接池JedisPool

    目录 1.JedisPool的应用 1.1 基本应用 1.2 封装应用 1.3 增加超时重试 2.JedisPool配置 2.1 工厂配置 2.2 资源池配置 Jedis提供了连接池JedisPool ...

  6. springboot引入Redis配置JedisPool连接池

    目录 一.pom.xml依赖 二.application.properties配置 三.java配置类 四.单元测试 一.pom.xml依赖 <dependency><groupId ...

  7. redis 连接池_SpringBoot整合redis

    闲来没事,把之前自己搭建的SpringBoot集成Redis整理了一下,相信网上有很多,我只是写一下搭建的文章,能帮到就好,不能帮助,也是自己整理的文档罢了.文章开始: 开发工具用的IDEA 2018 ...

  8. Redis连接池Lettuce Jedis 区别

    Lettuce 和 Jedis 的定位都是Redis的client,所以他们当然可以直接连接redis server. pring boot框架中已经集成了redis,在1.x.x的版本时默认使用的j ...

  9. python redis连接池_redis 连接池

    redis是一个key-value存储系统,和memcached类似,支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set-有 ...

最新文章

  1. Kafka万亿级消息实战
  2. (chap9 基于HTTP的功能追加协议) 期盼已久的http 2.0
  3. Vitaly and Night
  4. boost::bucket_sorter用法的测试程序
  5. 修改java和mysql_关于mysql和java的数据修改
  6. 小米6指主板图示_小米MIX2手机不开机,修过没修好,通病问题教你一坨锡就能搞定...
  7. Tensorflow(0)--Tensorboard
  8. Draconian,自由或保姆状态:Java,C#,C,C ++,Go和Rust中的并发意识形态
  9. (转载)—— Logistic Regression(逻辑回归)模型实现二分类和多分类
  10. 重构之以委托取代继承
  11. 【转】HTTP请求中的form data和request payload的区别
  12. 一个ABC眼中的中国的创业环境(一)
  13. jQuery源码06-jQuery = function(){};给JQ对象,添加一些方法和属性,extend : JQ的继承方法,jQuery.extend()...
  14. BP 神经网络用于模式分类
  15. 你想要的宏基因组-微生物组知识全在这(2022.5)
  16. 21王道计算机网络pdf百度云,王道计算机网络第五章.pdf
  17. Nginx服务(6)——实现Gzip网页压缩和图片压缩
  18. IPv4编址;A类、B类、C类、D类、E类IP地址(IP地址;网络地址和主机地址;子网掩码;网关;广播地址;)
  19. 2022年高考送祝福,金秋9月,CSDN等你哦!
  20. 思考分析常用思维模型

热门文章

  1. c#让程序在WIN7下兼容模式运行
  2. android如何实现开机自动启动Service或app
  3. 数字证书中keytool命令使用说明
  4. Java练习:用IF()进行数字排序
  5. mongodb 运行状况,索引构建分析
  6. 活动目录环境下 临时让End user提升权限安装应用软件
  7. Vue的百度地图插件尝试
  8. ID--HANDLE--HWND三者之间的互相转换
  9. 2张图简单分析count(0)与count(*)
  10. oracle 按照周 分组