redis如何解决key冲突?

1、业务隔离

不同的业务使用不同的redis集群,或者协议使用redis的不同db。

为每个业务分配独立的Redis数据库:可以通过Redis的多数据库功能,为每个业务分配独立的数据库,避免不同业务的Key之间的冲突。

例如:

将所有用户相关的操作放在一个数据库中,将所有订单相关的操作放在另一个数据库中。

这种方式可以在代码中通过指定不同的数据库编号来实现。

2、良好的Redis Key的设计

格式:业务标识:系统名称:模块名称:关键词简写

比如:保险:用户管理:用户申请:手机号

Redis Key:bx:um:reg:mobile

为每个业务分配独立的Key前缀:可以为每个业务分配一个独立的Key前缀。

例如:

将所有用户相关的Key以”user:”为前缀

将所有订单相关的Key以”order:”为前缀

这种方式可以通过在代码中定义一个全局的Key前缀变量来实现。

3、使用Redis的Hash类型

可以使用Redis的Hash类型来存储复杂的业务数据结构。

将业务数据组织为一个Hash,使用一个Key来表示整个业务数据,Hash的Field表示具体的业务字段。这种方式可以通过定义一个复杂的Hash结构来解决Key冲突的问题。

4、使用Redis的Lua脚本

可以使用Redis的Lua脚本来解决复杂的业务逻辑,Lua脚本可以通过一系列的Redis命令来实现。可以将复杂的业务逻辑封装为一个Lua脚本,并为每个业务分配一个独立的脚本,通过调用不同的Lua脚本来执行不同的业务操作。这种方式可以避免在代码中直接使用Redis命令,提高代码的可读性和可维护性。

例如:

使用 Redis 的 Lua 脚本可以更加高效地处理业务逻辑,同时避免了多个命令之间的竞争条件。在实现 Redis 的业务隔离时,可以使用 Redis 的 Lua 脚本进行实现。下面是一个使用 Redis 的 Lua 脚本来实现业务隔离的例子:

假设我们有两个业务:A 和 B,每个业务都有一组 key-value 数据。我们希望这两个业务之间的数据是隔离的,即 A 业务只能访问自己的 key-value 数据,B 业务也只能访问自己的 key-value 数据。

我们可以通过在 Lua 脚本中设置一个命名空间来实现业务隔离,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 设置业务 A 的命名空间
local namespaceA = "namespace:A:"
-- 设置业务 B 的命名空间
local namespaceB = "namespace:B:"

-- 获取业务 A 的值
local valueA = redis.call('GET', namespaceA .. KEYS[1])
-- 获取业务 B 的值
local valueB = redis.call('GET', namespaceB .. KEYS[1])

-- 如果是业务 A,返回业务 A 的值,否则返回业务 B 的值
if ARGV[1] == 'A' then
return valueA
else
return valueB
end

通过在 key 的前面添加命名空间来实现业务隔离。在实际的使用中,可以根据实际情况来设置不同的命名空间,以达到业务隔离的目的。

Java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class RedisLuaScript {

private RedisTemplate<String, Object> redisTemplate;

/**
* 执行Redis Lua脚本
*
* @param script Lua脚本内容
* @param keys Redis Key列表
* @param args Lua脚本参数列表
* @param returnType 返回值类型
* @return 执行结果
*/
public <T> T executeLuaScript(String script, List<String> keys, List<Object> args, Class<T> returnType) {
DefaultRedisScript<T> redisScript = new DefaultRedisScript<>();
redisScript.setResultType(returnType);
redisScript.setScriptText(script);
return redisTemplate.execute(redisScript, keys, args.toArray());
}

/**
* 通过业务隔离获取指定key的值
*
* @param namespace 业务隔离的命名空间
* @param key Redis Key
* @param returnType 返回值类型
* @return 对应Key的值
*/
public <T> T getValueWithNamespace(String namespace, String key, Class<T> returnType) {
String script = "local valueA = redis.call('GET', ARGV[1] .. KEYS[1])\n" +
"if (valueA ~= nil) then\n" +
" return valueA\n" +
"end\n" +
"local valueB = redis.call('GET', ARGV[2] .. KEYS[1])\n" +
"return valueB";
List<String> keys = Collections.singletonList(key);
List<Object> args = Arrays.asList(namespace + ":", "");
return executeLuaScript(script, keys, args, returnType);
}
}


redis如何解决key冲突?
https://leellun.github.io/2023/05/07/面试题/2023-05-07-redis如何解决key冲突?/
作者
leellun
发布于
2023年5月7日
许可协议