一:环境准备

1. 引入依赖


  1. <!--引入jedis连接依赖-->
  2. <dependency>
  3. <groupId>redis.clients</groupId>
  4. <artifactId>jedis</artifactId>
  5. <version>2.9.0</version>
  6. </dependency>

2.创建jedis对象

  1. public static void main(String[] args) {
  2. //1.创建jedis对象
  3. Jedis jedis = new Jedis("192.168.40.4", 6379);//1.redis服务必须关闭防火墙 2.redis服务必须开启远程连接
  4. jedis.select(0);//选择操作的库默认0号库
  5. //2.执行相关操作
  6. //....
  7. //3.释放资源
  8. jedis.close();
  9. }

image.png

1.1:操作key相关API

  1. private Jedis jedis;
  2. @Before
  3. public void before(){
  4. this.jedis = new Jedis("192.168.202.205", 7000);
  5. }
  6. @After
  7. public void after(){
  8. jedis.close();
  9. }
  10. //测试key相关
  11. @Test
  12. public void testKeys(){
  13. //删除一个key
  14. jedis.del("name");
  15. //删除多个key
  16. jedis.del("name","age");
  17. //判断一个key是否存在exits
  18. Boolean name = jedis.exists("name");
  19. System.out.println(name);
  20. //设置一个key超时时间 expire pexpire
  21. Long age = jedis.expire("age", 100);
  22. System.out.println(age);
  23. //获取一个key超时时间 ttl
  24. Long age1 = jedis.ttl("newage");
  25. System.out.println(age1);
  26. //随机获取一个key
  27. String s = jedis.randomKey();
  28. //修改key名称
  29. jedis.rename("age","newage");
  30. //查看可以对应值的类型
  31. String name1 = jedis.type("name");
  32. System.out.println(name1);
  33. String maps = jedis.type("maps");
  34. System.out.println(maps);
  35. }

image.png

1.2:操作String相关API

  1. //测试String相关
  2. @Test
  3. public void testString(){
  4. //set
  5. jedis.set("name","小陈");
  6. //get
  7. String s = jedis.get("name");
  8. System.out.println(s);
  9. //mset
  10. jedis.mset("content","好人","address","海淀区");
  11. //mget
  12. List<String> mget = jedis.mget("name", "content", "address");
  13. mget.forEach(v-> System.out.println("v = " + v));
  14. //getset
  15. String set = jedis.getSet("name", "小明");
  16. System.out.println(set);
  17. //............
  18. }

image.png

1.3:操作List相关API

  1. //测试List相关
  2. @Test
  3. public void testList(){
  4. //lpush
  5. jedis.lpush("names1","张三","王五","赵柳","win7");
  6. //rpush
  7. jedis.rpush("names1","xiaomingming");
  8. //lrange
  9. List<String> names1 = jedis.lrange("names1", 0, -1);
  10. names1.forEach(name-> System.out.println("name = " + name));
  11. //lpop rpop
  12. String names11 = jedis.lpop("names1");
  13. System.out.println(names11);
  14. //llen
  15. jedis.linsert("lists", BinaryClient.LIST_POSITION.BEFORE,"xiaohei","xiaobai");
  16. //........
  17. }

image.png

1.4:操作Set的相关API

  1. //测试SET相关
  2. @Test
  3. public void testSet(){
  4. //sadd
  5. jedis.sadd("names","zhangsan","lisi");
  6. //smembers
  7. jedis.smembers("names");
  8. //sismember
  9. jedis.sismember("names","xiaochen");
  10. //...
  11. }

image.png

1.5: 操作ZSet相关API

  1. //测试ZSET相关
  2. @Test
  3. public void testZset(){
  4. //zadd
  5. jedis.zadd("names",10,"张三");
  6. //zrange
  7. jedis.zrange("names",0,-1);
  8. //zcard
  9. jedis.zcard("names");
  10. //zrangeByScore
  11. jedis.zrangeByScore("names","0","100",0,5);
  12. //..
  13. }

image.png

1.6: 操作Hash相关API

  1. //测试HASH相关
  2. @Test
  3. public void testHash(){
  4. //hset
  5. jedis.hset("maps","name","zhangsan");
  6. //hget
  7. jedis.hget("maps","name");
  8. //hgetall
  9. jedis.hgetAll("mps");
  10. //hkeys
  11. jedis.hkeys("maps");
  12. //hvals
  13. jedis.hvals("maps");
  14. //....
  15. }

