分布式协议与算法实战——Quorum NWR算法(笔记)

在最终一致性系统中某个模块需要强一致性,为避免重新开发一套系统,可以使用Quorum NWR协议 解决这个问题。也就是说,在原有系统上开发实现一个新功能,就可以满足业务同学的需求了。因为通过Quorum NWR,你可以自定义一致性级别,通过临时调整写入或者查询的方式,当 W +R > N 时,就可以实现强一致性了。

Quorum NWR 的三要素

N 表示副本数,又叫做复制因子(Replication Factor):表示集群中同一份数据有多少个副本。副本数可以不等于节点数,不同的数据可以有不同的副本数。在实现 Quorum NWR 的时候,需要实现自定义副本的功能。也就是说,用户可以自定义指定数据的副本数。
W,又称写一致性级别(Write Consistency Level):表示成功完成 W 个副本更新,才完成写操作。
R,又称读一致性级别(Read Consistency Level):表示读取一个数据对象时需要读 R个副本。即,读取指定数据时,要读 R 副本,然后返回 R 个副本中最新的那份数据。

W + R > N 的时候,对于客户端来讲,整个系统能保证强一致性,一定能返回更新后的那份数据。
W + R < N 的时候,对于客户端来讲,整个系统只能保证最终一致性,可能会返回旧数据。

实现 Quorum NWR

InfluxDB 企业版,支持“any、one、quorum、all”4 种写一致性级别:

  • any:任何一个节点写入成功后,或者接收节点已将数据写入 Hinted-handoff 缓存(也就是写其他节点失败后,本地节点上缓存写失败数据的队列)后,就会返回成功给客户端;
  • one:任何一个节点写入成功后,立即返回成功给客户端,不包括成功写入到 Hinted-handoff 缓存;
  • quorum:当大多数节点写入成功后,就会返回成功给客户端。此选项仅在副本数大于 2时才有意义,否则等效于 all;
  • all:仅在所有节点都写入成功后,返回成功。

注:对时序数据库而言,读操作常会拉取大量数据查询性能是挑战,是必须要考虑优化的,因此,在 InfluxDB 企业版中,不支持读一致性级别,只支持写一致性级别。另外,我们可以通过设置写一致性级别为 all,来实现强一致性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redlock 算法是一种用于分布式锁的算法,它由 Redis 的作者 Salvatore Sanfilippo 在 2015 年提出。下面是一个基于 Redlock 算法实现的分布式锁的 Java 代码示例: ```java import redis.clients.jedis.Jedis; import java.util.UUID; public class Redlock { private final Jedis[] jedisInstances; private final int quorum; private final int validityTime; private final String lockKey; private String lockValue; public Redlock(String[] jedisHosts, int quorum, int validityTime, String lockKey) { this.jedisInstances = new Jedis[jedisHosts.length]; for (int i = 0; i < jedisHosts.length; i++) { jedisInstances[i] = new Jedis(jedisHosts[i]); } this.quorum = quorum; this.validityTime = validityTime; this.lockKey = lockKey; } public boolean acquire() { String uuid = UUID.randomUUID().toString(); int acquired = 0; long startTime = System.currentTimeMillis(); while ((System.currentTimeMillis() - startTime) < validityTime && acquired < quorum) { for (Jedis jedis : jedisInstances) { String result = jedis.set(lockKey, uuid, "NX", "PX", validityTime); if ("OK".equals(result)) { acquired++; } } if (acquired >= quorum) { lockValue = uuid; return true; } else { release(); } try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } return false; } public boolean release() { boolean success = true; for (Jedis jedis : jedisInstances) { String result = jedis.eval("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", 1, lockKey, lockValue).toString(); if (!"1".equals(result)) { success = false; } } return success; } } ``` 上面的代码中,`Redlock` 类封装了 Redis 实例数组、投票阈值、锁有效期、锁的键值等属性。`acquire()` 方法用于获取锁,它通过在 Redis 中使用 `SET key value NX PX milliseconds` 命令来获取锁,其中 `NX` 表示只在键不存在时才设置值,`PX` 表示设置键的过期时间为 `milliseconds` 毫秒。为了确保获取锁的可靠性,`acquire()` 方法通过多次尝试获取锁,直至获得足够数量的 Redis 实例的投票,即 `acquired >= quorum` 时返回 `true`。如果在有效期内未能获得足够数量的投票,则 `acquire()` 方法返回 `false`。 `release()` 方法用于释放锁,它通过 Lua 脚本在 Redis 中执行一个原子操作,将只删除锁的值为指定 UUID 的键。如果释放成功,则返回 `true`,否则返回 `false`。 使用示例: ```java Redlock redlock = new Redlock(new String[]{"localhost:6379", "localhost:6380", "localhost:6381"}, 3, 1000, "my_lock"); if (redlock.acquire()) { try { // do something } finally { redlock.release(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值