redis單例提供了一種數據緩存方式和豐富的數據操作api,但是將數據完全存儲在單個redis中主要存在兩個問題:數據備份和數據體量較大造成的性能降低。這裏redis的主從模式爲這兩個問題提供了一個較好的解決方案。
主從模式指的是使用一個redis實例作爲主機,其餘的實例作爲備份機。主機和從機的數據完全一致,主機支持數據的寫入和讀取等各項操作,而從機則只支持與主機數據的同步和讀取,也就是說,客戶端可以將數據寫入到主機,由主機自動將數據的寫入操作同步到從機。
主從模式很好的解決了數據備份問題,並且由於主從服務數據幾乎是一致的,因而可以將寫入數據的命令發送給主機執行,
而讀取數據的命令發送給不同的從機執行,從而達到讀寫分離的目的。如下所示主機redis-A分別有redis-B、redis-C、redis-D、redis-E四個從機:
一:搭建Redis的主從模式環境:
redis主從模式的配置可以理解爲多個不同的redis實例通過一定的配置告知其相互之間的主從關係。
而前面已經介紹,每個redis實例都會佔用一個本機的端口號,主從模式的配置主要的配置點有兩個:當前實例端口號和當前實例是主機還是從機,是從機的話其主機的ip和端口是什麼。一般的redis目錄下的redis.conf保存的是默認配置,儘量不要對其進行修改,這裏我們複製三份redis.conf文件,分別命名爲6379.conf,6380.conf和6381.conf,如下是端口爲6379的主機的主要配置:
每一個對應的配置如下,注意修改端口號和主機名稱
bind 127.0.0.1
port 6381
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 127.0.0.1 6379
依次修改配置後啓動:
./src/redis-server 6379.conf
./src/redis-server 6380.conf
./src/redis-server 6381.conf
分別在三個命令行工具中執行一個get命令,獲取鍵名爲msg的數據,如下所示:
客戶端連接:
採用Redission客戶端進行連接:
導入依賴如下:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.6.0</version>
</dependency>
package com.ishangjie.config;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.client.codec.Codec;
import org.redisson.codec.CodecProvider;
import org.redisson.config.Config;
import org.redisson.liveobject.provider.ResolverProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/**
* redisson分佈式鎖解決方案
* @author liuty
*
*/
@Configuration
public class RedissonProxy implements RedissonClient{
@Value("${redis.hostname}")
private String hostName;
@Value("${redis.port}")
private String port;
private String password;
@Value("${redis.connectionMinimumIdleSize}")
private int connectionMinimumIdleSize;
@Value("${redis.connectionPoolSize}")
private int connectionPoolSize;
private int connectTimeout = 10000;
/**
* Redis server response timeout. Starts to countdown when Redis command was succesfully sent.
* Value in milliseconds.
*
*/
private int timeout = 3000;
private RedissonClient delegateRedissonClient;
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getConnectionPoolSize() {
return connectionPoolSize;
}
public void setConnectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
}
@PostConstruct
public void init() {
Config config = new Config();
String address = hostName + ":" + port;
config.useSingleServer()
.setAddress(address)
.setPassword(password)
.setConnectionMinimumIdleSize(connectionMinimumIdleSize)
.setConnectionPoolSize(connectionPoolSize)
.setTimeout(timeout)
.setConnectTimeout(connectTimeout);
delegateRedissonClient = Redisson.create(config);
}
@Override
public RBinaryStream getBinaryStream(String name) {
return delegateRedissonClient.getBinaryStream(name);
}
@Override
public <V> RGeo<V> getGeo(String name) {
return delegateRedissonClient.getGeo(name);
}
@Override
public <V> RGeo<V> getGeo(String name, Codec codec) {
return delegateRedissonClient.getGeo(name, codec);
}
@Override
public <V> RSetCache<V> getSetCache(String name) {
return delegateRedissonClient.getSetCache(name);
}
@Override
public <V> RSetCache<V> getSetCache(String name, Codec codec) {
return delegateRedissonClient.getSetCache(name, codec);
}
@Override
public <K, V> RMapCache<K, V> getMapCache(String name, Codec codec) {
return delegateRedissonClient.getMapCache(name, codec);
}
@Override
public <K, V> RMapCache<K, V> getMapCache(String name) {
return delegateRedissonClient.getMapCache(name);
}
@Override
public <V> RBucket<V> getBucket(String name) {
return delegateRedissonClient.getBucket(name);
}
@Override
public <V> RBucket<V> getBucket(String name, Codec codec) {
return delegateRedissonClient.getBucket(name, codec);
}
@Override
public RBuckets getBuckets() {
return delegateRedissonClient.getBuckets();
}
@Override
public RBuckets getBuckets(Codec codec) {
return delegateRedissonClient.getBuckets(codec);
}
@Override
public <V> RHyperLogLog<V> getHyperLogLog(String name) {
return delegateRedissonClient.getHyperLogLog(name);
}
@Override
public <V> RHyperLogLog<V> getHyperLogLog(String name, Codec codec) {
return delegateRedissonClient.getHyperLogLog(name, codec);
}
@Override
public <V> RList<V> getList(String name) {
return delegateRedissonClient.getList(name);
}
@Override
public <V> RList<V> getList(String name, Codec codec) {
return delegateRedissonClient.getList(name, codec);
}
@Override
public <K, V> RListMultimap<K, V> getListMultimap(String name) {
return delegateRedissonClient.getListMultimap(name);
}
@Override
public <K, V> RListMultimap<K, V> getListMultimap(String name, Codec codec) {
return delegateRedissonClient.getListMultimap(name, codec);
}
@Override
public <K, V> RListMultimapCache<K, V> getListMultimapCache(String name) {
return delegateRedissonClient.getListMultimapCache(name);
}
@Override
public <K, V> RListMultimapCache<K, V> getListMultimapCache(String name, Codec codec) {
return delegateRedissonClient.getListMultimapCache(name, codec);
}
@Override
public <K, V> RMap<K, V> getMap(String name) {
return delegateRedissonClient.getMap(name);
}
@Override
public <K, V> RMap<K, V> getMap(String name, Codec codec) {
return delegateRedissonClient.getMap(name, codec);
}
@Override
public <K, V> RSetMultimap<K, V> getSetMultimap(String name) {
return delegateRedissonClient.getSetMultimap(name);
}
@Override
public <K, V> RSetMultimap<K, V> getSetMultimap(String name, Codec codec) {
return delegateRedissonClient.getSetMultimap(name, codec);
}
@Override
public <K, V> RSetMultimapCache<K, V> getSetMultimapCache(String name) {
return delegateRedissonClient.getSetMultimapCache(name);
}
@Override
public <K, V> RSetMultimapCache<K, V> getSetMultimapCache(String name, Codec codec) {
return delegateRedissonClient.getSetMultimapCache(name, codec);
}
@Override
public RSemaphore getSemaphore(String name) {
return delegateRedissonClient.getSemaphore(name);
}
@Override
public RPermitExpirableSemaphore getPermitExpirableSemaphore(String name) {
return delegateRedissonClient.getPermitExpirableSemaphore(name);
}
@Override
public RLock getLock(String name) {
return delegateRedissonClient.getLock(name);
}
@Override
public RLock getFairLock(String name) {
return delegateRedissonClient.getFairLock(name);
}
@Override
public RReadWriteLock getReadWriteLock(String name) {
return delegateRedissonClient.getReadWriteLock(name);
}
@Override
public <V> RSet<V> getSet(String name) {
return delegateRedissonClient.getSet(name);
}
@Override
public <V> RSet<V> getSet(String name, Codec codec) {
return delegateRedissonClient.getSet(name, codec);
}
@Override
public <V> RSortedSet<V> getSortedSet(String name) {
return delegateRedissonClient.getSortedSet(name);
}
@Override
public <V> RSortedSet<V> getSortedSet(String name, Codec codec) {
return delegateRedissonClient.getSortedSet(name, codec);
}
@Override
public <V> RScoredSortedSet<V> getScoredSortedSet(String name) {
return delegateRedissonClient.getScoredSortedSet(name);
}
@Override
public <V> RScoredSortedSet<V> getScoredSortedSet(String name, Codec codec) {
return delegateRedissonClient.getScoredSortedSet(name, codec);
}
@Override
public RLexSortedSet getLexSortedSet(String name) {
return delegateRedissonClient.getLexSortedSet(name);
}
@Override
public <M> RTopic<M> getTopic(String name) {
return delegateRedissonClient.getTopic(name);
}
@Override
public <M> RTopic<M> getTopic(String name, Codec codec) {
return delegateRedissonClient.getTopic(name, codec);
}
@Override
public <M> RPatternTopic<M> getPatternTopic(String pattern) {
return delegateRedissonClient.getPatternTopic(pattern);
}
@Override
public <M> RPatternTopic<M> getPatternTopic(String pattern, Codec codec) {
return delegateRedissonClient.getPatternTopic(pattern, codec);
}
@Override
public <V> RQueue<V> getQueue(String name) {
return delegateRedissonClient.getQueue(name);
}
@Override
public <V> RQueue<V> getQueue(String name, Codec codec) {
return delegateRedissonClient.getQueue(name, codec);
}
@Override
public <V> RBlockingQueue<V> getBlockingQueue(String name) {
return delegateRedissonClient.getBlockingDeque(name);
}
@Override
public <V> RBlockingQueue<V> getBlockingQueue(String name, Codec codec) {
return delegateRedissonClient.getBlockingQueue(name, codec);
}
@Override
public <V> RBoundedBlockingQueue<V> getBoundedBlockingQueue(String name) {
return delegateRedissonClient.getBoundedBlockingQueue(name);
}
@Override
public <V> RBoundedBlockingQueue<V> getBoundedBlockingQueue(String name, Codec codec) {
return delegateRedissonClient.getBoundedBlockingQueue(name, codec);
}
@Override
public <V> RDeque<V> getDeque(String name) {
return delegateRedissonClient.getDeque(name);
}
@Override
public <V> RDeque<V> getDeque(String name, Codec codec) {
return delegateRedissonClient.getDeque(name, codec);
}
@Override
public <V> RBlockingDeque<V> getBlockingDeque(String name) {
return delegateRedissonClient.getBlockingDeque(name);
}
@Override
public <V> RBlockingDeque<V> getBlockingDeque(String name, Codec codec) {
return delegateRedissonClient.getBlockingDeque(name, codec);
}
@Override
public RAtomicLong getAtomicLong(String name) {
return delegateRedissonClient.getAtomicLong(name);
}
@Override
public RAtomicDouble getAtomicDouble(String name) {
return delegateRedissonClient.getAtomicDouble(name);
}
@Override
public RCountDownLatch getCountDownLatch(String name) {
return delegateRedissonClient.getCountDownLatch(name);
}
@Override
public RBitSet getBitSet(String name) {
return delegateRedissonClient.getBitSet(name);
}
@Override
public <V> RBloomFilter<V> getBloomFilter(String name) {
return delegateRedissonClient.getBloomFilter(name);
}
@Override
public <V> RBloomFilter<V> getBloomFilter(String name, Codec codec) {
return delegateRedissonClient.getBloomFilter(name, codec);
}
@Override
public RScript getScript() {
return delegateRedissonClient.getScript();
}
@Override
public RScheduledExecutorService getExecutorService(String name) {
return delegateRedissonClient.getExecutorService(name);
}
@Override
@Deprecated
public RScheduledExecutorService getExecutorService(Codec codec, String name) {
return delegateRedissonClient.getExecutorService(codec, name);
}
@Override
public RRemoteService getRemoteService() {
return delegateRedissonClient.getRemoteService();
}
@Override
public RRemoteService getRemoteService(Codec codec) {
return delegateRedissonClient.getRemoteService(codec);
}
@Override
public RRemoteService getRemoteService(String name) {
return delegateRedissonClient.getRemoteService(name);
}
@Override
public RRemoteService getRemoteService(String name, Codec codec) {
return delegateRedissonClient.getRemoteService(name, codec);
}
@Override
public RBatch createBatch() {
return delegateRedissonClient.createBatch();
}
@Override
public RKeys getKeys() {
return delegateRedissonClient.getKeys();
}
@Override
public RLiveObjectService getLiveObjectService() {
return delegateRedissonClient.getLiveObjectService();
}
@Override
public void shutdown() {
delegateRedissonClient.shutdown();
}
@Override
public void shutdown(long quietPeriod, long timeout, TimeUnit unit) {
delegateRedissonClient.shutdown(quietPeriod,timeout,unit);
}
@Override
public Config getConfig() {
return delegateRedissonClient.getConfig();
}
@Override
public NodesGroup<Node> getNodesGroup() {
return delegateRedissonClient.getNodesGroup();
}
@Override
public ClusterNodesGroup getClusterNodesGroup() {
return delegateRedissonClient.getClusterNodesGroup();
}
@Override
public boolean isShutdown() {
return delegateRedissonClient.isShutdown();
}
@Override
public boolean isShuttingDown() {
return delegateRedissonClient.isShuttingDown();
}
@Override
public CodecProvider getCodecProvider() {
return delegateRedissonClient.getCodecProvider();
}
@Override
public <K, V> RLocalCachedMap<K, V> getLocalCachedMap(String key, LocalCachedMapOptions options) {
return delegateRedissonClient.getLocalCachedMap(key, options);
}
@Override
public <K, V> RLocalCachedMap<K, V> getLocalCachedMap(String key, Codec codec, LocalCachedMapOptions options) {
return delegateRedissonClient.getLocalCachedMap(key, codec,options);
}
@Override
public ResolverProvider getResolverProvider() {
return delegateRedissonClient.getResolverProvider();
}
public int getConnectionMinimumIdleSize() {
return connectionMinimumIdleSize;
}
public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
this.connectionMinimumIdleSize = connectionMinimumIdleSize;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}
application.yml 的配置信息如下
redis:
hostname: 192.168.63.133
port: 6379
connectionMinimumIdleSize: 10
connectTimeout: 1000
timeout: 3000
connectionPoolSize: 64
調用方式如下:
package com.ishangjie.controller;
import com.ishangjie.config.RedissonProxy;
import com.ishangjie.service.Aservice;
import org.redisson.api.RBucket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
/**
* @describe: 註冊功能
* author: liutengyuan
* @date: Created in 2019/2/27 16:19
**/
@RestController
public class Acontroller {
@Autowired
private Aservice aservice;
@Autowired
RedissonProxy redissonProxy;
public Acontroller() {
System.out.println("Acontroller is been created, Aservice = " + aservice );
}
@PostConstruct
public void init (){
System.out.println("執行了postConstruct 方法");
}
@RequestMapping("/spring/A")
public String getA(){
RBucket<Object> key = redissonProxy.getBucket("key");
key.set("aa");
return (String) redissonProxy.getBucket("key").get();
}
}
最後啓動Spring Boot 項目,在瀏覽器進行訪問URL:
而key的值也發生了變化: