# gmall-0108 **Repository Path**: code_workspace/gmall-0108 ## Basic Information - **Project Name**: gmall-0108 - **Description**: 谷粒商城 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-06-21 - **Last Updated**: 2021-07-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 谷粒商城 缓存: 目的: 场景: 选型: 如何实现缓存: RedisTemplate回顾: 1.xml 可读性一般 占用较多内存 性能较低 2.json 可读性较强 内存占用稍多xml 3.string 手动序列化 内存占用较少 性能较高 4.jdk 没有可读性 内存占用较多 性能最高 有一个子类:StringRedisTemplate 缓存高并发常见问题: 缓存穿透: 缓存雪崩: 缓存击穿: 分布式锁: 借助于当前学习过的技术或者使用分布式锁框架: 1.基于关系型数据库实现 2.基于redis实现分布式锁 3.基于zk实现分布式锁 性能:redis> zk > 关系型数据库 难易:zk> 关系型数据库 > redis 可靠性: zk> redis == 关系型数据库 基于redis实现分布式锁: 加锁:setnx 释放锁: 重试: 特点: 1.独占排他: setnx 2.防止死锁 一个redis客户端获取到锁之后,客户端服务器宕机: 解决办法: 给锁设置过期时间: 推荐使用 set key value ex 3 nx 不可重入 3.原子性: 加锁和过期时间:set key value ex 3 nx 4.防误删: redis本身就支持lua脚本: 分支控制: if(判断) then ... else if(判断) then ... else ... end evel "if(KEYS[1]>ARGV[1]) then return KEYS[1] else return KEYS[1] end" 1 20 30 一、分布式锁 基于redis 性能最高 基于关系型数据库 基于zk 可靠性最高 -**-特点: 1.独占排他: setnx set key value ex 3 nx 2.防死锁: 客户端获取锁之后,服务器宕机了:给锁设置过期时间 expire set key value ex 3 nx 不可重入: 可重入即可 3.原子性: 加锁:加锁和设置过期时间 set key value ex 3 nx 解锁:判断和解锁直接的 lua脚本 4.解铃还需系铃人: 判断是否自己的锁 lua脚本 5.可重入:hash + lua 脚本 6.自动续期:定时器 + lua 脚本 7.集群情况下,如果一个客户端从主中获取到锁,从还没有来的及同步数据,主就挂掉了,然后升级为主,另一个客户端又会从新主中获取到锁 相当于锁失效,可以使用RedLock算法解决。 实现分布式锁的步骤: 1.加锁: setnx set key value ex 3 nx hash + lua 脚本 lua脚本 + 定时器Timer 实现自动续期 2.解锁: del:可能导致误删 判断是否是自己的锁L: lua脚本 lua 脚本: if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end 可重入锁的情况下:lua脚本实现释放锁 3.重试: 如果当前线程没有获取到锁,就要重试(递归调用) 可重入:ReentrantLock 加锁: 1.判断lock锁是否存在(exists lock),如果返回false 说明锁不存在,则直接获取锁即可(hset lock uuid 1) 2.如果返回true,则说明锁已经存在。再去判断是否是自己的锁(hexists lock uuid) 如果返回true(1),说明是自己的锁,则可以重入(hincrby lock uuid 1)并设置过期时间 3.否则返回 0,说明获取锁失败 if(redis.call('exists',KEYS[1])==0 or redis.call('hexists',KEYS[1],ARGV[1]) == 1) then redis.call('hincrby',KEYS[1],ARGV[1],1) redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end 解锁: 1.判断锁是否存在,以及是否是自己的锁(hexists lock uuid),返回0 直接返回nil 2.如果存在自己的锁,则出来一次(hincrby lock uuid -1),出来一次之后判断返回值是否为0,如果为0,则释放锁(del)