image.png

二:SpringBoot整合Redis

Spring Boot Data(数据) Redis 中提供了RedisTemplate和StringRedisTemplate,其中StringRedisTemplate是RedisTemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同,RedisTemplate中的两个泛型都是Object,意味着存储的key和value都可以是一个对象,而StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。
**
注意: 使用RedisTemplate默认是将对象序列化到Redis中,所以放入的对象必须实现对象序列化接口

2:环境准备

2.1.引入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>

2.2.配置application.propertie

  1. spring.redis.host=localhost
  2. spring.redis.port=6379
  3. spring.redis.database=0

3: 使用StringRedisTemplate和RedisTemplate

  1. @Autowired
  2. private StringRedisTemplate stringRedisTemplate; //对字符串支持比较友好,不能存储对象
  3. @Autowired
  4. private RedisTemplate redisTemplate; //存储对象
  5. @Test
  6. public void testRedisTemplate(){
  7. System.out.println(redisTemplate);
  8. //设置redistemplate值使用对象序列化策略
  9. redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());//指定值使用对象序列化
  10. //redisTemplate.opsForValue().set("user",new User("21","小黑",23,new Date()));
  11. User user = (User) redisTemplate.opsForValue().get("user");
  12. System.out.println(user);
  13. // Set keys = redisTemplate.keys("*");
  14. // keys.forEach(key -> System.out.println(key));
  15. /*Object name = redisTemplate.opsForValue().get("name");
  16. System.out.println(name);*/
  17. //Object xiaohei = redisTemplate.opsForValue().get("xiaohei");
  18. //System.out.println(xiaohei);
  19. /*redisTemplate.opsForValue().set("name","xxxx");
  20. Object name = redisTemplate.opsForValue().get("name");
  21. System.out.println(name);*/
  22. /*redisTemplate.opsForList().leftPushAll("lists","xxxx","1111");
  23. List lists = redisTemplate.opsForList().range("lists", 0, -1);
  24. lists.forEach(list-> System.out.println(list));*/
  25. }
  26. //key的绑定操作 如果日后对某一个key的操作及其频繁,可以将这个key绑定到对应redistemplate中,日后基于绑定操作都是操作这个key
  27. //boundValueOps 用来对String值绑定key
  28. //boundListOps 用来对List值绑定key
  29. //boundSetOps 用来对Set值绑定key
  30. //boundZsetOps 用来对Zset值绑定key
  31. //boundHashOps 用来对Hash值绑定key
  32. @Test
  33. public void testBoundKey(){
  34. BoundValueOperations<String, String> nameValueOperations = stringRedisTemplate.boundValueOps("name");
  35. nameValueOperations.set("1");
  36. //yuew
  37. nameValueOperations.set("2");
  38. String s = nameValueOperations.get();
  39. System.out.println(s);
  40. }
  41. //hash相关操作 opsForHash
  42. @Test
  43. public void testHash(){
  44. stringRedisTemplate.opsForHash().put("maps","name","小黑");
  45. Object o = stringRedisTemplate.opsForHash().get("maps", "name");
  46. System.out.println(o);
  47. }
  48. //zset相关操作 opsForZSet
  49. @Test
  50. public void testZSet(){
  51. stringRedisTemplate.opsForZSet().add("zsets","小黑",10);
  52. Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);
  53. zsets.forEach(value-> System.out.println(value));
  54. }
  55. //set相关操作 opsForSet
  56. @Test
  57. public void testSet(){
  58. stringRedisTemplate.opsForSet().add("sets","xiaosan","xiaosi","xiaowu");
  59. Set<String> sets = stringRedisTemplate.opsForSet().members("sets");
  60. sets.forEach(value-> System.out.println(value));
  61. }
  62. //list相关的操作opsForList
  63. @Test
  64. public void testList(){
  65. // stringRedisTemplate.opsForList().leftPushAll("lists","张三","李四","王五");
  66. List<String> lists = stringRedisTemplate.opsForList().range("lists", 0, -1);
  67. lists.forEach(key -> System.out.println(key));
  68. }
  69. //String相关的操作 opsForValue
  70. @Test
  71. public void testString(){
  72. //stringRedisTemplate.opsForValue().set("166","好同学");
  73. String s = stringRedisTemplate.opsForValue().get("166");
  74. System.out.println(s);
  75. Long size = stringRedisTemplate.opsForValue().size("166");
  76. System.out.println(size);
  77. }
  78. //key相关的操作
  79. @Test
  80. public void test(){
  81. Set<String> keys = stringRedisTemplate.keys("*");//查看所有key
  82. Boolean name = stringRedisTemplate.hasKey("name");//判断某个key是否存在
  83. stringRedisTemplate.delete("age");//根据指定key删除
  84. stringRedisTemplate.rename("","");//修改key的名称
  85. stringRedisTemplate.expire("key",10, TimeUnit.HOURS);
  86. //设置key超时时间 参数1:设置key名 参数2:时间 参数3:时间的单位
  87. stringRedisTemplate.move("",1);//移动key
  88. }

