SpringBoot整合SpringSeesion实现Redis缓存
使用Spring Boot开发项目时我们经常需要存储Session,因为Session中会存一些用户信息或者登录信息。传统的web服务是将session存储在内存中的,一旦服务挂了,session也就消失了,这时候我们就需要将session存储起来,而Redis就是用来缓存seesion的一种非关系型数据库,我们可以通过配置或者注解的方式将Spring Boot和Redis整合。而在分布式系统中又会涉及到session共享的问题,多个服务同时部署时session需要共享,Spring Session可以帮助我们实现这一功能。将Spring Session集成到Spring Boot框架中并使用Redis进行缓存是目前非常流行的解决方案,接下来就跟着我一起学习吧。
工具/材料IntelliJ IDEA
首先我们创建一个Spring Boot 2x的项目,在applicationproperties配置文件中添加Redis的配置,Spring和Redis的整合可以参考我其他的文章,此处不再详解。我们设置服务端口serverport为8080端口用于启动第一个服务。
接下来我们需要在pom文件中添加spring-boot-starter-data-redis和spring-session-data-redis这两个依赖,spring-boot-starter-data-redis用于整合Spring Boot和Redis,spring-session-data-redis集成了spring-session和spring-data-redis,提供了session与redis的整合方案。
接下来我们创建一个配置类RedisSessionConfig,这个类使用@Configuration注解表明这是一个配置类。在这个类上我们同时添加注解@EnableRedisHttpSession,表示开启Redis的Session管理。如果需要设置失效时间可以使用@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)表示一小时后失效。若同时需要设置Redis的命名空间则使用@EnableRedisHttpSession(maxInactiveIntervalInSeconds=3600, redisNamespace="{springsessionredisnamespace}") ,其中{springsessionredisnamespace}表示从配置文件中读取这个命名空间。
配置完成后我们写一个测试类SessionController,在这个类中我们写两个方法,一个方法用于往session中存数据,一个用于从session中取数据,代码如下图所示,我们存取请求的url。启动类非常简单,一般都是通用的,我们创建一个名为SpringbootApplication的启动类,使用main方法启动。
接下来我们使用Postman分别请求上面两个接口,先请求存数据接口,再请求取数据接口,结果如下图所示,我们可以看到数据已从redis中取出。另外需要注意sessionId的值,这是session共享的关键。
为了验证两个服务是否共享了session,我们修改项目的配置文件,将服务端口serverport改为8090,然后再启动服务。此时我们不必在请求存数据的接口,只需要修改请求端口号再一次请求取数据的接口即可。由下图可以看到两次请求的sessionId值相同,实现了session的共享。
以上我们完成了SpringBoot整合SpringSeesion实现Redis缓存的功能,在此我们还要推荐一个Redis的可视化工具RedisDesktopManager,我们可以配置Redis数据库的连接,然后便可以非常直观地查看到存储到Redis中的session了,如下图所示,session的命名空间是share,正是从配置文件中读取到的。
特别提示如果Redis服务器是很多项目共用的,非常建议配置命名空间,否则同时打开多个项目的浏览器页面可能会导致session错乱的现象。
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多秒才能得到结果,用户体验极差。
6原理:其实使用了redis的话为什么数据库不会崩溃是因为redis最大连接数为300,这样数据库最大同时连接数也是300多,所以不会挂掉,至于redis为什么设置为300是因为设置的太高就会报错(连接被拒绝)或者等待超时(就算设置等待超时的时间很长也会报这个错)。
一、Redis集群介绍
Redis真的是一个优秀的技术,它是一种key-value形式的NoSQL内存数据库,由ANSI C编写,遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 Redis最大的特性是它会将所有数据都放在内存中,所以读写速度性能非常好。Redis是基于内存进行操作的,性能较高,可以很好的在一定程度上解决网站一瞬间的并发量,例如商品抢购秒杀等活动。
网站承受高并发访问压力的同时,还需要从海量数据中查询出满足条件的数据,需要快速响应,前端发送请求、后端和mysql数据库交互,进行sql查询操作,读写比较慢,这时候引入Redis ,把从mysql 的数据缓存到Redis 中,下次读取时候性能就会提高;当然,它也支持将内存中的数据以快照和日志的形式持久化到硬盘,这样即使在断电、机器故障等异常情况发生时数据也不会丢失,Redis能从硬盘中恢复快照数据到内存中。
Redis 发布了稳定版本的 50 版本,放弃 Ruby的集群方式,改用 C语言编写的 redis-cli的方式,是集群的构建方式复杂度大大降低。Redis-Cluster集群采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。
为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。
redis-cluster投票:容错,投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉。
集群中至少应该有奇数个节点,所以至少有三个节点,每个节点至少有一个备份节点,所以下面使用6节点(主节点、备份节点由redis-cluster集群确定)。6个节点分布在一台机器上,采用三主三从的模式。实际应用中,最好用多台机器,比如说6个节点分布到3台机器上,redis在建立集群时为自动的将主从节点进行不同机器的分配。
二、单机redis模式
下载源码redis50并解压编译
wget http://downloadredisio/releases/redis-500targz
tar xzf redis-500targz
cd redis-500
make
redis前端启动需要改成后台启动
修改redisconf文件,将daemonize no -> daemonize yes
vim redisconf
启动redis
/www/server/redis/src/redis-server /www/server/redis/redisconf
查看redis是否在运行
ps aux|grep redis
现在是单机redis模式完成。
三、redis集群模式:
1创建6个Redis配置文件
cd /usr/local/
mkdir redis_cluster //创建集群目录
cd redis_cluster
mkdir 7000 7001 7002 7003 7004 7005//分别代表6个节点
其对应端口 7000 7001 7002 70037004 7005
2复制配置文件到各个目录
cp /www/server/redis/redisconf /usr/local/redis_cluster/7000/
cp /www/server/redis/redisconf /usr/local/redis_cluster/7001/
cp /www/server/redis/redisconf /usr/local/redis_cluster/7002/
cp /www/server/redis/redisconf /usr/local/redis_cluster/7003/
cp /www/server/redis/redisconf /usr/local/redis_cluster/7004/
cp /www/server/redis/redisconf /usr/local/redis_cluster/7005/
3分别修改配置文件
vim /usr/local/redis_cluster/7000/redisconf
vim /usr/local/redis_cluster/7001/redisconf
vim /usr/local/redis_cluster/7002/redisconf
vim /usr/local/redis_cluster/7003/redisconf
vim /usr/local/redis_cluster/7004/redisconf
vim /usr/local/redis_cluster/7005/redisconf
如下
port 7000 #端口
cluster-enabled yes #启用集群模式
cluster-config-file nodes_7000conf #集群的配置 配置文件首次启动自动生成
cluster-node-timeout 5000 #超时时间 5秒
appendonly yes #aof日志开启 它会每次写操作都记录一条日志
daemonize yes #后台运行
protected-mode no #非保护模式
pidfile /var/run/redis_7000pid
//下面可以不写
#若设置密码,master和slave需同时配置下面两个参数:
masterauth "jijiji" #连接master的密码
requirepass "jijiji" #自己的密码
cluster-config-file,port,pidfile对应数字
4启动节点
cd /www/server/redis/src/
/redis-server /usr/local/redis_cluster/7000/redisconf
/redis-server /usr/local/redis_cluster/7001/redisconf
/redis-server /usr/local/redis_cluster/7002/redisconf
/redis-server /usr/local/redis_cluster/7003/redisconf
/redis-server /usr/local/redis_cluster/7004/redisconf
/redis-server /usr/local/redis_cluster/7005/redisconf
查看redis运行
ps aux|grep redis
5启动集群
/www/server/redis/src/redis-cli --cluster create 127001:7000 127001:7001 127001:7002 127001:7003 127001:7004 127001:7005 --cluster-replicas 1
这里使用的命令是create,因为我们要创建一个新的集群。 该选项--cluster-replicas 1意味着我们希望每个创建的主服务器都有一个从服。
输入yes
至此,Reids5 集群搭建完成。
6检查Reids5集群状态
可以执行redis-cli --cluster check host:port检查集群状态slots详细分配。
redis-cli --cluster info 127001:7000
7停止Reids5集群
(1)因为Redis可以妥善处理SIGTERM信号,所以直接kill -9也是可以的,可以同时kill多个,然后再依次启动。
kill -9 PID PID PID
(2)redis5 提供了关闭集群的工具,修改文件: /www/server/redis/utils/create-cluster/create-cluster
端口PROT设置为6999,NODES为6,工具会生成 7000-7005 六个节点 用于操作。
修改后,执行如下命令关闭集群:
/www/server/redis/utils/create-cluster/create-cluster stop
重新启动集群:
/www/server/redis/utils/create-cluster/create-cluster start
8帮助信息
执行redis-cli --cluster help,查看更多帮助信息
redis-cli --cluster help
吉海波
大致为两种措施:
一、脚本同步:
1、自己写脚本将数据库数据写入到redis/memcached。
2、这就涉及到实时数据变更的问题(mysqlrowbinlog的实时分析),binlog增量订阅Alibaba的canal,以及缓存层数据丢失/失效后的数据同步恢复问题。
二、业务层实现:
1、先读取nosql缓存层,没有数据再读取mysql层,并写入数据到nosql。
2、nosql层做好多节点分布式(一致性hash),以及节点失效后替代方案(多层hash寻找相邻替代节点),和数据震荡恢复了。
redis实现数据库缓存的分析:
对于变化频率非常快的数据来说,如果还选择传统的静态缓存方式(Memocached、FileSystem等)展示数据,可能在缓存的存取上会有很大的开销,并不能很好的满足需要,而Redis这样基于内存的NoSQL数据库,就非常适合担任实时数据的容器。
但是往往又有数据可靠性的需求,采用MySQL作为数据存储,不会因为内存问题而引起数据丢失,同时也可以利用关系数据库的特性实现很多功能。所以就会很自然的想到是否可以采用MySQL作为数据存储引擎,Redis则作为Cache。
MySQL到Redis数据复制方案,无论MySQL还是Redis,自身都带有数据同步的机制,比较常用的MySQL的Master/Slave模式,就是由Slave端分析Master的binlog来实现的,这样的数据复制其实还是一个异步过程,只不过当服务器都在同一内网时,异步的延迟几乎可以忽略。那么理论上也可用同样方式,分析MySQL的binlog文件并将数据插入Redis。
因此这里选择了一种开发成本更加低廉的方式,借用已经比较成熟的MySQLUDF,将MySQL数据首先放入Gearman中,然后通过一个自己编写的PHPGearmanWorker,将数据同步到Redis。比分析binlog的方式增加了不少流程,但是实现成本更低,更容易操作。
8GB的内存。Redis的至少8GB的内存,最好能达到16GB或者甚至更多,以提供足够的缓存和内存大小,释放Redis的最佳性能。Redis是一款开源的、高性能的键值存储,常被称作是一款数据结构服务器、缓存服务器。
hello 大家好,我是七淅(xī)。
Redis 大家肯定不陌生,但在使用层面看不到的地方,就容易被忽略。今天想和大家分享的内容是 Redis 各个缓冲区的作用、溢出的后果及优化方向 。
在开始正文前,想多叨叨几句。不管是 Redis 还是其他中间件,底层很多原理都是相似的,设计思想都是通用的。
大家以后如果在学什么新框架/组件,可以尽量和已经学过的知识点进行联想,这样会更容易理解点的,不至于说死记硬背。
比如现在说到的缓冲区,它的目的是什么呢?
无它,为了性能。
要么缓存数据, 提高响应速度 。比如 MySQL 中有个 change buffer
要么担心消费者速度跟不上生产,怕 数据丢失 。所以需要把生产数据先暂存起来。Redis 的缓冲区就是这个作用。
另外,消费者速度跟不上,如果是同步处理的话,那是不是也会拖慢生产者,所以这里其实也是在保证生产者的速度。
可能有的读者会说:扯淡,消费者都跟不上了,生产者再快有什么用?
其实有没有一种可能,生产者根本不关心消费者什么时候用呢?前者是负责把后者需要的东西处理好给它就完事了。生产者很忙,还有其他一大堆数据要处理,不能慢慢等消费者同步消费完才去做其他事情。
好像开头扩展得有点多,我收一收,下面会详细说到。有疑问的小伙伴请上车,七淅正式发车了。
首先 Redis 有什么缓冲区呢?
一共 4 个:
服务器端会给 每个连接的客户端 都设置了一个输入缓冲区。
暂存请求数据。
输入缓冲区会先把客户端发送过来的命令暂存起来,Redis 主线程再从输入缓冲区中读取命令,进行处理。
为了避免客户端和服务器端的请求发送和处理速度不匹配,这点和等下要说的输出缓冲区是一样的。
首先缓冲区是一块固定大小的内存区域,如果要把这个地方填满的话,那 Redis 会直接把客户端连接关闭。
保护自己嘛,你客户端挂了总比我服务端挂了好,服务端一挂就是所有客户端都没用了。
那填满缓冲区就有 2 个情况了:
那么把上述原理对应到 Redis 的场景。
一下子填满的情况可以是往 Redis 里写大量数据,百万千万数量级那种。
另一个情况可以是 Redis 服务端因执行耗时操作,阻塞住了,导致没法消费输入缓冲区数据。
对应上面 2 个溢出场景,优化方向很自然就有了。
一下子填满的情况,是不是可以考虑不要一下子写这么多数据,能否拆下数据(其实一下子写大量数据本身就不合理哈)
另外,是否可以调高缓冲区大小呢?
这个其实是不行的哈,因为没有可以设置的地方,目前服务端默认为每个客户端输入缓冲区分配的大小是 1GB。
那轮到第 2 个溢出场景:两边处理速度不一致。
正常来说,服务端不应该出现长时间阻塞,所以需要看看是什么原因导致的阻塞,解决到就好了。
同输入缓冲区,服务器端也会给 每个连接的客户端 都设置了一个输出缓冲区。
同上,也是暂存请求数据。
这个地方其实我在文章开头说的,生产者不关心消费者什么时候用,只负责把消费者之前请求的东西处理好就完事了。
服务端一般都会和多个客户端连接,加上 redis 网络通信模块是单线程的(即使是新版本支持多线程也一样)
假如没有输出缓冲区会发生什么事呢?
服务端处理了很多客户端 A 的请求,需要经过网络这一耗时操作,返回给客户端 A。在这个过程中,客户端 B 的请求一直得不到服务端处理和响应,这样吞吐量就上不去了。
有了缓冲区之后,至少能解放服务端,让它去处理客户端 B 的请求。
这里也是同输入缓冲区,我就不啰嗦了,溢出的话服务端也会关闭客户端连接。
类似的,不要一下子读大量数据;不持续在线上执行 MONITOR 命令。
而输出缓冲区的大小是可以通过 client-output-buffer-limit 来设置的。
但是一般来说,我们都不用改,因为默认情况就够了,这里了解下就好。
温馨提示下,如果对 Redis 同步/复制不了解的读者,比如不知道全量/增量复制,建议可以看下我这篇文章:一文让你明白Redis主从同步。
下面回到正题哈。
有复制肯定有主从,而主从间的数据复制包括全量复制和增量复制两种。
全量复制是同步所有数据,而增量复制只会把主从库网络断连期间主库收到的命令,同步给从库。
暂存数据。
主节点上会为 每个从节点 都维护一个复制缓冲区。
在全量复制时,主节点在向从节点传输 RDB 文件的同时,会继续接收客户端发送的写命令请求,并保存在复制缓冲区中,等 RDB 文件传输完成后,再发送给从节点去执行。
从节点接收和加载 RDB 较慢,同时主节点接收到了大量的写命令,写命令在复制缓冲区中就会越积越多,最后就会溢出。
一旦溢出,主节点会直接关闭和从节点进行复制操作的连接,导致全量复制失败
可以控制主节点数据量在 2~4GB(仅供参考),这样可以让全量同步执行得更快些,避免复制缓冲区累积过多命令
也可以调整缓冲区大小,还是之前的 client-output-buffer-limit 参数。
比如: config set client-output-buffer-limit slave 512mb 128mb 60
这个是在新增复制用到的缓冲区。
暂存数据。
从节点意外断开连接后重连,可从该缓冲区同步期间没同步到的数据。
不会溢出。(想不到吧jpg)
该缓冲区本质是一个 固定长度,先进先出的队列 ,默认 1MB。
所以当队列被占满,不是报错,也不像上面几个缓冲区直接关闭连接。而是覆盖最早进入队列的数据。
因此,如果有从节点还没有同步这些旧命令数据,就会导致主从节点重新进行全量复制,而不是增量复制。
调整复制积压缓冲区的大小,参数是: repl_backlog_size
redis缓存原理是sql语句时key值,查询结果resultSet是value,当同一个查询语句访问时(select from t_product),只要曾经查询过,调用缓存直接返回resultSet,节省了数据库读取磁盘数据的时间。
redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
save seconds updates,save配置,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。这个可以多个条件配合,比如默认配置文件中的设置,就设置了三个条件。
appendonly yes/no ,appendonly配置,指出是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面的save条件来同步的,所以有的数据会在一段时间内只存在于内存中。
扩展资料
redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。
存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
redis的官网地址,redisio。(域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)
背景介绍:我们系统使用的缓存服务是付费版的阿里云的redis集群服务,配置是4核,16G。redis的集群结构如下:分为四个节点DB0,DB1,DB2,DB3
之前的存储方案是存储的商品促销数据,结构是:
KEY FIELD VALUE来存储。其中KEY是一个固定的字符串"zy:prom:wx",FIELD则是商品sku,VALUE是商品促销的具体信息。这种方式导致我们存入缓存服务器的数据一直集中在DB0节点上,在访问量过大时,该节点会在短时间内受到到的访问压力很大,DB0的cpu瞬间达到100%以上,造成服务卡顿甚至不可用。而相比之下DB1,DB2,DB3的节点cpu压力却很小,可以忽略不计。这是为什么?最后询问了阿里的技术,他们说我们的数据存储的方法有误,具体是我们的key设置有误。与阿里的技术对话如下:
所以我们后来改造了方案把key的组成变程了"prom:wx:sku",这样key就会根据sku的不同而不同,增大了key的离散度,这样key通过hash算出来的值,就会不同,使得所有的数据不再存放到同一台节点上,完美解决问题。
修改后的存储分布情况如下图:DB0、DB1、DB2、DB3四个节点数据均匀分布。
对修改前后两天同一时间区间的缓存服务器的cpu压力情况对比:
0条评论