2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Linux 安装Redis-6.2.5 配置及使用(RDB与AOF持久化 sentinel机制 主从复制 Spring Boot 集成 Redis)

Linux 安装Redis-6.2.5 配置及使用(RDB与AOF持久化 sentinel机制 主从复制 Spring Boot 集成 Redis)

时间:2019-07-02 18:23:20

相关推荐

Linux 安装Redis-6.2.5 配置及使用(RDB与AOF持久化 sentinel机制 主从复制 Spring Boot 集成 Redis)

CentOS 7 安装Redis-6.2.5版本

Redis采用的是基于内存的单进程 单线程模型 的KV数据库,由C语言编写。官方提供的数据是可以达到100000+的qps

应用场景:

令牌(Token)生成短信验证码发布订阅分布式锁计数器缓存(热点数据)

官网地址:https://redis.io

获取Redis安装包

# 使用wget命令下载安装包,安装wget命令下载工具yum -y install wget# 创建redis目录mkdir /usr/local/redis -pcd /usr/local/redis# 下载安装包wget http://download.redis.io/releases/redis-6.2.5.tar.gz

官网下载地址,及安装启动教程:https://redis.io/download

通过官网下载指定版本,然后使用传输文件工具上传到Linux服务器的/usr/local/redis 路径上(没有创建mkdir /usr/local/redis -p)

https://download.redis.io/releases

安装gcc/g++编译器(要大于>4.8.5版本),及make编译

#使用命令查看gcc/g++版本gcc -vg++ -v#gcc 版本 4.8.5 0623 (Red Hat 4.8.5-36) (GCC)# 先进入此目录cd /etc/scl/conf# 使用SCL管理, Red Hat 软件包源yum -y install centos-release-scl# 安装devtoolset-9依赖包yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils# 临时有效,退出 shell 或重启会恢复原 gcc 版本scl enable devtoolset-9 bash# 永久有效# echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile# 查看gcc/g++版本gcc -vg++ -v#gcc version 9.3.1 (Red Hat 9.3.1-2) (GCC)# 回到redis目录cd /usr/local/redis# 解压redis安装包tar -zxvf redis-6.2.5.tar.gz# make编译cd redis-6.2.5make# 编译成功#Hint: It's a good idea to run 'make test' ;)# 当前终端运行redis服务进程./src/redis-server#29211:C 23 Dec 13:58:49.608 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo#29211:C 23 Dec 13:58:49.608 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=29211, just started#29211:C 23 Dec 13:58:49.608 # Warning: no config file specified, using the default config. In order to specify a config file use ./src/redis-server /path/to/redis.conf#29211:M 23 Dec 13:58:49.613 * Increased maximum number of open files to 10032 (it was originally set to 1024).#29211:M 23 Dec 13:58:49.613 * monotonic clock: POSIX clock_gettime#_._# _.-``__ ''-._#_.-`` `. `_. ''-._ Redis 6.2.5 (00000000/0) 64 bit# .-`` .-```. ```\/ _.,_ ''-._ # ( ', .-` | `, )Running in standalone mode# |`-._`-...-` __...-.``-._|'` _.-'|Port: 6379# | `-._ `._ /_.-' |PID: 29211# `-._ `-._ `-./ _.-' _.-'# |`-._`-._ `-.__.-' _.-'_.-'| # | `-._`-._ _.-'_.-' | https://redis.io # `-._ `-._`-.__.-'_.-' _.-'# |`-._`-._ `-.__.-' _.-'_.-'| # | `-._`-._ _.-'_.-' | # `-._ `-._`-.__.-'_.-' _.-'#`-._ `-.__.-' _.-' #`-._ _.-' # `-.__.-' ##29211:M 23 Dec 13:58:49.616 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.#29211:M 23 Dec 13:58:49.616 # Server initialized#29211:M 23 Dec 13:58:49.616 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.#29211:M 23 Dec 13:58:49.616 * Ready to accept connections# 按键Ctrl + C 终止Redis服务进程(先不要按)#Redis is now ready to exit, bye bye...

打开另外一个终端

# 打开另外一个终端# 查看进程信息,一行color=auto 6379(没有运行),两行才算运行ps aux | grep redis#root29211 0.1 0.2 162480 10256 pts/0 Sl+ 13:58 0:02 ./src/redis-server *:6379#root29536 0.0 0.0 112724 984 pts/1 S+ 14:21 0:00 grep --color=auto redis# 查看端口是否在运行,显示行数是在运行,没显示(没运行)netstat -tunlp | grep 6379#tcp 00 0.0.0.0:6379 0.0.0.0:*LISTEN29211/./src/redis-s #tcp6 00 :::6379 :::*LISTEN29211/./src/redis-s

