Redis-3.0.7 集群
安装redis
下载redis-3.0.7tar.gz
tar -zxvf redis-3.0.7tar.gz
cd redis-3.0.7
make过程可能报错,原因是缺少包,按提示安装即可
make
cp /home/redis/app/redis-3.0.7/src/redis-trib.rb /usr/local/bin
cp /home/redis/app/redis-3.0.7/src/redis-server /usr/local/bin
cp /home/redis/app/redis-3.0.7/src/redis-cli /usr/local/bin
/opt目录下建立redis目录
cd /opt
mkdir redis
cd reids
mkdir conf
mkdir data
mkdir logs
建立配置文件
- 新建redis-common.conf
#GENERAL
daemonize yes
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
databases 16
dir /opt/redis/data
slave-serve-stale-data yes
#slave只读
slave-read-only yes
#not use default
repl-disable-tcp-nodelay yes
slave-priority 100
#打开aof持久化
appendonly yes
#每秒一次aof写
appendfsync everysec
#关闭在aof rewrite的时候对新的写操作进行fsync
no-appendfsync-on-rewrite yes
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
#打开redis集群
cluster-enabled yes
#节点互连超时的阀值
cluster-node-timeout 15000
cluster-migration-barrier 1
slowlog-log-slower-than 10000
slowlog-max-len 128
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
- conf目录下建立6个实例配置文件:
redis@ubuntu:/opt/redis/conf$ ll
total 32
drwxrwxr-x 2 redis redis 4096 Jul 22 16:36 ./
drwxr-xr-x 5 redis redis 4096 Jul 26 13:22 ../
-rw-rw-r-- 1 redis redis 976 Jul 22 11:28 redis-6379.conf
-rw-rw-r-- 1 redis redis 1002 Jul 22 16:31 redis-6380.conf
-rw-rw-r-- 1 redis redis 973 Jul 22 16:31 redis-6381.conf
-rw-rw-r-- 1 redis redis 976 Jul 22 16:35 redis-7379.conf
-rw-rw-r-- 1 redis redis 1002 Jul 22 16:36 redis-7380.conf
-rw-rw-r-- 1 redis redis 973 Jul 22 16:36 redis-7381.conf
- redis-6379.conf配置如下,其他conf只是端口不一致
#包含通用配置
include /opt/redis/redis-common.conf
#监听tcp端口
port 6379
#最大可用内存
maxmemory 100m
#内存耗尽时采用的淘汰策略:
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key accordingly to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
maxmemory-policy allkeys-lru
#aof存储文件
appendfilename "appendonly-6379.aof"
#rdb文件,只用于动态添加slave过程
dbfilename dump-6379.rdb
#cluster配置文件(启动自动生成)
cluster-config-file nodes-6379.conf
#部署在同一机器的redis实例,防止瞬间fork所有redis进程做rewrite,占用大量内存</span>
auto-aof-rewrite-percentage 80-100
编写6个实例启动脚本start_redis_cluster.sh
start_redis_cluster.sh代码如下:
redis-server /opt/redis/conf/redis-6379.conf > /opt/redis/logs/redis-6379.log 2>&1 &
redis-server /opt/redis/conf/redis-6380.conf > /opt/redis/logs/redis-6380.log 2>&1 &
redis-server /opt/redis/conf/redis-6381.conf > /opt/redis/logs/redis-6381.log 2>&1 &
redis-server /opt/redis/conf/redis-7379.conf > /opt/redis/logs/redis-7379.log 2>&1 &
redis-server /opt/redis/conf/redis-7380.conf > /opt/redis/logs/redis-7380.log 2>&1 &
redis-server /opt/redis/conf/redis-7381.conf > /opt/redis/logs/redis-7381.log 2>&1 &
编写集群启动脚本start_redis_trib.sh
start_redis_trib.sh代码如下:
redis-trib.rb create --replicas 1 192.168.114.129:6379 192.168.114.129:6380 192.168.114.129:6381 192.168.114.129:7379 192.168.114.129:7380 192.168.114.129:7381
注意此处要写具体实际IP与端口,不能写127.0.0.1,不然不能被非本机应用调用。
启动集群
依次执行:
start_redis_cluster.sh
start_redis_trib.sh
JAVA调用redis集群
pom.xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Spring配置文件
<!-- 扫描properties文件 -->
<context:property-placeholder ignore-resource-not-found="false" location="classpath*:*.properties" />
<description>Redis配置</description>
<!-- redis连接池的配置 -->
<bean name="genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}" />
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="minIdle" value="${redis.pool.minIdle}" />
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
<!-- <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> -->
<!-- 有如下两个参数,初始化genericObjectPoolConfig会报错,(没有日志提示,应该为bug),导致后续从pool获取连接时报错
<property name="testOnReturn" value="${redis.pool.testOnReturn}" />
<property name="testWhileIdle" value="${redis.pool.testWhileIdle" /> -->
</bean>
<!-- jedisCluster实现服务端集群 -->
<bean id="jedisCluster" class="com.demo.redis.cluster.JedisClusterFactory">
<property name="addressConfig" value="classpath:connect-redis.properties" />
<property name="addressKeyPrefix" value="address" /> <!-- 属性文件里 key的前缀 -->
<property name="timeout" value="0" />
<property name="maxRedirections" value="1" />
<property name="genericObjectPoolConfig" ref="genericObjectPoolConfig" />
</bean>
connect-redis.properties配置文件(据说写一个地址就行)
address1=192.168.114.129:6379
address2=192.168.114.129:6380
address3=192.168.114.129:6381
##address4=192.168.114.129:7379
##address5=192.168.114.129:7381
##address6=192.168.114.129:7382
Java代码
JedisClusterFactory代码(来源于网络)
package com.demo.redis.cluster;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {
private Resource addressConfig;
private String addressKeyPrefix ;
private JedisCluster jedisCluster;
private Integer timeout;
private Integer maxRedirections;
private GenericObjectPoolConfig genericObjectPoolConfig;
private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");
@Override
public JedisCluster getObject() throws Exception {
return jedisCluster;
}
@Override
public Class<? extends JedisCluster> getObjectType() {
return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);
}
@Override
public boolean isSingleton() {
return true;
}
private Set<HostAndPort> parseHostAndPort() throws Exception {
try {
Properties prop = new Properties();
prop.load(this.addressConfig.getInputStream());
Set<HostAndPort> haps = new HashSet<HostAndPort>();
for (Object key : prop.keySet()) {
if (!((String) key).startsWith(addressKeyPrefix)) {
continue;
}
String val = (String) prop.get(key);
boolean isIpPort = p.matcher(val).matches();
if (!isIpPort) {
throw new IllegalArgumentException("ip 或 port 不合法");
}
String[] ipAndPort = val.split(":");
HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));
haps.add(hap);
}
return haps;
} catch (IllegalArgumentException ex) {
throw ex;
} catch (Exception ex) {
throw new Exception("解析 jedis 配置文件失败", ex);
}
}
@Override
public void afterPropertiesSet() throws Exception {
Set<HostAndPort> haps = this.parseHostAndPort();
jedisCluster = new JedisCluster(haps, timeout, maxRedirections,genericObjectPoolConfig);
}
public void setAddressConfig(Resource addressConfig) {
this.addressConfig = addressConfig;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setMaxRedirections(int maxRedirections) {
this.maxRedirections = maxRedirections;
}
public void setAddressKeyPrefix(String addressKeyPrefix) {
this.addressKeyPrefix = addressKeyPrefix;
}
public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {
this.genericObjectPoolConfig = genericObjectPoolConfig;
}
}
RedisTest代码
package com.demo.redis;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import redis.clients.jedis.JedisCluster;
@RunWith(SpringJUnit4ClassRunner.class)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@ContextConfiguration({ "classpath*:applicationContext.xml","classpath*:redis-cluster.xml" })
public class RedisTest {
private static final Logger log = LoggerFactory.getLogger(RedisTest.class);
@Autowired
private JedisCluster jedisCluster;
@Test
public void testCluster(){
log.debug("start...");
int i=0;
while(i<=10000){
jedisCluster.set(i+"", i+"");
log.debug(jedisCluster.get(i+""));
i++;
}
log.debug("...end!!!");
}
}