git@github.com:pengbiaobeyond/redis.git
0、redis环境搭建
1. 上传Redis的安装包
redis-5.0.6.tar.gz
2. 解压我们的Redis安装包
tar -zxvf redis-5.0.6.tar.gz
3. mkdir /usr/redis
4. make install PREFIX=/usr/redis
5. 启动Redis cd /usr/redis/bin ./redis-server
将Redis设置为后台启动
cp /usr/redis-5.0.6/redis.conf /usr/redis/bin
vi redis.conf daemonize yes
./redis-server ./redis.conf 重启启动Redis
ps aux | grep 'redis'
设置Redis账号密码
搜索:# requirepass foobared
requirepass 123456
客户端连接:auth 123456
设置Reids允许ip访问
注释掉bind 127.0.0.1
protected-mode no ###允许外界访问
redis-5.0.6.tar.gz redisclient-客户端工具.zip
1、五种数据类型
String,List,Hash,set,sorted Set五种数据类型;
2、redis分库,默认十六个库,redis.conf配置文件中 databases 16 可改,可以在微服务中应用不同服务连接不同库;
./redis-cli -h 192.168.212.155 -p 6379 -a 123456
select dbNum
flushdb
3、redis实现订阅
https://blog.csdn.net/Marvel__Dead/article/details/78647383
redis 127.0.0.1:6379> SUBSCRIBE redisChat
redis 127.0.0.1:6379> PUBLISH redisChat “Redis is a great caching technique”
redis 127.0.0.1:6379> PUBLISH redisChat “Learn redis by runoob.com”
# 订阅者的客户端会显示如下消息( 127.0.0.1)
1) “message”
2) “redisChat”
3) “Redis is a great caching technique”
1) “message”
2) “redisChat”
3) “Learn redis by runoob.com”
4、redis主从复制
如果配置主从复制,那么只有主服务器才可以进行写的操作,从服务器只能做读的操作
修改redis.conf配置文件
slaveof 192.168.33.130 6379
masterauth 123456—- 主redis服务器配置了密码,则需要配置
每次redis从服务器启动的时候会向主服务器发送sync包,主服务器接收到以后会在每次写的操作以后保存快照以及所进行的缓存命令,一旦有变化就发给从服务器,然后从服务器执行相应的命令更新缓存值,同时更新快照文件;
5、哨兵机制
心跳机制,监控redis集群,如果master主服务器宕机则在所有从服务器中选举出一个master来,即使以后原来的master机器重新启动好了,它只能是从节点;
实现步骤:
1.拷贝到etc目录(sentinel.cnf配置文件在redis解压包中)
cp sentinel.conf /usr/local/redis/etc
2.修改sentinel.conf配置文件
sentinel monitor mymaster 192.168.110.133 6379 1 #主节点 名称 IP 端口号 选举次数
sentinel auth-pass mymaster 123456 #密码
3. 修改心跳检测 30毫秒
sentinel down-after-milliseconds mymaster 30
4.sentinel parallel-syncs mymaster 2 --- #每次最多可以有1个从同步主。一个从同步结束,另一个从开始同步。
5. 启动哨兵模式
./redis-server /usr/local/redis/etc/sentinel.conf --sentinel &
6. 停止哨兵模式
6、持久化机制
RDB以二进制文件形式将redis中的数据保存起来,以某个时间点进行存储,比如说60s内至少有10次写的操作就会进行存储;
优点:开启单独的进程去做io操作,和当前的redis主进程没有任何关联;
缺点:非实时,突然宕机,数据可能有一部分丢失;
AOF:
实时日志记录写的操作,效率不是很高,会影响到整体的性能,但是AOF比较安全,即使突然宕机,丢失数据的可能性也不大;
RDB:
默认开启,在redis.conf中及配置:
#dbfilename:持久化数据存储在本地的文件
dbfilename dump.rdb
#dir:持久化数据存储在本地的路径,如果是在/redis/redis-3.0.6/src下启动的redis-cli,则数据会存储在当前src目录下
dir ./
##snapshot触发的时机,save
##如下为900秒后,至少有一个变更操作,才会snapshot
##对于此值的设置,需要谨慎,评估系统的变更操作密集程度
##可以通过“save “””来关闭snapshot功能
#save时间,以下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储。
save 900 1
save 300 10
save 60 10000
##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等
stop-writes-on-bgsave-error yes
##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间
rdbcompression yes
AOF:
在Redis的配置文件中存在三种同步方式,它们分别是:
appendfsync always #每次有数据修改发生时都会写入AOF文件,能够保证数据不丢失,但是效率非常低。
appendfsync everysec #每秒钟同步一次,可能会丢失1s内的数据,但是效率非常高。
appendfsync no #从不同步。高效但是数据不会被持久化。
直接修改redis.conf中 appendonly yes
建议最好还是使用everysec 既能够保证数据的同步、效率也还可以
##此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能
##只有在“yes”下,aof重写/文件同步等特性才会生效
appendonly yes
##指定aof文件名称
appendfilename appendonly.aof
##指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec
appendfsync everysec
##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”
no-appendfsync-on-rewrite no
##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”
auto-aof-rewrite-min-size 64mb
##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比。
##每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增长到A*(1 + p)之后
##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。
auto-aof-rewrite-percentage 100
7、Redis事务
public void setString(String key, Object object) {
开启事务权限
stringRedisTemplate.setEnableTransactionSupport(true);
// 开启事务
stringRedisTemplate.multi();
try {
// 如果是String 类型
String value = (String) object;
stringRedisTemplate.opsForValue().set(key, value);
// 提交
stringRedisTemplate.exec();
} catch (Exception e) {
// 回滚
stringRedisTemplate.discard();
} finally {
}
}
8、spring整合一级、二级缓存
Ehcache做一级缓存,Redis做二级缓存;
Ehcache是本地缓存,不需要走网络,而Redis是分布式缓存,需要走网络,所以使用Ehcache会减轻redis的访问压力,也可以提高访问速度;
如果redis在高并发的情况下,宕机了,突然大量请求操作数据库,产生雪崩效应;
@Service
public class UserService {
@Autowired
private EhCacheUtils ehCacheUtils;
private static final String CACHENAME_USERCACHE = "userCache";
@Autowired
private RedisService redisService;
@Autowired
private UserMapper userMapper;
public Users getUser(Long id) {
String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
+ "-id:" + id;
// 1.先查找一级缓存(本地缓存),如果本地缓存有数据直接返回
Users ehUser = (Users) ehCacheUtils.get(CACHENAME_USERCACHE, key);
if (ehUser != null) {
System.out.println("使用key:" + key + ",查询一级缓存 ehCache 获取到ehUser:" + JSONObject.toJSONString(ehUser));
return ehUser;
}
// 2. 如果本地缓存没有该数据,直接查询二级缓存(redis)
String redisUserJson = redisService.getString(key);
if (!StringUtils.isEmpty(redisUserJson)) {
// 将json 转换为对象(如果二级缓存redis中有数据直接返回二级缓存)
JSONObject jsonObject = new JSONObject();
Users user = jsonObject.parseObject(redisUserJson, Users.class);
// 更新一级缓存
ehCacheUtils.put(CACHENAME_USERCACHE, key, user);
System.out.println("使用key:" + key + ",查询二级缓存 redis 获取到ehUser:" + JSONObject.toJSONString(user));
return user;
}
// 3. 如果二级缓存redis中也没有数据,查询数据库
Users user = userMapper.getUser(id);
if (user == null) {
return null;
}
// 更新一级缓存和二级缓存
String userJson = JSONObject.toJSONString(user);
redisService.setString(key, userJson);
ehCacheUtils.put(CACHENAME_USERCACHE, key, user);
System.out.println("使用key:" + key + ",一级缓存和二级都没有数据,直接查询db" + userJson);
return user;
}
}
@Component
public class EhCacheUtils {
// @Autowired
// private CacheManager cacheManager;
@Autowired
private EhCacheCacheManager ehCacheCacheManager;
// cacheName 和 key 区别 就是 redis中的db库 组
// 添加本地缓存 (相同的key 会直接覆盖)
public void put(String cacheName, String key, Object value) {
Cache cache = ehCacheCacheManager.getCacheManager().getCache(cacheName);
Element element = new Element(key, value);
cache.put(element);
}
// 获取本地缓存
public Object get(String cacheName, String key) {
Cache cache = ehCacheCacheManager.getCacheManager().getCache(cacheName);
Element element = cache.get(key);
return element == null ? null : element.getObjectValue();
}
public void remove(String cacheName, String key) {
Cache cache = ehCacheCacheManager.getCacheManager().getCache(cacheName);
cache.remove(key);
}
}