回到原来的终端

# 回到原来的终端,终止redis服务进程按键Ctrl + C#Redis is now ready to exit, bye bye...# 修改redis.conf文件,按键/ 输入需要查看修改的内容,然后回车,如:/protected-modevim redis.conf#运行远程连接需要调整,注释掉#bind 127.0.0.1 -::1#bind 127.0.0.1 -::1#关闭密码验证,yes 修改为 noprotected-mode no#设置后端启动 no 修改为 yesdaemonize yes# 占时不设置密码#(无需)关闭redis设置密码(默认是注释掉的,就是关闭)# requirepass foobared#(需要)开启redis设置密码,还要开启密码验证requirepass 123#开启密码验证,no 修改为 yesprotected-mode yes# 运行redis服务 加上redis.conf配置文件./src/redis-server redis.conf# 查看redis服务进程信息,以及 端口是否在运行ps aux | grep redis && netstat -tunlp | grep 6379#root32082 0.2 0.2 162480 9900 ? Ssl 15:22 0:00 ./src/redis-server *:6379#root32114 0.0 0.0 112724 984 pts/1 S+ 15:23 0:00 grep --color=auto redis#tcp 00 0.0.0.0:6379 0.0.0.0:*LISTEN32082/./src/redis-s #tcp6 00 :::6379 :::*LISTEN32082/./src/redis-s# 关闭防火墙,自己玩没必要开启防火墙# 查看防火状态(Active: inactive (dead)无效; Active: failed关闭; Active: active (running)运行)systemctl status firewalld# 关闭防火墙systemctl stop firewalld# 禁用开机启动systemctl disable firewalld# 启动防火墙#systemctl start firewalld # 开启开机启动#systemctl enable firewalld# 重启防火墙#systemctl restart firewalld# 要开启防火墙远程访问,需要开放redis端口 6379# 查看是否开放端口firewall-cmd --list-port# 开放6379端口firewall-cmd --add-port=6379/tcp --permanent#success# 关闭6379端口firewall-cmd --remove-port=6379/tcp --permanent# 重新加载信息firewall-cmd --reload#success

Redis可视化工具 Redis Desktop Manager

使用Redis可视化工具 Redis Desktop Manager v.0.8.8.384,网上找一个多的很,使用的版本号是v.0.8.8.384

# 先关闭redis服务 pwd /usr/local/redis/redis-6.2.5./src/redis-cli -p 6379 shutdown# 查看redis服务是否关闭ps aux | grep redis && netstat -tunlp | grep 6379#已关闭#root35336 0.0 0.0 112724 988 pts/1 S+ 17:35 0:00 grep --color=auto redis# 设置开机自动启动Redis服务(systemd对应的进程管理命令是systemctl)vim /etc/systemd/system/redis-server.service# 输入内容:[Unit]Description=redis-serverAfter=network.tartget[Service]Type=forkingExecStart=/usr/local/redis/redis-6.2.5/src/redis-server /usr/local/redis/redis-6.2.5/redis.confPrivateTmp=true[Install]WantedBy=multi-user.target# 开机自动启动redis-server 与 redis-server重启systemctl daemon-reloadsystemctl enable redis-serversystemctl restart redis-serversystemctl status redis-server#● redis-server.service - redis-server# Loaded: loaded (/etc/systemd/system/redis-server.service; enabled; vendor preset: disabled)# Active: active (running) since 四 -12-23 17:45:09 CST; 2s ago# Process: 35518 ExecStart=/usr/local/redis/redis-6.2.5/src/redis-server /usr/local/redis/redis-6.2.5/redis.conf (code=exited, status=0/SUCCESS)# Main PID: 35521 (redis-server)# Tasks: 5# Memory: 8.3M# CGroup: /system.slice/redis-server.service# └─35521 /usr/local/redis/redis-6.2.5/src/redis-server *:6379##12月 23 17:45:09 localhost.localdomain systemd[1]: Starting redis-server...#12月 23 17:45:09 localhost.localdomain systemd[1]: Started redis-server.# 启动服务 与 查看状态systemctl start redis-serversystemctl status redis-server# 停止 与 重启systemctl stop redis-serversystemctl restart redis-server# 开启开机启动 与 禁用开机启动systemctl enable redis-serversystemctl disable redis-server

Redis的6种数据类型

String(字符串)

string在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。类似java中的Map<String,String>应用场景:可以做验证码

# redis-cli客户端连接redis-server服务器/usr/local/redis/redis-6.2.5/src/redis-cli -p 6379# 新增或修改指定key的值set key val# 获取指定key的值get key# 删除指定key的值del key

