这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天
今天我学习了字节跳动掘金内部课程里面的存储与数据库。我学到了很多redis的用法。其中redis因为是基于内存的,所以非常快,而且redis是可以夸服务,如果是分布式环境下或者服务搭建集群的环境下都可以访问redis的。
这样我就想到,能不能拿redis来当分布式锁
全局唯一ID
订单如果用自增长会存在的问题:
ID的规律性太明显了 受单表数量限制,因为如果商城很大订单表数量可能很多,要分库分表,到时候id自增从1开始的话肯定会出现重复的。订单表为了后边方便查询肯定不能重复
全局ID生成器 全局id生成器,是一种分布式系统下用来生成全局唯一ID的工具,满足下列
特征:
- 唯一性
- 高可用
- 高性能(生成足够快)
- 递增性(整体递增,方便创建索引)
- 安全性(规律性不能太明显)
Redis肯定唯一的,性能也高,Redis也是采用递增方案的 生成器代码(Redis自增ID策略): 在最后做拼接的时候,我们不能直接拼接,因为是long类型来接收所以我们得用位运算,前面的左移动32位然后或运算后面的 key的设置是每天一个key,方便订单统计也防止可能会重复
分布式锁概述
在集群模式下,synchronize根本锁不住。因为每个都是不同tomcat,不同jvm的存在,每个jvm的每个锁都可以有一个线程来获取,就会出现并行安全问题。
要想解决这种问题,必须得想办法让多个jvm只能用同一个锁。分布式锁
但是如果使用这种分布式锁,在写代码的时候,我们一定要注意下面这几个问题。
处理不好的话,可能会导致系统出现各种bug,会出现超卖或者漏卖的情况,下面我举个例子,就是一人仅仅能秒杀一单的需求。在解决这种业务的时候可能会出现:
误删问题
当线程1正确获取redis锁执行业务,业务某种原因阻塞,超过时间就会超时释放,一旦1提前释放,2能获取成功,当2正在拿锁做业务时,1突然醒了然后执行完毕释放锁,这个时候1就把2的锁给释放掉了,3或者其他线程就能够进来。
解决方案
这种情况产生主要是因为线程1把线程2的锁给释放了导致,我们可以在释放锁之前加上判断是否是自己的锁,我们可以把redis存入的value来当这个线程的标识,删除的时候取出来判断一下
原子性问题
**这种情况:**当线程1获取锁执行业务,完成业务释放锁判断标识一致可以释放,这个时候判断完成堵塞了(可能是jvm垃圾回收会阻塞所有的代码),就没有释放成功,如果足够长,就触发了超时释放锁。一旦超时释放,其他线程2就能获取锁然后执行业务,这个时候线程1恢复了,但是他已经判断完标识了,这个时候直接又把2的锁给释放了,然后线程3又能进来执行
使用Lua脚本解决原子性问题
Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性
lua脚本是用Lua是一种编程语言,我们只要会用基础的操作就可以了