Redis 的双重哈希(Double Hashing)通常是指在 Redis 集群中使用的一种数据分片和节点定位机制。这种机制主要包含两个哈希步骤:
- 第一层哈希:使用 CRC16 算法对键(key)进行哈希,然后对 Redis 集群的哈希槽(hash slots)数量进行取模,从而将键映射到一个特定的哈希槽。
- 第二层哈希:当需要重新分片或者节点增加/减少时,为了保证数据迁移的最小化,Redis 集群使用虚拟节点(virtual nodes)的概念。每个物理节点可以有多个虚拟节点,每个虚拟节点也是一个哈希槽。这样,键通过第一层哈希确定的哈希槽可能会映射到不同的虚拟节点上,而这些虚拟节点再映射到实际的物理节点上。
双重哈希的优势包括:
- 均匀分布:通过双重哈希,可以更均匀地将数据分布到各个节点,减少某些节点过载而其他节点空闲的情况。
- 容错性:当某个节点失败时,只有映射到该节点的哈希槽需要重新分配,而不是整个键空间,这样可以减少数据迁移的开销。
- 灵活性:在增加或减少节点时,只需要重新分配部分哈希槽,而不是全部,这样可以减少数据迁移的开销,提高系统的灵活性。
此外,Redis 集群使用这种机制可以实现数据的高可用性和可扩展性,同时保持较低的数据迁移成本和较高的数据访问效率。
原子性
Lua 本身并没有提供对于原子性的直接支持,它只是一种脚本语言,通常是嵌入到其他宿主程序中运行,比如 Redis。在 Redis 中执行 Lua 脚本的原子性是指:整个 Lua 脚本在执行期间,不会被其他客户端的命令打断。
这意味着,当 Redis 执行 Lua 脚本时,Redis 会把 Lua 脚本作为一个整体并把它当作一个任务加入到一个队列中,然后单线程按照队列的顺序依次执行这些任务,在执行过程中 Lua 脚本是不会被其他命令或请求打断,因此可以保证每个任务的执行都是原子性的。
例如,假设我们要将某个值加上1,并且只有在这个值小于10的情况下才能执行加1操作,那么可以使用一下 Lua 脚本来实现:
if redis.call('GET', 'value') < 10 thenredis.call('INCR', 'value')
return 1
else
return 0
end
在redis中,整个 Lua 脚本作为一个整体被执行且不被其他事务打断,这就是一个原子性的操作。
此外,Redis 通过 eval、evalsha 等命令来执行 Lua 脚本。但是,Lua 脚本如何保证原子性呢?在 Redis 中,Lua 脚本能够保证原子性的主要原因还是 Redis 采用了单线程执行模型。也就是说,当 Redis 执行 Lua 脚本时,Redis 会把 Lua 脚本作为一个整体并把它当作一个任务加入到一个队列中,然后单线程按照队列的顺序依次执行这些任务,在执行过程中 Lua 脚本是不会被其他命令或请求打断,因此可以保证每个任务的执行都是原子性的。
总结来说,在 Redis 中,Lua 脚本的原子性是由 Redis 的单线程执行模型保证的,这使得 Lua 脚本在执行期间不会被其他客户端的命令打断,从而确保了操作的原子性。
redis管道:就是相当于队列,开启一个管道传入多条redis命令可以实现串行化执行。
redis的事务是弱事务,可以通过使用lua增强事务
虚拟节点机制通过引入额外的虚拟节点来提高数据分布的均匀性。在一致性哈希算法中,每个节点(或服务器)和每个键(或数据)都被映射到一个哈希环上。数据通常被存储在环上顺时针方向遇到的第一个节点上。如果没有虚拟节点,当节点数量较少时,数据可能会非常不均匀地分布在节点上,导致某些节点过载而其他节点空闲。
通过引入虚拟节点,可以使得数据在节点间分布得更加均匀。每个物理节点可以有多个虚拟节点,这些虚拟节点在哈希环上均匀分布。当定位数据时,首先根据键的哈希值找到对应的虚拟节点,然后根据虚拟节点映射到实际的物理节点上。
这样做的好处包括:
- 提高系统的稳定性:即使在节点增减的情况下,也可以保证数据分布的相对稳定。
- 减少对系统的冲击:在节点变化时,只有部分数据需要迁移,从而减少了对系统的冲击。
- 数据均匀分布:通过虚拟节点,可以使得数据在节点间分布得更加均匀。