List(列表)

list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。类似Java Map<String,Linked < String > >应用场景非常多:如twitter的关注列表、粉丝列表等都可以用Redis的list结构来实现;再如有的应用使用Redis的list类型实现一个简单的轻量级消息队列,生产者push,消费者pop/bpop;

# 从头部开始添加lpush key v1 v2 ....# 从尾部添加rpush key v1 v2 ...# 查看列表 lrange key start end (start从0开始,负数表示到链表尾部的位置,-1链表尾部,-2尾部倒数第二)lrange key 0 -1# 删除链表第一个元素lpop key# 删除链表倒数第一个元素rpop key# 获取链表元素个数llen key# 扩展命令(lpushx头部/rpushx) 仅当参数中指定的key存在时,向关联的list的头部或尾部插入value。如果不存在,将不进行插入lpushx key valuerpushx key value

Hash(字典)

hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。类似Java Map<String,HashMap<String,String>>

# 添加或修改指定keyhset key field val# 设置多个keyhmset key f1 v1 f2 v2# 获取值hget key field# 获取多个值hmget key f1 f2# 删除指定值hdel key f1 f2# 删除整个列表del key

Set(集合)

set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。时间复杂度的优劣对比常见的数量级大小:越小表示算法的执行时间频度越短,则越优;O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)//2的n方<O(n!)<O(nn)//n的n方

# 添加删除元素sadd k m1 m2srem k m1 m2# 获取set中所有成员smembers k# 求差集合(A、B两个集合,获取属于A但是B中没有的元素)sdiff A B# 求交集(A、B两个集合,AB两个集合都有的元素)sinter A B# 求并集sunion A B

Sorted Set(有序集合)

有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联整数值或双精度浮点数double类型的分数。redis正是通过整数或浮点数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但整数值或双精度浮点数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。应用场景:热点排行榜

#添加元素zadd ke 10 m1 9 m2 8 m3#获得元素,#获取指定成员对应的分数zscore ke m1#获取集合元素个数zcard ke#删除元素zrem ke m1#范围查询#zrange key start stop [withscores],加withscores参数表明返回的成员包含其分数。zrange ke 0 -1zrange ke 0 -1 withscores#照元素分数从大到小的顺序 zrevrange key start stop [withscores] 返回索引从start到stop之间的所有元素(包含两端的元素)zrevrange ke 0 -1 withscores#按照排名范围删除元素zremrangebyrank key start stop,移除下标 0 至 1 区间内的成员zremrangebyrank ke 0 1#按照数值范围删除元素zremrangebyscore key min max,移除所有数值在 1 到 10 内的成员zremrangebyscore ke 1 10

Steam(日志数据结构)

stream是Redis5版本引入的一个新的数据类型,提供了一组允许消费者以阻塞的方式等待生产者向stream中发送的新消息,此外还有一个名为消费者组的概念。消费者组最早是由名为Kafka的流行消息系统引入的。Redis用完全不同的术语重新实现了一个相似的概念,但目标是相同的:允许一组客户端相互配合来消费同一个stream的不同部分的消息。应用场景:适用于消息队列和时间序列存储

# 追加消息 XADD key ID field string [field string ...] ID可以自己指定,例如0-1, 0-2等等,*表示使用时间戳做IDxadd ke * m1 f1 f2 f3 f4 f5xadd ke * m2 f1 f2 f3 f4 f5# 消息长度 XLEN keyxlen ke# 范围查找的命令 XRANGE key start end [COUNT count]#start和end#`-`和`+` 分别代表最小和最大,或者说最老和最新的消息#start和end也可以使用时间戳,而不加上后面的自增ID部分来查询,#COUNT是用来达到多少数量消息之后就停止查找xrange ke - +xrange ke 1640516765000 1640516772621xrange ke - + count 1# 相反范围查找的命令 XREVRANGE key end start [COUNT count]xrevrange ke + -# 删除消息 xdel key ID [ID ...] 这里的删除仅仅是设置了标志位,不影响消息总长度xdel ke 1640516772621-0# 删除整个streamdel ke# 读取消息 XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]# BLOCK是阻塞读,如果填0,则是一直到有消息,否则都是阻塞。XREAD BLOCK 0 STREAMS ke 1640516772621-0# STREAMS后原本写ID的地方,如果使用 $ 则是代表最新的消息的ID#设想,如果你加入一个群聊,不看历史消息,但是从你加入之后的消息都能读到,该怎么做?这种时候就可以用这个了。XREAD COUNT 2 STREAMS ke $

