springboot整合redis异常汇总

package select; import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig; public class SelectFromMysql { public static void main(String[] args) { JedisPool pool; JedisPoolConfig config = new JedisPoolConfig();//创建redis连接池 // 设置连接数,-1无限制 config.setMaxTotal(300); // 设置空闲连接 config.setMaxIdle(100); // 设置阻塞时间,记住是毫秒数milliseconds config.setMaxWaitMillis(100000); // 创建连接池 pool = new JedisPool(config, "127.0.0.1", 6379,200000); for (int i =9222000; i <=9222200; i++) {//这里自己设置用多少线程并发访问 String teacherName=String.valueOf(i); new ThreadToMysql(teacherName, "123456",pool).start(); } }}

项目中要用到redis,于是尝试通过springboot整合redis,redis集群采用3主3从,搭建方法参考:

redis连接超时 redis连接超时该如何解决redis连接超时 redis连接超时该如何解决


redis连接超时 redis连接超时该如何解决


springboot从2.x版本开始默认使用lettuce访问redis,所以部分配置由jedis改为lettuce

异常1: Cannot retri initial cluster partitions from initial URIs [RedisURI [host='192.168.1.1', port=6379]]

spring.redis.timeout,在1.0中,时间相关的配置参数类型为int,默认单位为毫秒, 而且设置为0意味着不超时 ,2.x版本中参数类型为Duration,需要添加单位,如:500ms

异常2: ja.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig

添加依赖即可

commons-pool2

2.8.0

1.如果在配置文件中给redis设置了密码,还需要在redis-cli终端设置一下

config set requirepass xxxx(密码)

2.redis-cli 检at redis.clients.jedis.Binary.connect(Binary.ja:93)查cluster的状态

3.配置文件中cluster-require-full-coverage设置为no,重启redis服务,可参考:

redis客户端出现could not get a resource from the pool怎么解决

function_M.set_keepalive(self,...)localsock=self.sockifnotsockthenreturnnil,"notinitialized"endifself.subscribedthenreturnnil,"subscribedstate"endreturnsock:setkeepalive(...)end

在项目中使用redis做缓存,当运行一段时间后就会出现如下错误:Could not get a resource from the pool,然后在看具体的异常信息就是JedisPool中获取不到jedis对象,也就是说连接池中没有可用的jedis。

一个参数就是超时时间,长连接是不会断的,除非你自己去close或者那边断了,这个时候可以捕获错误,然后进行重连

自己的反应就是把链接数(setMaxTotal)调大一些,刚开始设置了100、后来200、在后来2000都不行

然后上网一搜发现大家的回答也都是修改连接数,如下demo就是网上一篇博客的解释:

1、产生原因:客户端去redis拿连接(代码描述的是租用对象borrowObject)的时候,池中无可用连接,即池中所有连接被占用,且在等待时候设定的超时时间后还没拿到时,报出此异常。

[color=red]

[/color]

但这个自己也设置了,配置如下:

#活动对象数

redis.pool.maxTotal=1000

#能够保持idel状态的对象数

redis.pool.maxIdle=100

redis.pool.minIdle=50

#当池内没有返回对象时,等待时间

redis.pool.maxWaitMillis=10000

#当调用borrow Object方法时,是否进行有效性检查

redis.pool.testOnBorrow=true

#当调用

如何在 Go 语言中使用 Redis 连接池

cluster

一、关于连接池

1234567801112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081

一个数据库只拥有有限的资源,并且如果你没有充分使用这些资源,你可以通过使用更多的连接来提高吞吐量。一旦所有的资源都在使用,那么你就不 能通过增加更多的连接来提高吞吐量。事实上,吞吐量在连接负载较大时就开始下降了。通常可以通过限制与可用的资源相匹配的数据库连接的数量来提高延迟和吞 吐量。

如何在Go语言中使用Redis连接池

如果不使用连接池,那么,每次传输数据,我们都需要进行创建连接,收发数据,关闭连接。在并发量不高的场景,基本上不会有什么问题,一旦并发量上去了,那么,一般就会遇到下面几个常见问题:

性能普遍上不去

CPU 大量资源被系统消耗

网络一旦抖动,会有大量 TIME_WAIT 产生,不得不定期重启服务或定期重启机器

工作不稳定,QPS 忽高忽低

要想解决这些问题,我们就要用到连接池了。连接池的思路很简单,在初始化时,创建一定数量的连接,先把所有长连接存起来,然后,谁需要使用,从这里取走,干完活立马放回来。 如果请求数超出连接池容量,那么就排队等待、退化成短连接或者直接丢弃掉。

二、使用连接池遇到的坑

最近在一个项目中,需要实现一个简单的 Web 提供 Redis 的 HTTP intece,提供 JSON 形式的返回结果。考虑用 Go 来实现。

首先,去看一下 Redis 的 Go Redis driver。 Star 的项目有两个:Radix.v2 和 Redigo。经过简单的比较后,选择了更加轻量级和实现更加优雅的 Radix.v2。

Radix.v2 包是根据功能划分成一个个的 sub package,每一个 sub package 在一个的子目录中,结构非常清晰。我的项目中会用到的 sub package 有 redis 和 pool。

由于我想让这种被 fork 的进程简单点,做的事情单一一些,所以,在没有深入去看 Radix.v2 的 pool 的实现之前,我选择了自己实现一个 Redis pool。(这里,就不贴代码了。后来发现自己实现的 Redis pool 与 Radix.v2 实现的 Redis pool 的原理是一样的,都是基于 channel 实现的, 遇到的问题也是一样的。)

不过在测试过程中,发现了一个诡异的问题。在请求过程中经常会报 EOF 错误。而且是概率性出现,一会有问题,一会又好了。通过反复的测试,发现 bug 是有规律的,当程序空闲一会后,再进行连续请求,会发生3次失败,然后之后的请求都能成功,而我的连接池大小设置的是3。再进一步分析,程序空闲300秒 后,再请求就会失败,发现我的 Redis server 配置了 timeout 300,至此,问题就清楚了。是连接超时 Redis server 主动断开了连接。客户端这边从一个超时的连接请求就会得到 EOF 错误。

然后我看了一下 Radix.v2 的 pool 包的源码,发现这个库本身并没有检测坏的连接,并替换为新server{location/pool{content_by_lua_block{localredis=require"resty.redis"localred=redis:new()localok,err=red:connect("127.0.0.1",6379)ifnotokthenngx.say("failedtoconnect:",err)returnendok,err=red:set("hello","world")ifnotokthenreturnendred:set_keepalive(10000,100)}}}

发现有个 set_keepalive 的方法,查了一下文档,方法的原型是 syntax: ok, err = red:set_keepalive(max_idle_timeout, pool_size) 貌似 max_idle_timeout 这个参数,就是我们所缺少的东西,然后进一步跟踪源码,看看里面是怎么保证连接有效的。

至此,已经清楚了,使用了 tcp 的 keepalive 心跳机制。

于是,通过与 Radix.v2 的作者一些讨论,选择自己在 redis 这层使用心跳机制,来解决这个问题。

四、的解决方案

在创建连接池之后,起一个 goroutine,每隔一段 idleTime 发送一个 PING 到 Redis server。其中,idleTime 略小于 Redis server 的 timeout 配置。连接池初始化部分代码如下:

p,err:=pool.New("tcp",u.Host,concurrency)errHndlr(err)gofunc(){for{p.Cmd("PING")time.Sleep(idelTimetime.Second)}}()

使用 redis 传输数据部分代码如下:

funcredisDo(ppool.Pool,cmdstring,args...intece{})(replyredis.Resp,errerror){reply=p.Cmd(cmd,args...)iferr=reply.Err;err!=nil{iferr!=io.EOF{Fatal.Println("redis",cmd,args,"erris",err)}}return}

其中,Radix.v2 连接池内部进行了连接池内连接的获取和放回,代码如下:

//Cmdautomaticallygetsoneclientfromthepool,executesthegivencommand//(returningitsresult),andputstheclientbackinthepoolfunc(pPool)Cmd(cmdstring,args...intece{})redis.Resp{c,err:=p.Get()iferr!=nil{returnredis.NewResp(err)}deferp.Put(c)returnc.Cmd(cmd,args...)}

这样,我们就有了 keepalive 的机制,不会出现 timeout 的连接了,从 redis 连接池里面取出的连接都是可用的连接了。看似简单的代码,却完美的解决了连接池里面超时连接的问题。同时,就算 Redis server 重启等情况,也能保证连接自动重连。

Jedis的使用及配置优化

从本地的字典中将key对于的值删除。

jedis就是基于ja语言的redis客户端,集成了redis的命令作,提供了连接池管理。

异常3:Caused by: io.lettuce.core.RedisCommandExecutionException: CLUSTERDOWN The cluster is down

redis-cli是redis提供的客户端,可以看作一个shell程序,它可以发送命令对redis进行作。

jedis直连,本质是定义一个tcp连接,然后使用socket技术进行通信

每次作创建一个jedis对象,执行完毕后关闭连接,对应的就是一次Tcp连接。

预先生成一批jedis连接对象放入连接池中,当需要对redis进行作时从连接池中借用jedis对象,作完成后归还。这样jedis对象可以重复使用,避免了频繁创建socket连接,节省了连接开销。

这里只是对连接池进行一个简单使用,实际开发通常会对JedisPool进行封装,进行一些参数配置和方法定义等,在使用Jedis API时,也会对常用API进行封装,方便程序调用

对于企业级开发来说,连接池的合理使用是非常重要的,如果设置不当会引起很多不必要的麻烦,容易造成线上的故障。

其实关于配置是一个比较难或者说没有确定的部分,这里只能给出一些思路和解决一些异常的方法。

为了方便使用,Jedis提供了 JedisPoolConfig ,它本身继承了 GenericObjectPoolConfig 设置了一些空闲监测设置

其实这个参数是比较难确定的,举个例子:

对于适合的maxTotal而言,我们需要考虑

无法从资源池获取到资源,原因是获取空闲连接超时了。

无法从资源池获取到资源,原因是池子中资源已经耗尽了。

ja怎么模拟redis缓存超时

这是一个小概率的算法,基本的设想是我们的样本代表整个键空间,然后我们继续失效直到将要失效的键百分比小于25%。

从expires中查找key的过期时间,如果不存在说明对应keorg.apachemonsy没有设置过期时间,直接返回。

如果是sle机器,则直接返回,因为Redis为了保证数据一致性且实现简单,将缓存失效的主动权交给Master机器,sle机器没有权限将key失效。

主动失效机制

主动失效机制也叫积极失效机制,即服务端定时的去检查失效的缓存,如果失效则进行相应的作。

我们都知道Redis是单线程的,基于驱动的,Redis中有个EventLoop,EventLoop负责对两类进行处理:

一类是IO,这类是从底层的多路复用器分离出来的。

一类是定时,这类主要用来对某个任务的定时执行。

php redis 长连接 多久会断

6.原理:其实使用了redis的话为什么数据库不会崩溃是因为redis连接数为300,这样数据库同时连接数也是300多,所以不会挂掉,至于redis为什么设置为300是因为设置的太高就会报错(连接被拒绝)或者等待超时(就算设置等待超时的时间很长也会报这个错)。

$redis->connect($host, $port, $timeout);

Caused by: redis.clients.jedis.exceptions.JedisConnectionException: ja.SocketTimeoutException: connect timed out

redis怎么加索引

前言:事先说明:在实际应用中这种做法设计需要各位读者自己设计,本文只提供一种思想。准备工作:安装后本地数redis,使用mysql数据库,事先插入1000万条数据,可以参考我之前的文章插入数据,这里不再细说。我大概的做法是这样的,编码使用多线程访问我的数据库,在访问数据库前先访问redis缓存没有的话在去查询数据库,需要注意的是redis连接数设置为300,不然会出现很多报错。

贴一下代码吧

123456780111213141516171819202122232425

package select; import ja.sql.Connection;import ja.sql.DriverMar;import ja.sql.ResultSet;import ja.sql.SQLException;import ja.sql.Statement; import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool; public class ThreadToMysql extends Thread { public String teacherName; public String password; public JedisPool pool; public ThreadToMysql(String teacherName, String password,JedisPool pool) {//构造函数传入要查询登录的老师姓名和密码 this.teacherName=teacherName; this.password=password; this.pool=pool; } public void run() { Jedis jedis = pool.getResource(); Long startTime=System.currentTimeMillis();//开始时间 if (jedis.get(teacherName)!=null) { Long entTime=System.currentTimeMillis();//开始时间 System.out.println(currentThread().getName()+" 缓存得到的结果: "+jedis.get(teacherName)+" 开始时间:"+startTime+" 结束时间:"+entTime+" 用时:" +(entTime-startTime)+"ms"); pool.returnResource(jedis); System.out.println("释放该redis连接"); } else { String = "jdbc:mysql://127.0.0.1/teacher"; String name = "com.mysql.jdbc.Driver"; String user = "root"; String password = "123456"; Connection conn = null; try { Class.forName(name); conn = DriverMar.getConnection(, user, password);//获取连接 conn.setAutoCommit(false);//关闭自动提交,不然connmit()运行到这句会报错 } catch (ClassNotFoundException e1) { e1.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } if (conn!=null) { String sql="select t_name from test_teacher where t_name='"+teacherName+"' and t_password='"+password+"' ";//SQL语句 String t_name=null; try { Statement stmt=conn.createStatement(); ResultSet rs=stmt.executeQuery(sql);//获取结果集 if (rs.next()) { t_name=rs.getString("t_name"); jedis.set(teacherName, t_name); System.out.println("释放该连接"); } connmit(); stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); }finally { pool.returnResource(jedis); System.out.println("释放该连接"); } Long end=System.currentTimeMillis(); System.out.println(currentThread().getName()+" 数据库得到的查询结果:"+t_name+" 开始时间:"+startTime+" 结束时间:"+end+" 用时:"+(end-startTime)+"ms"); } else { System.out.println(currentThread().getName()+"数据库连接失败:"); } } } }

我的数据库表数据是这样的。可以看到我的t_name是1-10000000,密码固定123456.利用循环创建线程很好做传入循环的次数作为查询的t_name就行了

采用redis缓存替换加索引的方案

1.在200并发访问下:这个问题绕了很多弯路,根据网上的很多方案,以为是redis集群配置成了主从模式,但是springboot连接使用的是cluster模式,发现问题出在spring.redis.timeout=0这条配置上。

次访问结果:由于次访问缓存不存在该数据,速度很慢

最慢90多秒

运行第二次访问后(redis数据库已存在数据)的结果:

最慢700多毫秒

2.当我尝试1000线程并发访问时redis直接挂掉,原因在于reids缓存并没有要查找的数据,就从数据库查找,1000个线程同时并发访问数据库等待时间太长了,造成redis连接等待超时(就算把redis的超时等待时间设置为100分钟也没用,会报redis连接被拒绝的错误)

3.当我利用循环事先把100万条数据插入redis缓存后,在1万个线程并发访问测试下只需要5~6秒就拿到了查询结果,效率出奇的快,而且没有报任何错

4.在3的条件下我把并发线程提升到100万个时,测试在百万并发条件下查询性能,发现完全没有压力,每个线程也是几毫秒就能查到结果,这个时候限制我速度的就是电脑CPU了。我的测试电脑是4核的,处理100万个线程起来比较慢,下面是截图,运行到50多万个线程的时候我就停止了运行

好了,以上都是数据库查询的字段没有加索引直接利用redis缓存查找的

1.给t_name和t_password字段加组合索引

我们来看看在有索引且redis缓存事先没有数据的时候,创建100万#最小能够保持idel状态的对象数个线程并发访问的结果

没问题,这样就完成了百万级别下的并发访问,但是这样我的程序创建线程很慢,因为我的电脑4核CPU的(但是要创建100万个线程),这个时候就是硬件设备的性能了,在设备硬件性能足够的条件下是没问题的

以下是我的总结:

1.我的优化方案中只有两种,一种是给查询的字段加组合索引。另一种是给在用户和数据库中增加缓存

2.添加索引方案:面对1~2千的并发是没有压力的,在往上则限制的瓶颈就是数据库连接数了,在上面中我用show global status like 'Max_used_connections’查看数据库可以知道数据库响应连接数是5700多,超过这个数tomcat直接报错连接被拒绝或者连接已经失效

3.缓存方案:在上面的测试可以知道,要是我们事先把数据库的千万条数据同步到redis缓存中,瓶颈就是我们的设备硬件性能了,如我们的主机有几百个核心CPU,就算是千万级的并发下也可以完全无压力,带个用户很好的。

4.索引+缓存方案:缓存事先没有要查询的数据,在一万的并发下测试数据库毫无压力,程序先通过查缓存再查数据库大大减轻了数据库的压力,即使缓存不命中在一万的并发下也能正常访问,在10万并发下数据库依然没压力,但是redis设置连接数300去处理10万的线程,4核CPU处理不过来,很多redis连接不了。我用show global status like 'Max_used_connections'查看数据库发现响应连接数是388,这么低所以数据库是不会挂掉的。

5.使用场景:a.几百或者2000以下并发直接加上组合索引就可以了。b.不想加索引又高并发的情况下可以先事先把数据放到缓存中,硬件设备支持下可解决百万级并发。c.加索引且缓存事先没有数据,在硬件设备支持下可解决百万级并发问题。d.不加索引且缓存事先没有数据,不可取,要80多秒才能得到结果,用户体验极。

说明:本文不代表实际应用开发场景,更多的是提供一种思想,一种解决方案,如有错误,请指正,谢谢

redis synctimeout 设置多少

如果用户闲置超过60秒,这个键将会被删除,只有访问时间值小于60秒的页面才会被记录。作设备:戴尔电脑

综合分析一下redis连接数有多少?是否超过了max open files的限制?

直接top看看redis是否跑满CPU等等。

还有超时时间配置多少等等。

redis 修改配置 怎么让配置生效

at org.springframework.data.redis.connection.jedis.JedisClusterConnection.convertJedisAccessException(JedisClusterConnection.ja:3999)

作系统:win10

2、解决办法:调整JedisPoolConfig中maxActive为适合自己系统的阀值。

步、首先进入redis的安装目录,cmd下运行“redis-server.exe”开启redis服务。

第二步、打开一个同样的cmd窗口,输入“redis-cli.exe”,进入客户端,然后输入config get ,获取所有配置,如下图所示。

第三步、可以通过config set 命令来设置配置,设置logll,也就是日志级别为not,然后通过config get 命令获取值,如下图所示。

第四步、首先,一定会想redis能不能像mysql那样指定端口,然后就是设置超时时间,也就是当redis多久没有使用时,redis自动关闭连接。

上面的命令是让redis在启动的时候加载配置文件中的配置,如果改过配置文件的话,需要用到,没改过则不用。(有的windows系统配置文件可能不叫redis.config,我的是,redis.windows.config)

redis挂了会链接数据库吗

而且有个弊端,百万级的并发访问需要事先把数据放到缓存中,在实际中并不对于jedis同理是使用ja语言作redis,双方都遵循redis提供的协议,按照协议开发对应的客户端。科学(因为并不知道那些是热点数据),下面来看看如何使用索引加缓存的效果

不会。Redis挂掉,客户端尝试连接Redis数据库时就会失败,是因为Redis是一个内存型数据库,所有数据都保存在内存中,Redis挂掉,则客户端无法访问这些数据,此时客户端尝试连接Redis数据库,就会收到连接超时或连接拒绝的错误消息。