尝试为键值存储中的键定义一些策略(我们使用的是 Redis)。键空间应该是:
可分片(可以引入更多服务器并分散它们之间的 key 空间)
命名空间(应该有某种机制将键逻辑地“组合”在一起,例如按域或相关概念)
高效(尝试在数据库中为键使用尽可能少的空间,以允许尽可能多的数据)
尽可能避免碰撞(避免两个不同对象的键相等)
我考虑过的两种选择是:
为命名空间使用前缀,由一些字符分隔(如
human_resources:person:<some_id>
)。这样做的好处是它非常可扩展且易于理解。缺点是可能会发生冲突,具体取决于分隔符(如果id
中包含字符:
怎么办?),以及可能的大小效率(过多的嵌套命名空间可能会创建很长的键)。使用一些数据结构(如 Ordered Set 或 Hash)来存储命名空间。这样做的主要缺点是失去“可分片性”,因为存储命名空间的结构需要在单个数据库中。
问题:在分片设置中管理 key 空间的好方法是什么?我们应该使用这些替代方案中的一种,还是有其他一些我们没有考虑过的更好的模式?
非常感谢!
最佳答案
Redis 世界中普遍接受的约定是选项 1 - 即命名空间由冒号等字符分隔。也就是说, namespace 几乎总是一层深。例如:person:12321
而不是 human_resources:person:12321
。
这如何与您设置的 4 条准则一起工作?
可分片 - 这种方法是可分片的。每个键可以进入不同的分片或相同的分片,具体取决于您的设置方式。
Namespaced 命名空间作为一种避免冲突的方法适用于这种方法。然而,命名空间作为一种对键进行分组的方式并不奏效。通常,使用键作为对数据进行分组的方法不是一个好主意。例如,如果这个人从一个部门调到另一个部门怎么办?如果更改 key ,则必须更新所有引用 - 这会变得很棘手。
最好确保对象的键永远不会改变。然后可以通过创建单独的索引在外部处理分组。
例如,假设您要按部门、薪资范围、地点对人员进行分组。这是您的操作方式 -
- 个人使用键
persons:12321
进入单独的散列
- 为每个组创建一个
set
- 例如:persons_by:department
- 并且只存储该组中每个人的数字标识符。例如 [12321, 43432]。这样,您就可以利用 Redis 的 Integer Set 的优势
高效 上面解释的方法在内存方面非常高效。为了节省更多内存,您可以在应用程序端进一步压缩 key 。例如,您可以存储 p:12321
而不是 persons:12321
。仅当您通过分析确定您需要这样的内存节省时,才应该这样做。一般来说,它不值得花费。
无碰撞 这取决于您的应用。每个用户或个人都应该有一个永不改变的主键。在您的 Redis key 中使用它,您就不会发生冲突。
你提到了这个方法的两个问题,我会尝试解决它们
如果id有冒号怎么办?
这当然是可能的,但您的应用程序的设计应该阻止它。最好不要在标识符中使用特殊字符——因为它们将在多个系统中使用。例如,标识符很可能是 URL 的一部分,即使对于 url,冒号也是保留字符。
如果您真的必须在您的标识符中允许特殊字符,您将不得不在您的代码中编写一个小的包装器来对特殊字符进行编码。 URL 编码完全能够处理这个问题。
大小效率
长 key 会产生成本,但不会太多。通常,您应该担心值的数据大小而不是键。如果您认为 key 消耗过多内存,请使用像 redis-rdb-tools 这样的工具来分析数据库。
如果您确实确定 key 大小是一个问题并且想要节省内存,您可以编写一个小的包装器来使用别名重写 key 。
关于database - 在键值存储中管理键的好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19279628/