Spring Boot 集成 Redis

Maven依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

Spring Boot 2 的 spring-boot-starter-data-redis 中,默认使用的是lettuce作为redis客户端,它与jedis的主要区别如下:

Jedis是同步的,不支持异步,Jedis客户端实例不是线程安全的,需要每个线程一个Jedis实例,所以一般通过连接池来使用JedisLettuce是基于Netty框架的事件驱动的Redis客户端,其方法调用是异步的,Lettuce的API是线程安全的,所以多个线程可以操作单个Lettuce连接来完成各种操作,同时Lettuce也支持连接池

如果不使用默认的lettuce,使用jedis的话,可以排除lettuce的依赖,手动加入jedis依赖,配置如下:

排除lettuce的依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.1.0</version></dependency>

#配置redis连接#选择数据库,默认值为0spring.redis.database=0#主机地址,默认localhostspring.redis.host=localhost#端口号,默认6379spring.redis.port=6379#密码spring.redis.password=#请求超时时间 0表示只要没拿到数据就一直请求spring.redis.timeout=0#配置lettuce连接池# 连接池最大连接数(使用负值表示没有限制)spring.redis.lettuce.pool.max-active=8# 连接池分配连接最大阻塞等待时间(阻塞时间到,抛出异常。使用负值表示无限期阻塞)spring.redis.lettuce.pool.max-wait=-1# 连接池中的最大空闲连接数spring.redis.lettuce.pool.max-idle=8# 连接池中的最小空闲连接数spring.redis.lettuce.pool.min-idle=0#配置jedis连接池#spring.redis.jedis.pool.max-active=8#spring.redis.jedis.pool.max-wait=-1#spring.redis.jedis.pool.max-idle=8#spring.redis.jedis.pool.min-idle=0

Spring Boot 内置实现的Redis API:

RedisTemplate:

/*** RedisTemplate*/RedisTemplate<Object,Object> redisTemplate;String key = "key";//redis-String类型redisTemplate.opsForValue().set(key, "redisTemplate");redisTemplate.delete(key);//相同key会进行覆盖, 原来是字符串,给user对象覆盖了 ——可以的redisTemplate.opsForValue().set(key, user对象);Object o = redisTemplate.opsForValue().get(key);if(o != null){user = (User)o;System.out.println(user);}//redis-Hash类型Map<String, Object> stu = new HashMap<>();stu.put("1", "山东威");stu.put("2", "山西洲");redisTemplate.opsForHash().putAll("ket", stu);Object o2 = redisTemplate.opsForHash().get("ket", "2");System.out.println(o2);List<Object> list = new ArrayList<>();Iterator<String> it = stu.keySet().iterator();while(it.hasNext()){String next = it.next();System.out.println(next);list.add(next);}List<Object> list1 = redisTemplate.opsForHash().multiGet("ket", list);//list1.forEach(System.out::println); //遍历出 山东威、山西洲list1.forEach(temp-> System.out.println(temp));

StringRedisTemplate:

继承自RedisTemplate,重新实现了序列化策略,使用StringRedisSerialier类来序列化key-value,包括List、Hash、Set等数据结构。操作String类型数据(不是说只能操作redis中的string类型,而是存储数据是string,key也为string的数据)

/*** StringRedisTemplate*/StringRedisTemplate stringRedisTemplate;String key = "key";//stringRedisTemplate.opsForValue().set(string,user对象); //error 放不了对象stringRedisTemplate.opsForValue().set(string,string);//获取Map里的单个值StringRedisTemplate stringRedisTemplate;Map<String, String> stu = new HashMap<>();stu.put("1", "黄秀珠");stu.put("2", "在深圳还好吗");stringRedisTemplate.opsForHash().putAll(key, stu);Object o1 = stringRedisTemplate.opsForHash().get(key,"1");System.out.println(o1); //输出黄秀珠//获取所有Map里的值List<Object> list = new ArrayList<>();Iterator it = stu.keySet().iterator();while(it.hasNext()){String obj = (String)it.next();System.out.println(obj);list.add(obj);}//获取出所有Map里放进的redis里的HashList<Object> objects = stringRedisTemplate.opsForHash().multiGet(key, list);//objects.forEach(System.out::println); //遍历出 黄秀珠、在深圳还好吗objects.forEach(temp-> System.out.println(temp));

修改RedisTemplate序列化规则:

Maven依赖:

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>

使用Jackson2JsonRedisSerialize 替换 默认的jdkSerializeable序列化:

