redis--分布式锁+分布式定时任务
1.1:redis特性:
速度快----- 数据存在基于内存,c语言编写,
持久化-----基于内存断电不保存所以对数据的更新将异步的保存到磁盘中
单线程-----无线程冲突
1.2:数据结构(主要前五种):
string(字符串): 字符串,json串,整数或浮点数,string 类型是二进制安全的,意思是 Redis 的 string 可以包含任何数据,
比如图片或者序列化的对象,一个 redis 中字符串 value 最多可以是 512M
hash(哈希):hash 是一个键值对集合,是一个 string 类型的 key和 value 的映射表,key 还是key,
但是value是一个键值对(key-value)。类比于 Java里面的 Map<String,Map<String,Object>> 集合。
list(列表): list 列表,它是简单的字符串列表,按照插入顺序排序,
你可以添加一个元素到列表的头部(左边)或者尾部(右边),它的底层实际上是个链表。
set(集合): Redis 的 set 是 string 类型的无序集合。。
zset(sorted set:有序集合), string 类型的无序集合但他是有序的
BitMaps:位图
HyperLogLog:超小内存唯一值计数
GEO:地理信息定位
支持多种编程语言,功能丰富,主从复制为高可用分布式做基础
1.3:常用的应用场景:
缓存系统,计数器,如转发数评论数,消息队列系统,对消息队列要求不强的
社交网络,排行榜,实时系统, 分布式id生成器 : incre id 单线程不会重复等
yml配置:
redis:
database: 0 redis数据库
host:
port:
password:
jedis:
pool:
max-active: 18
max-wait: -1
max-idle: 16
min-idle: 0
timeout: 1000ms
1.4:常见问题
1.redis的过期策略以及内存淘汰机制
过期策略是定期删除+惰性删除。首先第一点为什不用定时删除策略,定时删除用一个定时器来负责监视key,过期则自动删除,虽然内存及时释放,但十 分消耗cpu资源,在大并发请求下cpu要将时间应用在处理请求而不是删除key上
第二点定期删除和惰性删除是如何工作的:定期删除,redis默认每个100ms检查随机检查,是否有过期的key,有则删除,因为是随机的,所以可能有过期的但未删除,这个时候就需要惰性删除,当你获取key时,检查此key是否过期,过期则删除,第三点两者结合后的弊端:当过期没随机到也没请求还是不被删除
第四点解决方案是采用内存淘汰机制
在redis.conf里: 常用的allkeys-lru 内存淘汰机制 当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的
2. 缓存穿透和缓存雪崩(大公司才有)
第一点:缓存穿透(高频率请求缓存中不存在的数据,直接堆到数据库)
1利用互斥锁,如果缓存失效先去获得锁再去请求数据库 2提供利用布隆过滤器判断key是否合法
第二点缓存雪崩 同一时间大面积失效,下一波请求来了---------给失效时间增加随机值,避免集体失效
3.分布式数据库和缓存双写一致的问题
一般防止网络原因的线程安全和查询脏数据的问题:A进行写操作,删除缓存,B查询发现缓存不见了,查询到旧数据写入缓存,A更新数据库。这样永远是脏数据。
解决方案是:先删除缓存再写入数据库然后延时双删,再淘汰缓存,这里防止再淘汰失败,加上重试机制
先淘汰缓存,再写入数据库,休眠一秒(根据写的大致耗时加上几百ms),再淘汰缓存
public void write(String key,Object data){
jedis.delkey(key);
Db.update(data);
Thread.sleep(1000);
jedis.delkey(key);
}
对于主从分离的框架,b查到的是从表的旧数据,那么休眠时间是B更新到A用到的时间加几百ms 这里的删除可以做异步处理的timer,避免影响吞吐量。
这里的重试机制是:启动一个订阅程序去订阅数据库的binlog,mysql工具canal
步骤:1.更新数据库数据 2.数据库将操作信息写入binlog日志当中 3订阅程序提取出所需要的数据以及key
3.另起一段非业务代码,获取该信息 5,尝试删除缓存操作,发现删除失败6.将这些信息发送到信息队列 7,重新从消息队列获取该数据,重试操作
1.cannal的使用:抽取实时数据到任意存储服务
分服务端和消费端
服务端连接至不同的mysql实例,并为每个实例维护一个事件消息队列
客户端可以订阅这些队列中的数据的变更事件,处理并存到数据仓库
使用BinLog和Canal从mysql抽取数据
MySQL Binlog 则是一种实时的数据流,用于主从节点之间的数据复制,我们可以利用它来进行数据抽取
canal会将自己伪装成Mysql的从节点(Slave),并从主节点Master获取BinLog,解析并贮存
分布式锁和解决分布式定时任务和并发争夺key问题
一.前言:
分布式锁一般有三种实现方式:
1. 数据库乐观锁;
2. 基于Redis的分布式锁;
3.基于ZooKeeper的分布式锁。
二.使用redis的优势
–利用redis的自动过期(不会死锁)和分布式锁的特性,key是唯一的,单线程
分布式锁的要求:互斥性:只能一个持有,加锁和解锁必须同一个,不会发生死锁,容错性
三.redis分布式锁的实现
加锁和解锁原理就是
做A这件事需要锁机制,那么商议谁做A这件事就在redis里以A为key设立个值。如果别人想做这件事就去redis里看看有没有这个key如 果没有就去做。分布式定时任务,则要挑选一台来执行,而不是各个服务都去执行
对于分布式定时任务,我们主要做到3点
只在一台机器上执行定时任务,某台宕机后下一次执行能进行故障迁移,定位正在执行的机器
先引入jedis依赖
2.redisconfig配置redis
3.QuartzAop
里面一共有三个方法,其中webtoolUtil是封装的获取geiIpUtil的方法
第一个方法checkLock方法,给锁加上固定的过期时间的方法
第二个方法是checkStatus,拿到key和ip等信息
public boolean checkStatus(String lockKey){
String key =lockKey;
try {
while (true) { // 这个接口必然是并发的,所以加分布式锁
boolean lock = checkLock(key,1); // 一秒的超时时间
if (lock) {
break; // 获取到锁,才能跳出
}
}
String ip="";
try {
ip = WebToolUtils.getLocalIP();
} catch (UnknownHostException e) {
log.error(e.getMessage());
return false;
} catch (SocketException e) {
log.error(e.getMessage());
return false;
}
String ipAndPort = ip+":"+serverPort;
// 获取服务器上的工作ip
String currentIpAndPort = (String)redisTemplate.opsForValue().get(key);
log.info(“缓存服务器上面的key值”+key);
log.info(“缓存器上面的工作ip”+currentIpAndPort);
log.info(“本服务器ip”+ipAndPort);
// 如果为空的时候,设置进去
if(currentIpAndPort == null){
https://RedisUtil.setex(key, ip, 10);
redisTemplate.opsForValue().set(key, ipAndPort, 10, TimeUnit.SECONDS);
return true;
}
// 就是当前机器,则返回true
if(currentIpAndPort.equals(ipAndPort)){
return true;
}else{
log.info(“没有得到执行权”);
return false;
} } catch (Exception e) { log.info("没有得到执行权"); log.error(e.getMessage()); return false; } } @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)") public void around(ProceedingJoinPoint jp) throws Throwable{ if(checkStatus("schedular_root:carControl:"+jp.getSignature().getName())){ //环绕执行,前置获得锁 String ip = WebToolUtils.getLocalIP(); log.info("现在正在执行"+jp.getSignature()+":"+ip); log.info("执行方法名"+jp.getSignature().getName()); jp.proceed(); //让目标方法执行 redisTemplate.delete("lock:schedular_root:carControl:"+jp.getSignature().getName());//方法执行后删除 } }
- 定时任务分布式锁的简单实现-Redis
- SpringCloud定时任务需要用redis实现分布式全局锁的相关操作
- 分布式定时任务解决方案-spring boot整合JMS以及Redis实现
- 2种基于简单定时任务实现分布式定时任务的技术解决方案(zookeeper、redis和内联MQ)
- 基于redis的分布式quartz定时任务
- 使用zookeeper实现分布式集群定时任务组件
- Redis实现分布式锁与任务队列的思路
- 分布式定时任务Elastic-Job框架在SpringBoot工程中的应用实践(二)
- 分布式定时任务框架——python定时任务框架APScheduler扩展
- 当当(Elastic-job)分布式定时任务
- spring boot-分布式定时任务中,异步执行时JMS无法重新投递消息
- Elastic-Job——分布式定时任务框架
- 分布式系统中的定时任务全解(三)
- lesson9:分布式定时任务
- django+celery+redis实现运行定时任务
- Elastic-Job - 分布式定时任务框架
- spring boot-使用redis的Keyspace Notifications实现定时任务队列
- 分布式系统中的定时任务全解(四)--补充
- Elastic-Job - 分布式定时任务框架
- Redis实现分布式锁与任务队列