导图社区 Redis_backup_2220a3
安装 数据类型 发布、订阅 代码操作(Jedis操作 整合SpringBoot) 集群 哨兵监控
编辑于2022-08-23 09:10:54 北京市Redis
参考资料:http://itsoku.com/course/15/248
Redis下载安装
解压 tar -avxf redis-xx.xx.x.tar.gz 安装gcc yum install gcc 进入redis目录 cd redis-xx.xx 编译 make 安装 make install 查看安装目录 /usr/local/bin
Redis常用命令
前台启动:redis-server 后台启动: 1.复制redis.conf文件到/etc目录 cp /opt/redis-xx/redis.conf /etc 2.使用vi命令修改redis.conf文件中的daemonize yes 3.启动 redis-server /etc/redis.conf 4.查看redis进程 ps -ef |grep redis 关闭redis 1.kill -9 pid 2.redis-cli shutdown 进入redis客户端命令窗口 redis-cli
Redis数据类型
字符串String set name jordan get name append name "kobe" strlen name setnx name james 如果不存在返回1表示设置成功,如果已经存在返回0 设置失败 incr salary 如果salary不存在自动创建,值为1.否则自增1 desr salary 如果salary不存在自动创建,值为-1.否则自减1 insrby salary 1000 / decrby salary 800 递增、递减指定数字 mset name jordan num 23 同是设置多个key-value mget name num 同时获取多个key的值 msetnx name jordan num 23 当name和num都不存在的时候同时设置,如果其中一个存在,则全部设置失败 getrange name 0 3 截取name属性值的指定下标字符串 setrange name 1 kobe 下标1的位置进行覆盖 setex name 100 jordan 设置name的值为jordan,有效期为100秒 ttl name 获取name还有多少秒失效 getset name kobe 设置name为kobe,返回name的旧值 如果name为设置过,返回null 列表List lpush/rpush cource java c c++ php js 插入5个元素 lrange course 1 2 从左边取出索引位于1,2范围内的元素(0 -1 取出全部元素) lpop course 从左边弹出1个元素 rpop course 2从右边弹出2个元素 rpoplpush k1 k2 从k1的右边弹出一个元素放到k2的左边 lindex course 2 返回索引位置2的元素 如果没有返回nil 如果是-1返回倒数第一个 llen course 获取course对应的值的长度 linsert name before kobe jordan kobe前面添加jordan lrem k1 2 v2 k1集合中从左边删除2个v2 lset name 1 james 将name集合元素索引为1的替换为james,索引超出范围或者集合不存在则报错 集合Set sadd k1 v1 v2 v2 v3 向集合添加元素(无序,不重复) semvers k1 取出所有元素 sismemver k1 v1 判断集合中是否包含v1 包含返回1,否则返回0 scard k1 返回集合元素的个数 srem k1 v2 删除集合k1中的v2 spop k1 随机弹出k2集合中的一个元素 后面指定数字表示弹出指定数字个元素 sramdmember k1 3 随机获取k1集合3个元素,元素并不会被删除 smove course1 course2 js 集合sourse1中的js移到course2 sinter couse1 course2 course3 取三个集合的交集 sinterstore course course1 course2 将course1 course2交集放到course中 sunion course1 course2 course3取多个集合的并集,自动去重 sinterstore course course1 course2 将course1 course2并集放到course中 sdiff sdiffstore 差集 哈希表Hash hset user name jordan num 23 hget user name hget user 获取所有的user域值 hexists user name 判断是否存在 hkeys user 获取user所有的filed hvals user 获取user所有的value hlen user 返回filed的数量 hincrby user num 11 user中的num增加11 hsetnx user name jordan 不存在设置成功,否则设置失败 有序集合Zset zadd course 100 java 80 c 70 c++ 50 js zrange course 0 -1按照score升序返回course所有元素 zrange course 0 -1 withscores 同上 xtrbtsnhr course 0 -1 按照score降序获取所有元素 zrevrange course 0 2 按照score降序获取前3名 zrangebyscore course 70 90 升序位于【70 90】区间元素 zrevrangebyscore course 100 90 降序score位于【】 zincrby course 5 java 为java的score加5 zrem course c c++ 删除集合中的两个元素 zremrangebyrank course 0 1 删除索引范围[0,1]的数据 zcount course 80 100 统计score位于[80 100]区间元素的个数 zrank course c 获取元素c的排名返回1表示排名第2 zrevrank course java score降序得到java的排名 zscore course java 获取集合中java的score
Redis新的3中类型
Redis应用问题解决
缓存穿透
问题描述: 当系统中引入redis缓存后,一个请求进来后,会先从redis缓存中查询,缓存有就直接返回,缓存中没有就去db中查询,db中如果有就会将其丢到缓存中,但是有些key对应更多数据在db中并不存在,每次针对此次key的请求从缓存中取不到,请求都会压到db,从而可能压垮db。 比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用大量此类攻击可能压垮数据库。 解决方案: 
缓存击穿
问题描述:  解决方案: 
雪崩
问题描述: key对应的数据存在,但是极短时间内有大量的key集中过期,此时若有大量的并发请求过来,发现缓存没有数据,大量的请求就会落到db上去加载数据,会将db击垮,导致服务奔溃。 缓存雪崩与缓存击穿的区别在于:前者是大量的key集中过期,而后者是某个热点key过期 解决方案: 
分布式锁
问题描述: 随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。 分布式锁主流的实现方案  使用Redis实现分布式锁    终极方案:Lua脚本来释放锁 @RestController public class LockTest { @Autowired private RedisTemplate<String, String> redisTemplate; @RequestMapping(value = "/lock", produces = MediaType.TEXT_PLAIN_VALUE) public String lock() { String lockKey = "k1"; String uuid = UUID.randomUUID().toString(); //1.获取锁,有效期10秒 if (this.redisTemplate.opsForValue().setIfAbsent(lockKey, uuid, 10, TimeUnit.SECONDS)) { //2.执行业务 // todo 业务 //3.使用Lua脚本释放锁(可防止误删) String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"; DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setScriptText(script); redisScript.setResultType(Long.class); Long result = redisTemplate.execute(redisScript, Arrays.asList(lockKey), uuid); System.out.println(result); return "获取锁成功!"; } else { return "加锁失败!"; } } }
Redis主从复制
1. 环境准备(需要3台机器的)  2. master-6379主机 2.1 创建工作目录:master-slave mkdir /opt/master-slave 2.2 将redis.conf复制到master-slave目录 cp /opt/redis-6.2.1/redis.conf /opt/master-slave/ 2.3 创建master配置文件redis-6379.conf  3. slave-6380从机(其中bind 绑定的ip应该和从机ip一致,这里是用同一台主机模拟三台主机) /opt/master-slave目录创建redis-6380.conf  4. slave-6381从机(其中bind 绑定的ip应该和从机ip一致,这里是用同一台主机模拟三台主机)  5. 启动master/两台slave  6. 查看主机的信息  同样的方式查看两台从机的信息  7. 哨兵模式 能够自动监控master是否发生故障,如果故障了会根据投票数从slave中挑选一个作为master,其他的slave会自动转向同步新的master,实现故障自动转义。 7.1 环境(一主二从,三哨兵)  7.2 分别在三台服务器上创建sentinel1的配置文件 sentinel-26379.conf sentinel-26380.conf sentinel-26381.conf  7.3 启动3个sentinel   7.4 验证  7.5 当旧的master恢复之后,会自动挂在新的master下面  =================================== 如果从机的配置文件中没有配置连接主机的信息(红色框的内容去除) 可以通过控制台命令来指定salve从机的master 该方式在slave重启之后,主从配置会失效  从机执行如下命令:  当master挂掉之后,可以从slave中选择一个作为主机 
Redis集群
1. 创建master1的配置文件redis-6379.conf  2. 同样的方式创建master2 master3 3. 创建slave1 redis-6389.conf  4. 同样的方式创建slave2 slave3 5.启动三个master 三个slave,并查看启动情况   6. 确保node-xxx.conf文件已正常生成  7. 将六个节点合并为一个集群  8. 连接集群节点,查看集群信息   在集群中录入值   slot相关命令:  
代码操作Redis
Jedis操作Redis
public class JedisDemo { Jedis jedis; @Before public void before() { this.jedis = new Jedis("192.168.200.129", 6379); } @After public void after() { //关闭jedis this.jedis.close(); } /** * 测试redis是否连通 */ @Test public void test1() { String ping = jedis.ping(); System.out.println(ping); } /** * string类型测试 */ @Test public void stringTest() { jedis.set("site", "http://www.itsoku.com"); System.out.println(jedis.get("site")); System.out.println(jedis.ttl("site")); } /** * list类型测试 */ @Test public void listTest() { jedis.rpush("courses", "java", "spring", "springmvc", "springboot"); List<String> courses = jedis.lrange("courses", 0, -1); for (String course : courses) { System.out.println(course); } } /** * set类型测试 */ @Test public void setTest() { jedis.sadd("users", "tom", "jack", "ready"); Set<String> users = jedis.smembers("users"); for (String user : users) { System.out.println(user); } } /** * hash类型测试 */ @Test public void hashTest() { jedis.hset("user:1001", "id", "1001"); jedis.hset("user:1001", "name", "张三"); jedis.hset("user:1001", "age", "30"); Map<String, String> userMap = jedis.hgetAll("user:1001"); System.out.println(userMap); } /** * zset类型测试 */ @Test public void zsetTest() { jedis.zadd("languages", 100d, "java"); jedis.zadd("languages", 95d, "c"); jedis.zadd("languages", 70d, "php"); List<String> languages = jedis.zrange("languages", 0, -1); System.out.println(languages); } /** * 订阅消息 * * @throws InterruptedException */ @Test public void subscribeTest() throws InterruptedException { //subscribe(消息监听器,频道列表) jedis.subscribe(new JedisPubSub() { @Override public void onMessage(String channel, String message) { System.out.println(channel + ":" + message); } }, "sitemsg"); TimeUnit.HOURS.sleep(1); } /** * 发布消息 * * @throws InterruptedException */ @Test public void publishTest() { jedis.publish("sitemsg", "hello redis"); } }
Jedis操作Redis: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.2.1</version> </dependency>
SpringBoot2整合Redis
@RestController @RequestMapping("/redis") public class RedisController { @Autowired private RedisTemplate<String, String> redisTemplate; @RequestMapping("/stringTest") public String stringTest() { this.redisTemplate.delete("name"); this.redisTemplate.opsForValue().set("name", "路人");//opsForValue提供了操作String类型的所有方法 String name = this.redisTemplate.opsForValue().get("name"); return name; } @RequestMapping("/listTest") public List<String> listTest() { this.redisTemplate.delete("names"); this.redisTemplate.opsForList().rightPushAll("names", "刘德华", "张学友", "郭富城", "黎明"); //opsForList提供了操作List类型的所有方法 List<String> courses = this.redisTemplate.opsForList().range("names", 0, -1); return courses; } @RequestMapping("setTest") public Set<String> setTest() { this.redisTemplate.delete("courses"); this.redisTemplate.opsForSet().add("courses", "java", "spring", "springboot");//opsForSet提供了操作Set类型的所有方法 Set<String> courses = this.redisTemplate.opsForSet().members("courses"); return courses; } @RequestMapping("hashTest") public Map<Object, Object> hashTest() { this.redisTemplate.delete("userMap"); Map<String, String> map = new HashMap<>(); map.put("name", "路人"); map.put("age", "30"); this.redisTemplate.opsForHash().putAll("userMap", map);//opsForHash提供了操作Hash类型的所有方法 Map<Object, Object> userMap = this.redisTemplate.opsForHash().entries("userMap"); return userMap; } @RequestMapping("zsetTest") public Set<String> zsetTest() { this.redisTemplate.delete("languages"); this.redisTemplate.opsForZSet().add("languages", "java", 100d);//opsForZSet提供了操作zset类型的所有方法 this.redisTemplate.opsForZSet().add("languages", "c", 95d); this.redisTemplate.opsForZSet().add("languages", "php", 70); Set<String> languages = this.redisTemplate.opsForZSet().range("languages", 0, -1); return languages; } }
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
application.properties配置文件: spring.redis.host=192.168.200.129 spring.redis.port=6379 #spring.redis.password=root spring.redis.timeout=60000 spring.redis.database=0
SpringBoot整合Sentinel模式
 /** * 查看redis机器信息 * * @return */ @RequestMapping(value = "/info", produces = MediaType.TEXT_PLAIN_VALUE) public String info() { Object obj = this.redisTemplate.execute(new RedisCallback<Object>() { @Override public Object doInRedis(RedisConnection connection) throws DataAccessException { return connection.execute("info"); } }); return obj.toString(); }
SpringBoot整合redis集群
1. 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2. application.properties中配置redis cluster信息 spring.redis.cluster.nodes=192.168.200.129:6379,192.168.200.129:6380,192.168.200.129:6381,192.168.200.129:6389,192.168.200.129:6390,192.168.200.129:6391 spring.redis.timeout=60000
Redis发布和订阅
 
Redis持久化
AOF(Append Only File)
1. AOF默认不开启,redis.conf文件中需要对AOP进行配置(AOF和RDB同时开启,系统默认取AOF的数据)  2. AOF启动、修复、恢复  3. AOF同步频率设置 
以日志追加的形式记录每个写操作
RDB(Redis DataBase)
1. 指定备份文件的名称  2. 指定备份文件存放的目录  3. 触发RDB备份 方式1:自动备份  方式2:手动执行命令  方式3:flushall命令 执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义。 4. RDB的备份和恢复  ======================== Redis.conf其他操作  
指定时间间隔,以快照的方法泾数据集写入磁盘