@Configuration@EnableCachingpublic class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(om.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// 字符串序列器StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}}

Jackson2JsonRedisSerialize 序列化后使用栗子:

@AutowiredRedisTemplate<Object, Object> redisTemplate;@AutowiredStringRedisTemplate stringRedisTemplate;//使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化之后@Autowired //上两个error错误无法运行org.springframework.beans.factory.UnsatisfiedDependencyExceptionRedisTemplate<String, Object> redisTemplateJackson;//JsonSerialize会覆盖StringRedisTemplate(原有redis存储) ——redis-String类型 key="key"String key = "key";redisTemplateJackson.opsForValue().set(key, "redisTemplateJacksonSerialize");Object o = redisTemplateJackson.opsForValue().get(key);System.out.println(o);User user = new User(2, "黄秀珠", 22);redisTemplateJackson.opsForValue().set(key, user);Object o1 = redisTemplateJackson.opsForValue().get(key);System.out.println(o1);//JsonSerialize会覆盖StringRedisTemplate(原有redis存储) ——redis-Hash类型 key="ket"Map<String, Object> stu = new HashMap<>();stu.put("1", "山东威");stu.put("2", "山西洲");redisTemplateJackson.opsForHash().putAll("ket", stu);Object o2 = redisTemplateJackson.opsForHash().get("ket", "1");System.out.println(o2);List<Object> list = new ArrayList<>();Iterator it = stu.keySet().iterator();while(it.hasNext()){Object next = it.next();System.out.println(next);list.add(next);}List<Object> list1 = redisTemplateJackson.opsForHash().multiGet("ket", list);list1.forEach(System.out::println);

Redis 常用注解:

@EnableCaching 表示启用缓存支持

@EnableCachingpublic class RedisConfig {...}

@Cacheable 查询可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存

@service // service层@Cacheable(value = "users", key = "#pageIndex", condition = "#pageIndex < 3")@Overridepublic List<User> listAll(int pageIndex) {}//value: 类似Java Map<String-外key,HashMap<String-内key,String>> 外面一层key//key: 内面一层key//condition: 判断是否进行缓存,"#pageIndex < 3"//首先进行 内面一层key(#pageIndex先查,里没有执行method,里有了key再按缓存) and condition = "#pageIndex < 3"

@CachePut 更新标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中

@service // service层@CachePut(value = "users", key = "#pageIndex", condition = "#pageIndex < 3")@Overridepublic List<User> listAllPut(int pageIndex) {}//value: 类似Java Map<String-外key,HashMap<String-内key,String>> 外面一层key//key: 内面一层key//condition: 判断是否存入缓存,"#pageIndex < 3"//首先每次都会执行method 内面一层key(#pageIndex先查,里有key更新缓存,里没有key,要看#pageIndex(key) 是否小于< 3 小于存入/不小于不存入) and condition = "#pageIndex < 3"//错误问题!在idea测试出来,无法更新存入缓存redisMISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.Redis配置为保存RDB快照,但它目前无法在磁盘上持久化。可能修改数据集的命令被禁用,因为此实例被配置为在RDB快照失败时报告写入期间的错误(在bgsave error选项上停止写入)。有关RDB错误的详细信息,请查看Redis日志

@CacheEvict 清除清除缓存元素的方法或类上的。类上时表示其中所有的方法的执行都会触发缓存的清除操作

@service // service层@CacheEvict(value = "users", key = "#pageIndex", condition = "#pageIndex < 3", allEntries = true, beforeInvocation = true)@Overridepublic boolean update(int pageIndex){return true;}//其中value、key和condition的语义与@Cacheable对应的属性类似。//allEntries = true:(清除所有value = "users"里的 外内key); allEntries = 默认false:不清除所有,只清除内层key"#pageIndex";//清除beforeInvocation = true:(先清除外层key"users"里的 内层key"#pageIndex"缓存,再执行method,然后不会放入缓存); beforeInvocation = 默认false:(执行method,再清除缓存);

@CacheConfig 全局配置名称注解到类上面,表示本类的全局配置

@Service // service层@CacheConfig(cacheNames = "users")public class UserServiceImpl implements UserService {//查询@Cacheable(key = "#pageIndex", condition = "#pageIndex < 3")@Overridepublic List<User> listAll(int pageIndex) {}//更新@CachePut(key = "#pageIndex", condition = "#pageIndex < 4")@Overridepublic List<User> listAllPut(int pageIndex) {}//清除@CacheEvict(key = "#pageIndex", condition = "#pageIndex < 3", allEntries = true, beforeInvocation = true)@Overridepublic boolean update(int pageIndex){}}

@Caching 组合配置@Caching注解可以让我们在一个 方法 或者 类上 同时指定多个Spring Cache相关的注解其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict

@Caching(cacheable = @Cacheable("users"), evict = {@CacheEvict("cache2"), @CacheEvict(value = "cache3", allEntries = true)})

Redis持久化 (RDB 与 AOF) 模式

就是将内存数据保存到硬盘,Redis持久化存储 (RDB 与 AOF 两种模式)

RDB持久化:

RDB 是以二进制文件,是在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复优点:使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能缺点:

1> 子进程需要开销和主进程相同的内存完成数据保存,可能会导致内存溢出

2> RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失所以这种方式更适合数据要求不严谨的时候

RDB默认开启,redis.conf 中的具体配置参数; 持久化数据存储在本地的文件dump.rdb快照(snapshots)

#dbfilename:持久化数据存储在本地的文件dbfilename dump.rdb#dir:持久化数据存储在本地的路径,如果是在/redis/redis-3.0.6/myRedis下启动的redis-cli,则数据会存储在当前myRedis目录下dir ./#save时间,以下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储#可以通过 注释#save 900 1 来关闭snapshot功能##对于此值的设置,需要谨慎,评估系统的变更操作密集程度save 900 1save 300 10save 60 10000##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等stop-writes-on-bgsave-error yes##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间rdbcompression yes

AOF持久化:

Append-only file,将“操作 + 数据”以格式化指令的方式追加到操作日志文件的尾部,“日志文件”保存了历史所有的操作过程;当 server 需要数据恢复时,可以直接 replay 此日志文件,即可还原所有的操作过程优点:

1> 可以保持更高的数据完整性,如果设置追加 file 的时间是 1s,redis 发生故障,最多会丢失 1s 的数据;

2> 且如果日志写入不完整支持 redis-check-aof 来进行日志修复;AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令;缺点:AOF 文件比 RDB 文件大,且恢复速度慢AOF 记录同步选项appendfsync everysec 最多会丢失1s的数据,相对可靠

AOF 默认关闭,redis.conf 中的具体配置参数; 持久化数据存储在本地的文件appendonly.aof

##aof功能的开关,默认为“no”,只有在“yes”下,aof重写/文件同步等特性才会生效 appendonly yes##指定aof文件名称appendfilename appendonly.aof#指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec#always:每一条 aof 记录都立即同步到文件,这是最安全的方式,也以为更多的磁盘操作和阻塞延迟,是 IO 开支较大#everysec:每秒同步一次,性能和安全都比较中庸的方式,也是 redis 推荐的方式。如果遇到物理服务器故障,有可能导致最近一秒内 aof 记录丢失(可能为部分丢失)#no:redis并不直接调用文件同步,而是交给操作系统来处理,操作系统可以根据 buffer 填充情况 / 通道空闲时间等择机触发同步;这是一种普通的文件操作方式。性能较好,在物理服务器故障时,数据丢失量会因 OS 配置有关。appendfsync everysec#在aof-rewrite期间,appendfsync是否暂缓文件同步,“no”表示“不暂缓”,“yes”表示“暂缓”,默认为“no” no-appendfsync-on-rewrite no #aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb” auto-aof-rewrite-min-size 64mb #相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比;#每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增长到A*(1 + p)之后, 触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸auto-aof-rewrite-percentage 100

AOF rewrite:一条数据经过多次变更,将会产生多条 AOF 记录,其实只要保存当前的状态,历史的操作记录是可以抛弃的——作用是由 AOF 持久化模式“AOF rewrite”完成

触发 rewrite 的时机可以通过配置文件来声明-appendfsync everysec同步,同时 redis 中可以通过 bgrewriteaof 指令人工干预:

redis-cli -h ip -p port bgrewriteaof

AOF rewrite 过程并不阻塞客户端请求。系统会开启一个子进程来完成

总结:

AOF rewrite 操作 /aof 记录同步 /RDB snapshot(快照) 都消耗磁盘IO,Redis 采取了“schedule”策略:

无论是“人工干预”还是系统触发,RDB snapshot(快照) 和 AOF rewrite(通过配置文件来声明-appendfsync everysec同步) 需要逐个被执行

Redis主从复制

通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave)主数据库(master):主要进行读写操作,当发生写操作的时候自动将数据同步到从数据库从数据库(slave):负责一般是只读,并接收主数据库同步过来的数据