4. Redis 主从复制

4.1 主从复制

主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据
无法解决: 1.master节点出现故障的自动故障转移

4.2 主从复制架构图

image.png

4.3 搭建主从复制

  1. # 1.准备3台机器并修改配置
  2. - master
  3. port 6379
  4. bind 0.0.0.0
  5. - slave1
  6. port 6380
  7. bind 0.0.0.0
  8. slaveof masterip masterport
  9. - slave2
  10. port 6381
  11. bind 0.0.0.0
  12. slaveof masterip masterport

image.png

  1. # 2.启动3台机器进行测试
  2. - cd /usr/redis/bin
  3. - ./redis-server /root/master/redis.conf
  4. - ./redis-server /root/slave1/redis.conf
  5. - ./redis-server /root/slave2/redis.conf

5:Redis哨兵机制

5.1 哨兵Sentinel机制

Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。简单的说哨兵就是带有自动故障转移功能的主从架构
无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限

5.2 哨兵架构原理

image.png

5.3 搭建哨兵架构

  1. # 1.在主节点上创建哨兵配置
  2. - Master对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错;
  3. # 2.配置哨兵,在sentinel.conf文件中填入内容:
  4. - sentinel monitor 被监控数据库名字(自己起名字) ip port 1
  5. # 3.启动哨兵模式进行测试
  6. - redis-sentinel /root/sentinel/sentinel.conf
  7. 说明:这个后面的数字2,是指当有两个及以上的sentinel服务检测到master宕机,才会去执行主从切换的功能。

5.4 通过springboot操作哨兵

  1. # redis sentinel 配置
  2. # master书写是使用哨兵监听的那个名称
  3. spring.redis.sentinel.master=mymaster
  4. # 连接的不再是一个具体redis主机,书写的是多个哨兵节点
  5. spring.redis.sentinel.nodes=192.168.202.206:26379
  • 注意:如果连接过程中出现如下错误:RedisConnectionException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command ‘CONFIG SET protected-mode no’ from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2)
  • 解决方案:在哨兵的配置文件中加入bind 0.0.0.0 开启远程连接权限

image.png
image.png

三. Redis集群

3.1 集群

Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,支持slave-master选举和容错,支持在线分片(sharding shard )等特性。reshard。

3.2 集群架构图

image.png

3.3 集群细节

  • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
    - 节点的fail是通过集群中超过半数的节点检测失效时才生效.
    - 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
    - redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

image.png

3.4 集群搭建

判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数,搭建集群至少需要三个主节点,三个从节点,至少需要6个节点

  1. # 1.准备环境安装ruby以及redis集群依赖
  2. - yum install -y ruby rubygems
  3. - gem install redis-xxx.gem

image.png

2.在一台机器创建7个目录

image.png

3.每个目录复制一份配置文件

  1. # 3.每个目录复制一份配置文件
  2. [root@localhost ~]# cp redis-4.0.10/redis.conf 7000/
  3. [root@localhost ~]# cp redis-4.0.10/redis.conf 7001/
  4. [root@localhost ~]# cp redis-4.0.10/redis.conf 7002/
  5. [root@localhost ~]# cp redis-4.0.10/redis.conf 7003/
  6. [root@localhost ~]# cp redis-4.0.10/redis.conf 7004/
  7. [root@localhost ~]# cp redis-4.0.10/redis.conf 7005/
  8. [root@localhost ~]# cp redis-4.0.10/redis.conf 7006/

