缓存笔记 来自 程序员囧辉
黑马博学谷 幂等问题
黑马-一次说透,4大服务性幂等场景架构设计方案!
唯一性索引与逻辑删除冲突问题解决思路
‘逻辑删除‘和‘唯一索引‘冲突的解决方案
MyBatisPlus解决逻辑删除与唯一索引的兼容问题
缓存问题 是囧辉写的
如何保障缓存和数据库的一致性(超详细案例)
1 缓存一致问题
1.1.同步删除
核心流程:
- 更新数据库数据
- 删除缓存数据
问题:
- . 并发场景下存在脏数据 (
并发有脏数据问题
) - . 难以收拢所有更新数据库入口 (
可能通过命令行、工具等删除db,那么redis 无法删除
) - . 删除缓存失败存在脏数据 (
更新数据库后,存在网络问题,删除redis 失败。
)
脏数据问题。
1.2. 延时双删
核心流程:
- 删除缓存数据
- 更新数据库数据
- 等待一小段时间
- 再次删除缓存数据
问题:
- 延时时间难以确认 (
延时时间无法确认
) - 延时无法绝对保障数据的一致性 (
主从情况下
) 高并发写的情况写,主从同步可能是分钟级别的,但是延时双删第二个延时不可能是分钟级别,会导致在分钟级别时间内存在脏数据。
例子:更新了主库,但是查询的是从库,存在数据不一致。
1.3:异步监听从库binlog删除 + 重试
核心流程:
- 更新数据库
- 监听binlog删除缓存
- 缓存删除失败则通过MQ不断重试,直至删除成功
存在问题:
- 缓存 脏数据时间窗口“较大” (
针对于同步删除来说的
)- 更新完 db,产生binlog ,binlog发到从库,mq消费 删除缓存 都需要时间
- 在上面期间,缓存没删除,
那也是有脏数据。
- 极端场景下存在长期脏数据问题
- binlog抓取组件宕机(canal 宕机)
- 拆库拆表流程
1.3.1 推荐监听从库
这是一个权衡吧,你直接监听主库也是可以的,但是为什么我们不这么干了。
因为主从延迟通常情况下是很低的,基本在毫秒级別,几乎可以忽略不计。而监听主库会有什么问题了,如果我们的binlog中间件在功能迭代期间出现了bug,直接将主库搞挂或者影响到主库,那可能就直接影响到整个链路了,而如果影响的是从库,即使挂了可能也几乎没影响,因为我们一般会有预留容量,挂1台从库理论不会影响业务。
所以没有必要为了几毫秒的延迟去冒这个风险。
1.4. 最终保证
- 更新数据库后 同步删除缓存。(
减少异步删除不一致 时间窗口 太久的情况
) 为了应对同步删除的并发问题
。引入监听binlog,异步删除。带有重试,一定要成功。- 缓存数据带过期时间。过期后删除。
- 主要用于进一步防止并发下的脏数据问题
- 解决一些由于未知情况(缓存设计不合理,换数据结构),导致需要更换缓存结构的问题
- 监听数据库的binlog延迟N秒后进行数据一致性校验
- 解决一些极端场景下的脏数据问题
- 存在数据库更新的链路禁用对应缓存
比如更新完数据库后,马上又查询一次
可能查询走缓存 的数据还是脏数据。- 就是在更新请求链路中的查询请求都直接查db
- 防止并发下短期内的脏数据影响到更新流程
- 强制读Redis主节点
- 查询异步数据一致性校验、灰度放量
2.jvm 调优
- Serial GC:Full GC整个过程STW,Young GC整个过程STW
- Parallel GC:Full GC整个过程STW,Young GC整个过程STW
- CMS GC:Full GC整个过程STW,Young GC整个过程STW,Old GC只有两个小阶段STW
- G1 GC:Full GC整个过程STW,Young GC整个过程STW,Mixed GC由全局并发标记和对象复制组成,全局并发标记其中两个小阶段STW,其它并发
- Shenandoah GC/ZGC:它们都是回收堆的一部分,所以没有Full GC(Full GC是指回收整个堆,与之相对的是Partial GC,比如CMS GC的Old GC和G1的Mixed GC均属于此类)的概念
2.1 分区比例不合适问题
eden 比较小,导致:YGC次数变多。
eden 比较大,导致:扫描增多,YGC时间增加。
YGC STW的。影响接口请求时间。
survivor 偏小,导致:有些对象动态年龄规则,提前。直接晋升到老年代。
survior 偏大。导致浪费一些空间。
元空间full gc
2.2 gc
软引用
当gc后,空间还是不够用,将软引用作为gcroot,在进行一次gc。GC cause last dist collection。
cms 内存碎片,标记清除。
碎片化严重,影响大对象分配,没有连续的空间
2.3 cms 内存碎片导致full gc
3. 分库分表问题
切片策略 -范围切分
写流量集中再单表问题。
hash 切分
4.linux 常见命令
netstat -tunlp
查看端口占用情况
-t (tcp) 仅显示tcp相关选项
-u (udp)仅显示udp相关选项
-n 拒绝显示别名,能显示数字的全部转化为数字
-l 仅列出在Listen(监听)的服务状态
-p 显示建立相关链接的程序名
# netstat -tunlp | grep 8000
tcp 0 0 0.0.0.0:8000 (local adress)
0.0.0.0:* (foreign address)
LISTEN(state) 26993/nodejs (pid/program name)
netstat -ntlp //查看当前所有tcp端口
netstat -ntulp | grep 80 //查看所有80端口使用情况
netstat -ntulp | grep 3306 //查看所有3306端口使用情况
netstat -nat
查看 进程连接 或者关闭状态
过滤 第6列
netstat -nat |awk ‘{print $6}’| sort |uniq -c
打印第六列 排序 去重
702 个正在连接
8个监听
lsof -i
lsof -i:端口号
lsof -i:8000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nodejs 26993 root 10u IPv4 37999514 0t0 TCP *:8000 (LISTEN)
top
第一行
第三行
free -h