一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库

执行过程:

:当一个从数据库启动时,会向主数据库发送sync命令,:主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来:当快照完成后,redis会将快照文件和所有缓存的命令发送给从数据库:从数据库收到后,会载入快照文件并执行收到的缓存的命令

修改redis.conf从配置文件:

# 设置访问主服务器地址和端口# slaveof <masterip> <masterport> 3.x版本使用指令(slaveof 是mysql的版权)replicaof <masterip> <masterport> # 主Redis配置了密码,则需要配置# masterauth 123456# 可以使用info命令查看主从信息info replicationip:6378> info replicationip:6378> infoip:6380> info replicationip:6381> info replication

从数据库终端slave:

pwd /usr/local/redis/redis-6.2.5mkdir slavecp redis.conf slave/redis80.confcp redis.conf slave/redis81.conf成都 slave# 进程终端1:vi redis80.confport 6380dbfilename dump80.rdbpidfile /var/run/redis_6380.pidreplicaof 主服务器ip 6378# 启动redis80 从服务器../src/redis-server redis80.conf# 进程终端2:vi redis81.confport 6381dbfilename dump81.rdbpidfile /var/run/redis_6381.pidreplicaof 主服务器ip 6378# 启动redis81 从服务器../src/redis-server redis81.conf

主数据库终端master:

