# linux安装redis
#注意,要使用gcc8, centos7.9默认的gcc4.8.5编译会报错
wget http://download.redis.io/releases/redis-6.0.9.tar.gz
tar -zxvf redis-6.0.9.tar.gz
cd redis-6.0.9
make
make install
nohup redis-server > out.log &
# 无网环境安装
- centos7.9默认使用 gcc4.8.5
- 可以基于redis5.x版本进行编译.
wget http://download.redis.io/releases/redis-5.0.6.tar.gz
tar -zxvf redis-5.0.6.tar.gz
cd redis-5.0.6
make install -j4 PREFIX=/u01/redis
# 此外,当前用户需要有 /usr/local/bin的读写权限
make install
nohup redis-server > out.log &
- 除此外,还可以通过有网环境先安装,然后在迁移的方案;
# redis概述
# redis的由来
REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。
# redis与其它k-v产品的特点
- 支持数据持久化
- 支持丰富的数据类型
- 支持主从备份
# redis支持的数据类型
- 字符串
- hash字典
- 集合
- 列表
- 有序集合
# redis数据结构操作命令
# redis字符串操作
- 增:
set key value
- 查:
get key
- 批量查:
mget key1 [key2...]
# redis字典操作
- 单数据
- 增:
hset key field value
- 删:
hdel key field1 [field2...]
- 查:
hget key field
- 增:
- 批量操作
- 增:
hmset key field1 value1 [field2 value2...]
- 查:
hgetall key
,hkeys key
,hmget key field [field1...]
- 增:
# redis列表操作
- 增:
lpush key value1 [value2...]
,rpush key value1 [valu2...]
- 查:
lpop key
,rpop key
,llen key
,lrange key start stop
- 改:
lset key index value
# redis集合操作
- 增:
sadd key member1 [member2...]
- 查:
smembers key
,scard key
- 应用操作:
- 取并集:
sunion key1 key2
- 取交集:
sinter key1 key2
- 取并集:
# redis有序集合操作
- 增:
zadd key score1 member [score2 member2...]
- 查:
zcard key
,zscore key member
,zrank key member
# redis通用操作
# 登录数据库
redis-cli.exe -h host -p port
auth password
# key的通用操作
- key是否存在:
exists key
- 删除key:
del key
- 获取key的类型:
type key
- 查询key:
keys pattern
- 设置有效期:
expire key seconds
- 获取有效期:
ttl key
- 清空缓存:
flushdb
# redis集群
# 搭建
以集群模式启动redis-server
port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes bind 0.0.0.0
..\redis-server.exe .\redis.conf
安装ruby脚本语言环境并验证
ruby -version
- 安装ruby-redis插件
gem install redis -v 3.2.1
- 下载redis-trib脚本并执行集群命令
wget https://raw.githubusercontent.com/MSOpenTech/redis/3.0/src/redis-trib.rb
redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
# 注意事项
- 整个过程中,不要使用中文路径;
- 搭建集群时,最好不要使用127.0.0.1作为集群单机ip,在局域网环境下,可能会出现反常现象;
# 客户端连接测试
redis-cli.exe -c -h 127.0.0.1 -p 7000
# redis集群代理
# redis-cluster-proxy
- 官方推出,与java不兼容。redis6.0开始支持,不建议在生产使用;
# twemproxy(nutcraker)
- twitter开源的,可代理redis,memcached. 与java不兼容;
# redis高级运维
# 获取连接信息(超高并发导致服务不可用)
#查看活跃连接数客户端地址(虚拟机层面):
lsof -i:port | awk -F '->' '{print $2}' | awk -F ':' '{print $1}' | awk '{sum[$1]+=1} END {for(k in sum) print k ":" sum[k]}' | sort -n -r -k 2 -t ':'
#查看连接数(redis层面)
infos clients
#查看连接数详细信息
client list #age 和 idle 表示存活的时间,和已经空闲的时间;
#查看配置过的最大连接数
config get maxclients #默认情况下是 10000
# redisJava客户端与模板模式
# 架构设计
public interface RedisOperations<K, V> {
<T> T execute(RedisCallback<T> action);
Boolean hasKey(K key);
Boolean delete(K key);
void rename(K oldKey, K newKey);
Boolean expire(K key, long timeout, TimeUnit unit);
Boolean persist(K key);
ListOperations<K, V> opsForList();
SetOperations<K, V> opsForSet();
//xxx: 省略其它抽象..., 模板所有的实际方法,都是委派给子类execute方法执行的
}
public class RedisAccessor implements InitializingBean {
private @Nullable RedisConnectionFactory connectionFactory;
@Nullable
public RedisConnectionFactory getConnectionFactory() {
return connectionFactory;
}
}
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
try{
RedisConnectionFactory factory = getRequiredConnectionFactory();
//xxx: 从工厂获取连接
RedisConnection conn = RedisConnectionUtils.getConnection(factory);
}finally{
//释放连接(物理层面)
RedisConnectionUtils.releaseConnection(conn, factory, enableTransactionSupport);
}
}
}
# 执行流程
public abstract class RedisConnectionUtils {
public static RedisConnection getConnection(RedisConnectionFactory factory) {
return getConnection(factory, false);
}
public static RedisConnection getConnection(RedisConnectionFactory factory, boolean transactionSupport) {
return doGetConnection(factory, true, false, transactionSupport);
}
public static RedisConnection doGetConnection(RedisConnectionFactory factory, boolean allowCreate, boolean bind,
boolean transactionSupport) {
//xxx: 从工厂中获取连接,省略其它抽象...
//xxx: 工厂本身的缓存机制,由各自厂商实现...略
RedisConnection conn = factory.getConnection();
}
}
# 总结
redis
的关键在于connectionFactory
,spring默认采用lettuce实现spring-data-redis
默认提供了两个bean,分别为按照名称注入的redisTemplate以及按照类型注入的StringRedisTemplate
# 实现自动重连配置(jedis)
# 重定义工厂
public class AutomannnJedisConnectionFactory extends JedisConnectionFactory {
public AutomannnJedisConnectionFactory(RedisClusterConfiguration clusterConfig, JedisClientConfiguration clientConfig) {
super(clusterConfig,clientConfig);
}
@Override
public RedisConnection getConnection() {
try{
RedisConnection connection= super.getConnection();
connection.hashCommands().hGetAll(NO_MEANING_TAG.getBytes());
return connection;
}catch (Exception e){
System.out.println("redis集群异常,尝试进行灾备切换....");
this.afterPropertiesSet();
return super.getConnection();
}
};
}
# 替换默认redisSession存储
class Configuration{
@Bean
public BeanPostProcessor customerSessionRepository() {
BeanPostProcessor beanPostProcessor = new BeanPostProcessor() {
public RedisOperationsSessionRepository sessionRepository(ApplicationEventPublisher publisher,
RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = this.createRedisTemplate(connectionFactory);
RedisOperationsSessionRepository sessionRepository =
new RedisOperationsSessionRepository(redisTemplate);
sessionRepository.setApplicationEventPublisher(publisher);
sessionRepository.setDefaultMaxInactiveInterval(1800);
sessionRepository.setRedisKeyNamespace("spring:session");
sessionRepository.setRedisFlushMode(RedisFlushMode.ON_SAVE);
sessionRepository.setDatabase(0);
return sessionRepository;
}
private RedisTemplate<Object, Object> createRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setBeanClassLoader(getClass().getClassLoader());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RedisOperationsSessionRepository) {
AutomannnJedisConnectionFactory connectionFactory =
applicationContext.getBean(AutomannnJedisConnectionFactory.class);
bean = sessionRepository(applicationContext, connectionFactory);
return bean;
}
return null;
}
};
return beanPostProcessor;
}
@Bean
public AutomannnJedisConnectionFactory automannnJedisConnectionFactory(SessionConfig sessionConfig) {
AutomannnJedisConnectionFactory connectionFactory =
new AutomannnJedisConnectionFactory(sessionConfig.getRedisConnectionFactory().getClusterConfiguration(), sessionConfig.getRedisConnectionFactory().getClientConfiguration());
return connectionFactory;
}
}
# 集成配置
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({Configuration.class})
public @interface EnableRedisSessionReConnect {
}
# 连接的实现细节
public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
protected Jedis fetchJedisConnector() {
if (getUsePool() && pool != null) {
return pool.getResource();
}
Jedis jedis = createJedis();
jedis.connect();
potentiallySetClientName(jedis);
return jedis;
}
}
- 默认情况下,如果配置了pool参数,则会使用连接池