image.png

  1. # 4.修改不同目录配置文件
  2. - port 6379 ..... //修改端口
  3. - bind 0.0.0.0 //开启远程连接
  4. - cluster-enabled yes //开启集群模式
  5. - cluster-config-file nodes-port.conf //集群节点配置文件
  6. - cluster-node-timeout 5000 //集群节点超时时间
  7. - appendonly yes //开启AOF持久化
  8. # 5.指定不同目录配置文件启动七个节点
  9. - [root@localhost bin]# ./redis-server /root/7000/redis.conf
  10. - [root@localhost bin]# ./redis-server /root/7001/redis.conf
  11. - [root@localhost bin]# ./redis-server /root/7002/redis.conf
  12. - [root@localhost bin]# ./redis-server /root/7003/redis.conf
  13. - [root@localhost bin]# ./redis-server /root/7004/redis.conf
  14. - [root@localhost bin]# ./redis-server /root/7005/redis.conf
  15. - [root@localhost bin]# ./redis-server /root/7006/redis.conf

image.png

  1. # 6.查看进程
  2. - [root@localhost bin]# ps aux|grep redis

1.创建集群

  1. # 1.复制集群操作脚本到bin目录中
  2. - [root@localhost bin]# cp /root/redis-4.0.10/src/redis-trib.rb .
  3. # 2.创建集群
  4. - ./redis-trib.rb create --replicas 1 192.168.202.205:7000 192.168.202.205:7001 192.168.202.205:7002 192.168.202.205:7003 192.168.202.205:7004 192.168.202.205:7005

image.png

3.集群创建成功出现如下提示

image.png

2.查看集群状态

  1. # 1.查看集群状态 check [原始集群中任意节点] [无]
  2. - ./redis-trib.rb check 192.168.202.205:7000
  3. # 2.集群节点状态说明
  4. - 主节点
  5. 主节点存在hash slots,且主节点的hash slots 没有交叉
  6. 主节点不能删除
  7. 一个主节点可以有多个从节点
  8. 主节点宕机时多个副本之间自动选举主节点
  9. - 从节点
  10. 从节点没有hash slots
  11. 从节点可以删除
  12. 从节点不负责数据的写,只负责数据的同步

3.添加主节点

  1. # 1.添加主节点 add-node [新加入节点] [原始集群中任意节点]
  2. - ./redis-trib.rb add-node 192.168.1.158:7006 192.168.1.158:7005
  3. - 注意:
  4. 1.该节点必须以集群模式启动
  5. 2.默认情况下该节点就是以master节点形式添加

4.添加从节点

  1. # 1.添加从节点 add-node --slave [新加入节点] [集群中任意节点]
  2. - ./redis-trib.rb add-node --slave 192.168.1.158:7006 192.168.1.158:7000
  3. - 注意:
  4. 当添加副本节点时没有指定主节点,redis会随机给副本节点较少的主节点添加当前副本节点
  5. # 2.为确定的master节点添加主节点 add-node --slave --master-id master节点id [新加入节点] [集群任意节点]
  6. - ./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000

5.删除副本节点

  1. # 1.删除节点 del-node [集群中任意节点] [删除节点id]
  2. - ./redis-trib.rb del-node 127.0.0.1:7002 0ca3f102ecf0c888fc7a7ce43a13e9be9f6d3dd1
  3. - 注意:
  4. 1.被删除的节点必须是从节点或没有被分配hash slots的节点

6.集群在线分片

  1. # 1.在线分片 reshard [集群中任意节点] [无]
  2. - ./redis-trib.rb reshard 192.168.1.158:7000

四.Redis实现分布式Session管理

4.1 管理机制

redis的session管理是利用spring提供的session管理解决方案,将一个应用session交给Redis存储,整个应用中所有session的请求都会去redis中获取对应的session数据。

image.png

4.2 开发Session管理

1. 引入依赖

  1. <dependency>
  2. <groupId>org.springframework.session</groupId>
  3. <artifactId>spring-session-data-redis</artifactId>
  4. </dependency>

2. 开发Session管理配置类

  1. @Configuration
  2. @EnableRedisHttpSession
  3. public class RedisSessionManager {
  4. }

3.打包测试即可