java架構之路-(Redis專題)SpringBoot連接Redis超簡單

  • 2019 年 10 月 25 日
  • 筆記

  上次我們搭建了Redis的主從架構,哨兵架構以及我們的集群架構,但是我們一直還未投入到實戰中去,這次我們用jedis和springboot兩種方式來操作一下我們的redis

主從架構

  如何配置我上次已經講過了,https://www.cnblogs.com/cxiaocai/p/11711377.html。我們這次主要看如何用java來操作redis,先來複習一下上次的配置,準備三台伺服器,安裝redis,保證互通,兩台改為slave,配置replicaof IP 埠,主從複製是通過rdb文件來複制的。大概就這麼多,配置不再多說了,我們直接上程式碼。

  jedis

  創建一個Maven項目,引入我們的jedis依賴包

<!-- 加入jedis依賴 -->  <dependency>      <groupId>redis.clients</groupId>      <artifactId>jedis</artifactId>      <version>2.9.0</version>  </dependency>

這裡我就不封裝連接工具類啦,我們直接看下測試程式碼吧

public static void main(String[] args) {      JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();      jedisPoolConfig.setMaxTotal(20);      jedisPoolConfig.setMaxIdle(10);      jedisPoolConfig.setMinIdle(5);      // timeout,這裡既是連接超時又是讀寫超時,從Jedis 2.8開始有區分connectionTimeout和soTimeout的構造函數      JedisPool jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379, 3000, null);        Jedis jedis = null;      try {          //從redis連接池裡拿出一個連接執行命令          jedis = jedisPool.getResource();          System.out.println(jedis.set("xiaocai", "666"));          System.out.println(jedis.get("xiaocai"));      } catch (Exception e) {          e.printStackTrace();      } finally {          //注意這裡不是關閉連接,在JedisPool模式下,Jedis會被歸還給資源池。          if (jedis != null)              jedis.close();      }  }

主從的連接很簡單的,設置連接參數,直接連接就可以操作我們的redis了,主從的連接,就是基本的鏈接。

  springboot

  我們再來看一下springboot怎麼來連接吧,建立一個springboot項目,什麼也不用設置,建立一個最簡單的就可以的,首先還是加入我們的Maven驅動包

<!-- 加入redis連接池-->  <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-data-redis</artifactId>  </dependency>

加入我們的redis的配置資訊,放置在application.yml文件下即可。

spring:    redis:      database: 0 # Redis資料庫索引(默認為0)      host: 127.0.0.1 # Redis伺服器地址      port: 6379 # Redis伺服器連接埠      password: # Redis伺服器連接密碼(默認為空)      timeout: 5000 # 連接超時時間(毫秒)      jedis:        pool:          max-active: 8 # 連接池最大連接數(使用負值表示沒有限制)          max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制)          max-idle: 8 # 連接池中的最大空閑連接          min-idle: 0 # 連接池中的最小空閑連接

這個也就不存在什麼工具類了,內部都已經封裝好了,我們直接來上測試類吧

package com.redisclient.master_slave;    import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.web.bind.annotation.GetMapping;  import org.springframework.web.bind.annotation.RestController;  import org.springframework.data.redis.core.StringRedisTemplate;    @RestController  public class RedisMasterSlave {        @Autowired      private StringRedisTemplate stringRedisTemplate;        @GetMapping(value = "/")      public String getIndex(){          stringRedisTemplate.opsForValue().set("xiaocai", "888");          System.out.println(stringRedisTemplate.opsForValue().get("xiaocai"));          return "小菜技術";      }  }

  相比我們上面的jedis還要簡單,直接自動裝配一下我們的StringRedisTemplate即可,剩下的就是我們的redis操作了,五種數據的基本操作如下。

redisTemplate.opsForValue();//操作字元串   redisTemplate.opsForHash();//操作hash  redisTemplate.opsForList();//操作list  redisTemplate.opsForSet();//操作set  redisTemplate.opsForZSet();//操作有序set

還有什麼更多的操作不知道的,歡迎來我的公眾號內問答,我會依依給你解釋清楚的。

哨兵架構

  哨兵架構,是主從的升級版,master節點宕機後,可以主動選取我們的master節點。

  我們還是分為jedis和springboot兩種方式分別來嘗試連接一下我們的哨兵架構,搭建我就不說啦,上次博文已經說過了。https://www.cnblogs.com/cxiaocai/p/11711377.html  

  jedis

  還是老規矩,引入依賴,剩下的我們直接來寫測試類吧。

package com.redisclient.sentinel;    import redis.clients.jedis.*;  import java.util.HashSet;  import java.util.Set;    public class JedisClientSentinel {        public static void main(String[] args) {          JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();          jedisPoolConfig.setMaxTotal(20);          jedisPoolConfig.setMaxIdle(10);          jedisPoolConfig.setMinIdle(5);            String masterName = "mymaster";          Set<String> sentinels = new HashSet<String>();          sentinels.add(new HostAndPort("47.105.97.79", 6380).toString());          sentinels.add(new HostAndPort("47.105.97.142", 6380).toString());          sentinels.add(new HostAndPort("118.190.147.181", 6380).toString());          //JedisSentinelPool其實本質跟JedisPool類似,都是與redis主節點建立的連接池          //JedisSentinelPool並不是說與sentinel建立的連接池,而是通過sentinel發現redis主節點並與其建立連接          JedisSentinelPool jedisPool = new JedisSentinelPool(masterName, sentinels, jedisPoolConfig, 5000, null);            Jedis jedis = null;          try {              //從redis連接池裡拿出一個連接執行命令              jedis = jedisPool.getResource();              System.out.println(jedis.set("xiaocai888", "666888"));              System.out.println(jedis.get("xiaocai888"));          } catch (Exception e) {              e.printStackTrace();          } finally {              //注意這裡不是關閉連接,在JedisPool模式下,Jedis會被歸還給資源池。              if (jedis != null)                  jedis.close();          }      }    }

  最簡單的理解就是我們建立了一個set連接池。當哨兵節點宕機一個的時候,會嘗試連接其它節點,當master節點宕機時,會報錯連接錯誤,稍後會自動恢復的。 ✨

  springboot

  我們先來修改一下我們yml配置文件

#哨兵模式  spring:    redis:      database: 0 # Redis資料庫索引(默認為0)      host: 120.27.27.4 # Redis伺服器地址      port: 6379 # Redis伺服器連接埠      password: # Redis伺服器連接密碼(默認為空)      timeout: 5000 # 連接超時時間(毫秒)      sentinel:        master: mymaster #主伺服器所在集群名稱        nodes: 115.28.208.105:26379,47.105.92.89:26379,118.190.151.92:26379

  而我們的測試類和主從是一樣的配置就可以了,springboot主要改一下配置就可以了。

集群架構

  上次我們說過了我們的集群架構,就是很多個小主從集合在一起,內部有半數機制,建議設置大於3的奇數個主從服務。

   這從我們來搭建三組一主一從服務,我們先來看一下jedis的程式碼,我們內部redis是將16384分為了三個片區,為了確保每個片區都存入數據我們採用了隨機生成的key。

  jedis

package com.redisclient.cluster;    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;  import redis.clients.jedis.*;  import java.io.IOException;  import java.util.HashSet;  import java.util.Random;  import java.util.Set;    public class JedisClientCluster {        public static void main(String[] args) throws IOException {          GenericObjectPoolConfig config = new GenericObjectPoolConfig();          config.setMaxTotal(20);          config.setMaxIdle(10);          config.setMinIdle(5);          //這裡將所有主從節點全部放入          Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();          jedisClusterNode.add(new HostAndPort("120.27.27.4", 6379));          jedisClusterNode.add(new HostAndPort("47.105.86.150", 6379));          jedisClusterNode.add(new HostAndPort("47.105.84.186", 6379));          jedisClusterNode.add(new HostAndPort("115.28.208.105", 6379));          jedisClusterNode.add(new HostAndPort("47.105.92.89", 6379));          jedisClusterNode.add(new HostAndPort("118.190.151.92", 6379));            JedisCluster jedisCluster = null;          try {              //connectionTimeout:指的是連接一個url的連接等待時間              //soTimeout:指的是連接上一個url,獲取response的返回等待時間              jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "xiaocai", config);              while (true) {                  try {                      jedisCluster.set(getRandomString(4), "value" + getRandomString(4));                      Thread.sleep(5000);                  } catch (Exception e) {                      e.printStackTrace();                  }              }          } catch (Exception e) {              e.printStackTrace();          } finally {              if (jedisCluster != null)                  jedisCluster.close();          }      }        //length用戶要求產生字元串的長度      public static String getRandomString(int length) {          String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";          Random random = new Random();          StringBuffer sb = new StringBuffer();          for (int i = 0; i < length; i++) {              int number = random.nextInt(62);              sb.append(str.charAt(number));          }          return sb.toString();      }    }

  springboot

  還是老規矩改一下配置類 

# 集群模式  spring:    redis:      database: 0 # Redis資料庫索引(默認為0)      host: 120.27.27.4 # Redis伺服器地址      port: 6379 # Redis伺服器連接埠      password: xiaocai # Redis伺服器連接密碼(默認為空)      timeout: 5000 # 連接超時時間(毫秒)      cluster:        nodes: 115.28.208.105:6379,47.105.92.89:6379,118.190.151.92:6379

  說到這裡我們的三種模式的連接就全部寫完了,這些使用還是一個比一個簡單的,我們來看下內部的通訊和選舉機制吧。

選舉機制

  當slave發現自己的master變為FAIL狀態時,便嘗試進行Failover,以期成為新的master。由於掛掉的master可能會有 多個slave,從而存在多個slave競爭成為master節點的過程, 其過程如下:

1.slave發現自己的master變為FAIL

2.將自己記錄的集群currentEpoch加1,並廣播FAILOVER_AUTH_REQUEST 資訊

3.其他節點收到該資訊,只有master響應,判斷請求者的合法性,並發送FAILOVER_AUTH_ACK,對每一個epoch只發 送一次ack

4.嘗試failover的slave收集master返回的FAILOVER_AUTH_ACK

5.slave收到超過半數master的ack後變成新Master(這裡解釋了集群為什麼至少需要三個主節點,如果只有兩個,當其 中一個掛了,只剩一個主節點是不能選舉成功的)

6.廣播Pong消息通知其他集群節點。從節點並不是在主節點一進入 FAIL 狀態就馬上嘗試發起選舉,而是有一定延遲,一定的延遲確保我們等待FAIL狀態在 集群中傳播,slave如果立即嘗試選舉,其它masters或許尚未意識到FAIL狀態,可能會拒絕投票

  最近公司有一些事情,就先說到這裡吧,有時間給大家說一下redis來實現分散式鎖的機制,還有一個炒雞好用的redis分散式鎖。

 

最進弄了一個公眾號,小菜技術,歡迎大家的加入