关于缓存中间件r2m迁移jimdb

最近公司的kv数据库中间件由r2m切换至jimdb,特此记录

diff:

  1. jimdb采用哨兵模式探活;r2m由实例互相探测。
  2. jimdb采取nio;r2m基于jedis使用连接池(可能有连接风暴现象)

jimdb

  1. jimdb提供了节点抖动和故障检测、摘除功能
  2. jimdb支持入出流量控制
  3. 支持热key自动发现(封装的缓存对象中有该属性)
  4. 支持读写分离;支持轮询、随机负载均衡策略;支持客户端分组,每个分组使用不同策略

r2m

  1. 支持的指令更多
  2. 基于开源组件jedis

缓存迁移

  1. 缓存不重要,直接切换读与写。
  2. 不停写r2m,r2m不断同步数据到jimdb,切量读jimdb,完全读jimdb,校验数据一致性,读写jimdb。
  3. 停写,r2m迁移数据,读写jimdb。
  4. 双写,r2m同时进行迁移。

简要分析

方案一:看着就不太靠谱
方案二:

  • 可能读到历史数据
  • 在写流量切换的时候可能出现缓存不一致
    r2m: t1 -> k = v1
    jimdb: t2 -> k = v2
    r2m->jimdb k=v1(最终)

    r2m: t1 -> k 过期
    jimdb: t2 -> k 更新过期状态
    r2m->jimdb k 过期

方案三:

  • 需要容忍长时间停写,中途还要校验数据一致性

方案四: goodgood

设计

  1. 对缓存所有的操作均应封装在一个公共类ext中,对于项目里所有不规范的写法做统一收口
  2. 写一个通用公共类,其中同时支持对jimdb与r2m的读写,策略由ducc来配置
  3. r2m在我们的系统存在两个集群,其为并列关系,此次排查这两个集群是否存在同一个key(查无),然后合并为一个集群。该集群分主从,下面称为jimdb主与jimdb从。
  4. 写策略同时支持:
    • 读、写r2m
    • 读、写jimdb主
    • 读、写jimdb从
    • 同时写r2m、jimdb主
    • 同时写jimdb主、jimdb从
      写两个集群时根据读策略异步写入另一个集群
  5. 读策略同时支持
    • 读r2m
    • 读jimdb主
    • 读jimdb从

代码实现

  1. 对于缓存原始方法,封装公共的cacheHandler,根据策略不同做语义转换(两个中间件的方法名有很多不一致)。此时公共类的参数具有
    • r2m实例
    • jimdb实例
    • 读写策略
    • 线程池(用于异步操作)
      初始化在客户端中进行
  2. 对于缓存的pipline方法则有所不同。若还是采取上述方法,spring使用同一个公共类实例则会产生线程安全问题。(a线程调用init方法, b线程close)。因此每次调用pipline时都需要new一个实例,其中excutor可共用。其实本质还是要模仿之前的写法。
  3. 既然读写时异步的,那close与sync也要是异步的。那么异步操作如何保证sync与close方法总是在最后执行呢?
    • 最开始我打算使用countDownLatch实现,每次调用方法(例如setex)时-1,线程池中阻塞直到计数器为0。但这样需要手动传入一共需要执行的方法数量,客户端也得改。若出现方法出现在if中的情况:if(flag){setex;}则无法判断一共有几个操作
    • 因此采用Phaser组件,每次调用方法时(同步)注册,调用完通知消费完毕。在线程池中调sync与close前,阻塞(异步)等待
感谢您的收看~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