jedis針對三種redis工作模式、哨兵模式的原始碼閱讀分析
阿新 • • 發佈:2018-12-25
只要是非單機模式,一定要配置JedisPoolConfig,無論何種叢集,最終都是要通過它的原始碼中是這樣寫的
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class JedisPoolConfig extends GenericObjectPoolConfig { public JedisPoolConfig() { // defaults to make your life with connection pool easier :) setTestWhileIdle(true); setMinEvictableIdleTimeMillis(60000); setTimeBetweenEvictionRunsMillis(30000); setNumTestsPerEvictionRun(-1); } }
在spring配置中,如果想要更改其引數值,直接覆寫該值即可。在Spring中這個基本連線池一般這樣配置
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="200" /> <property name="maxIdle" value="30" /> <property name="maxWaitMillis" value="30000" /> <property name="testOnBorrow" value="false" /><!-- 向呼叫者輸出“連結”資源時,是否檢測是有有效,如果無效則從連線池中移除,並嘗試獲取繼續獲取。設為true,一個掛都不能用 --> <property name="testOnReturn" value="true" /><!-- 向連線池“歸還”連結時,是否檢測“連結”物件的有效性。 --> </bean>
這裡說的三種工作模式是指:
1、單機模式
Jedis jedis=new Jedis("192.168.0.100", 6379);
這種是最純粹的單機模式,一般都採用連線池+連線工廠(JedisConnectionFactory)的模式進行開發
public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory { private final static Log log = LogFactory.getLog(JedisConnectionFactory.class); private static final ExceptionTranslationStrategy EXCEPTION_TRANSLATION = new PassThroughExceptionTranslationStrategy( JedisConverters.exceptionConverter()); private static final Method SET_TIMEOUT_METHOD; private static final Method GET_TIMEOUT_METHOD; private JedisShardInfo shardInfo; private String hostName = "localhost"; private int port = Protocol.DEFAULT_PORT; private int timeout = Protocol.DEFAULT_TIMEOUT; private String password; private boolean usePool = true; private Pool<Jedis> pool; private JedisPoolConfig poolConfig = new JedisPoolConfig(); private int dbIndex = 0; private boolean convertPipelineAndTxResults = true; private RedisSentinelConfiguration sentinelConfig;
由原始碼中分析可以得到,預設的主機名是localhst這個顯然不行,肯定要覆蓋重新主機為真是的IP地址,然後加上連線池資訊,通過注入方式即可實現。
2、分片模式
通過分片池ShardedJedisPool 實現
通過閱讀原始碼,我們可以看到它的其中一個建構函式為(CTRL+SHIFT_T直接原始碼中查詢)
public class ShardedJedisPool extends Pool<ShardedJedis> {
public ShardedJedisPool(final GenericObjectPoolConfig poolConfig, List<JedisShardInfo> shards) {
this(poolConfig, shards, Hashing.MURMUR_HASH);
}
根據這個建構函式,我們可以在spring實現它
<!-- redis sharding -->
<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
<constructor-arg index="0" ref="jedisPoolConfig" />
<constructor-arg index="1">
<list>
<bean name="redis1" class="com.my.cache.MyJedisShardInfo">
<constructor-arg index="0" value="${redis.slaver1.host}" />
<constructor-arg index="1" value="${redis.client.connectionTimeout}" />
<constructor-arg index="2" value="${redis.client.soTimeout}" />
</bean>
<bean name="redis2" class="com.my.cache.MyJedisShardInfo">
<constructor-arg index="0" value="${redis.slaver2.host}" />
<constructor-arg index="1" value="${redis.client.connectionTimeout}" />
<constructor-arg index="2" value="${redis.client.soTimeout}" />
</bean>
</list>
</constructor-arg>
</bean>
3、叢集模式(since 3.0)
通過JedisCluster實現,原始碼建構函式如下所示,一般叢集環境中,我們要加上基本連線池,所以選擇第一個建構函式。
public class JedisCluster implements JedisCommands, BasicCommands, Closeable {
public static final short HASHSLOTS = 16384;
private static final int DEFAULT_TIMEOUT = 2000;
private static final int DEFAULT_MAX_REDIRECTIONS = 5;
public static enum Reset {
SOFT, HARD
}
private int maxRedirections;
private JedisClusterConnectionHandler connectionHandler;
public JedisCluster(Set<HostAndPort> nodes, final GenericObjectPoolConfig poolConfig) {
this(nodes, DEFAULT_TIMEOUT, DEFAULT_MAX_REDIRECTIONS, poolConfig);
}
public JedisCluster(Set<HostAndPort> nodes) {
this(nodes, DEFAULT_TIMEOUT);
}
哨兵模式是通過JedisSentinelPool 實現的,原始碼如下
public class JedisSentinelPool extends Pool<Jedis> {
protected GenericObjectPoolConfig poolConfig;
protected int timeout = Protocol.DEFAULT_TIMEOUT;
protected String password;
protected int database = Protocol.DEFAULT_DATABASE;
protected Set<MasterListener> masterListeners = new HashSet<MasterListener>();
protected Logger log = Logger.getLogger(getClass().getName());
private volatile JedisFactory factory;
private volatile HostAndPort currentHostMaster;
public JedisSentinelPool(String masterName, Set<String> sentinels,
final GenericObjectPoolConfig poolConfig) {
this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null,
Protocol.DEFAULT_DATABASE);
}
這樣在spring就可以這樣寫,第一個建構函式的引數為master伺服器,這個由於在原始碼中沒有單獨寫出來,所以我們只能用構造器方式去射入值。
<bean id="jedisPool" class="redis.clients.jedis.JedisSentinelPool">
<constructor-arg index="0" value="mymaster" />
<constructor-arg index="1">
<set>
<value>127.0.0.1:26379</value>
<value>127.0.0.1:36379</value><!--配置了兩個哨兵 -->
</set>
</constructor-arg>
<constructor-arg index="2" ref="jedisPoolConfig" />
</bean>
通過配置後,在程式中就可以直接引用:
@Resource
private JedisSentinelPool jedisSentinelPool;
然後通過jedis=jedisSentinelPool.getResource();就可以獲取當前的jedis了