../src/redis-cli -p 6378127.0.0.1:6378> info replication# Replicationrole:masterconnected_slaves:2slave0:ip=127.0.0.1,port=6380,state=online,offset=434,lag=1slave1:ip=127.0.0.1,port=6381,state=online,offset=434,lag=0master_replid:0f8f58d3c56b6f77e20cb3c7c71fbefaf5a64be8master_replid2:0000000000000000000000000000000000000000master_repl_offset:434second_repl_offset:-1repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:434127.0.0.1:6378> keys *(empty array)127.0.0.1:6378> set test 123OK127.0.0.1:6378> set test abcOK

查看从服务器终端slave:

../src/redis-cli -p 6380127.0.0.1:6380> info replication# Replicationrole:slavemaster_host:127.0.0.1master_port:6378master_link_status:upmaster_last_io_seconds_ago:8master_sync_in_progress:0slave_repl_offset:784slave_priority:100slave_read_only:1connected_slaves:0master_replid:0f8f58d3c56b6f77e20cb3c7c71fbefaf5a64be8master_replid2:0000000000000000000000000000000000000000master_repl_offset:784second_repl_offset:-1repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:784127.0.0.1:6380> keys *1) "test"127.0.0.1:6380> get test"123"127.0.0.1:6380> set test abc(error) READONLY You can't write against a read only replica.#你不能对只读副本进行写入

Redis哨兵机制

Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器(主从服务器),该系统执行以下三个任务:1.监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常2.提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知3.自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效主服务器Master的其中一个从服务器Slave升级为新的Master

sentinel 是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)定时发送消息来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master

哨兵模式,拷贝一份sentinel.conf到slave目录下,修改sentinel.conf配置文件:

pwd /usr/local/redis/redis-6.2.5/slavecp ../sentinel.conf slave/sentinel-1.confvim sentinel-1.conf#端口port 26379#日志文件配置logfile "/usr/local/redis/redis-6.2.5/slave/sentinel-1.log"#进程号文件配置pidfile /var/run/redis-sentinel-1.pid#工作目录dir /usr/local/redis/redis-6.2.5/slave/#后台启动daemonize yes#主节点 名称(mymaster只要是字符串即可) IP(master的IP) 端口号(master的端口) 选举次数(需要几个哨兵同意 则认为主服务器失效)sentinel monitor mymaster 127.0.0.1 6378 1#主节点密码#sentinel auth-pass mymaster 123456#修改心跳检测5000毫秒,意思就是在多少毫秒内主节点连接无响应,那么认定为主节点已经宕机 //默认30 seconds秒 30000sentinel down-after-milliseconds mymaster 5000#在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步sentinel parallel-syncs mymaster 2#进行故障转移时如果超过了配置的<times>时间就表示故障转移超时失败 //默认3 minutes分钟 180000毫秒sentinel failover-timeout mymaster 15000# 启动哨兵模式../src/redis-sentinel sentinel-1.conf# 关闭哨兵模式,shutdown关闭 服务端、客户端、哨兵端 都可以#../src/redis-cli -h 127.0.0.1 -p 26379 shutdown

主服务器master:

../src/redis-cli -p 6378127.0.0.1:6378> info replication# Replicationrole:masterconnected_slaves:2slave0:ip=127.0.0.1,port=6380,state=online,offset=24623,lag=0slave1:ip=127.0.0.1,port=6381,state=online,offset=24623,lag=1master_replid:a1b761a06f89998271bd78c756564ac9046976e5master_replid2:0000000000000000000000000000000000000000master_repl_offset:24623second_repl_offset:-1repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:24623# 模拟6378 宕机(挂掉); save保存快照; 6378服务端和6378客户端都会关了127.0.0.1:6378> shutdown [NOSAVE|SAVE]

从服务器slave(redis80.conf会给修改,经过哨兵选举成为了主服务master):

#终端1:vi redis80.confport 6380dbfilename dump80.rdbpidfile /var/run/redis_6380.pid##replicaof 127.0.0.1 6378#终端2:vi redis81.confport 6381dbfilename dump81.rdbpidfile /var/run/redis_6381.pidreplicaof 127.0.0.1 6378 变成 6380#6378主服务终端关闭了还没有启动:vi redis78.conf# replicaof <masterip> <masterport>#slave 6380变成master:[root@localhost slave]# ../src/redis-cli -p 6380127.0.0.1:6380> info replication# Replicationrole:masterconnected_slaves:1slave0:ip=127.0.0.1,port=6381,state=online,offset=96937,lag=0master_replid:e765df828618ebb7dfe7f9a929c399d20653c0aamaster_replid2:a1b761a06f89998271bd78c756564ac9046976e5master_repl_offset:96937second_repl_offset:76513repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:96937127.0.0.1:6380> keys *1) "test"127.0.0.1:6380> get test"ggggg"127.0.0.1:6380> set test HHHHHOK127.0.0.1:6380> exit

重启6378主服务终端,变成了从服务slave:

# 6378服务端启动重启后vi redis78.conf# Generated by CONFIG REWRITE 由配置重写生成replicaof 127.0.0.1 6380// 最后面会添加,主服务器 master 6380#slave 6380变成master:[root@localhost slave]# ../src/redis-cli -p 6380127.0.0.1:6380> info replication# Replicationrole:masterconnected_slaves:2slave0:ip=127.0.0.1,port=6381,state=online,offset=299218,lag=1slave1:ip=127.0.0.1,port=6378,state=online,offset=299218,lag=0master_replid:e765df828618ebb7dfe7f9a929c399d20653c0aamaster_replid2:a1b761a06f89998271bd78c756564ac9046976e5master_repl_offset:299218second_repl_offset:76513repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:299218127.0.0.1:6380>

Spring Boot 集成主从复制 sentinel机制

#配置redis连接#选择数据库,默认值为0spring.redis.database=0#密码spring.redis.password=#请求超时时间spring.redis.timeout=0#配置jedis连接池spring.redis.jedis.pool.max-active=8spring.redis.jedis.pool.max-wait=-1spring.redis.jedis.pool.max-idle=8spring.redis.jedis.pool.min-idle=0#设置哨兵监听主服务器spring.redis.sentinel.master=mymaster#设置哨兵群,多个哨兵使用,号分割spring.redis.sentinel.nodes=访问运行哨兵服务器ip:26379

配置application.yml:

spring:redis:# host: redis服务器ip# port: 6379database: 1sentinel:master: mymasternodes: 访问运行哨兵服务器ip:26379#主节点 master主服务器 主机IP 要外放出去给访问#vim sentinel-1.conf#sentinel monitor mymaster redis服务器ip 6378 1

遇到的error version

// error,SpringBoot2.4.2无法启动!可能是版本不能兼容的问题JedisSentinelPool;Correct the classpath of your application so that it contains a single, compatible version of redis.clients.jedis.JedisSentinelPoolcompatible version of// 兼容版本Spring Boot:Default:https://start.spring.io //2.3.8可以解决Custom:/ //SpringBoot2.3.4

Redis事务

redis事务可以一次执行多个命令,事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行(以数据结构 队列 的形式压入)事务在执行的过程中,不会被其他客户端发送来的命令请求所打断一个事务从开始到执行会经历以下三个阶段: 开始事务命令入队执行事务

它先以 MULTI 开始一个事务,然后将多个命令入队到事务中,最后由 EXEC 命令触发事务,一并执行事务中的所有命令:

# 终端启动在主服务器master:127.0.0.1:6380> multiOK127.0.0.1:6380> set u1 123QUEUED127.0.0.1:6380> get u1QUEUED127.0.0.1:6380> exec1) OK2) "123"127.0.0.1:6380> multiOK127.0.0.1:6380> set u2 11111 2222QUEUED127.0.0.1:6380> get u1QUEUED127.0.0.1:6380> set u5 555QUEUED127.0.0.1:6380> exec1) (error) ERR syntax error2) "123"3) OK//存进去了 redis 没有回滚

redis事务 不支持回滚 为了提升效率,加了回滚需要处理锁的问题,所以不加,锁是影响效率的只做了批量处理,可以达到检查指令是否是错误

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。