10

尝试为键值存储中的键定义一些策略(我们使用的是 Redis)。键空间应该是:

  • 可分片(可以引入更多服务器并分散它们之间的密钥空间)

  • 命名空间(应该有某种机制将键在逻辑上“组合”在一起,例如按域或相关概念)

  • 高效(尽量在 DB 中为键使用尽可能少的空间,以允许尽可能多的数据)

  • 尽可能少的碰撞(避免两个不同对象的键相等)


我考虑过的两种选择是:

  1. 为命名空间使用前缀,由一些字符(如human_resources:person:<some_id>)分隔。这样做的好处是它具有很好的可扩展性且易于理解。不利的一面是可能的冲突,具体取决于分隔符(如果id其中有字符:怎么办?),以及可能的大小效率(太多嵌套的命名空间可能会创建很长的键)。

  2. 使用一些数据结构(如 Ordered Set 或 Hash)来存储命名空间。这样做的主要缺点是失去“可分片性”,因为存储命名空间的结构需要在单个数据库中。

问题:在分片设置中管理键空间的好方法是什么?我们应该使用这些替代方案中的一个,还是有一些我们没有考虑过的更好的模式?

非常感谢!

4

1 回答 1

12

Redis 世界中普遍接受的约定是选项 1 - 即命名空间由冒号等字符分隔。也就是说,命名空间几乎总是一层深。例如:person:12321而不是human_resources:person:12321

这如何与您设置的 4 条准则一起工作?

可分片- 这种方法是可分片的。每个键都可以进入不同的分片或同一个分片,具体取决于您的设置方式。

命名空间命名空间作为一种避免冲突的方法适用于这种方法。然而,命名空间作为一种组合键的方式并没有奏效。一般来说,使用键作为分组数据的一种方式是个坏主意。例如,如果这个人从一个部门调到另一个部门怎么办?如果您更改密钥,您将不得不更新所有引用 - 这会变得很棘手。

最好确保对象的密钥永远不会更改。然后可以通过创建单独的索引在外部处理分组。

例如,假设您想按部门、工资范围、位置对人员进行分组。这是你的做法 -

  1. 个人使用密钥进入单独的哈希persons:12321
  2. 为每个组创建一个set- 例如:persons_by:department- 并且仅存储此集合中每个人的数字标识符。例如 [12321, 43432]。这样,你就得到了 Redis 的 Integer Set 的优势

高效上面解释的方法在内存方面非常有效。为了节省更多内存,您可以在应用程序端进一步压缩密钥。例如,您可以存储p:12321而不是persons:12321. 只有当您通过分析确定您需要这样的内存节省时,您才应该这样做。一般来说,这不值得付出代价。

无碰撞这取决于您的应用程序。每个用户或个人都应该有一个永远不会改变的主键。在你的 Redis 键中使用它,你不会有冲突。

您提到了这种方法的两个问题,我将尝试解决它们

如果 id 有冒号怎么办?

这当然是可能的,但是您的应用程序的设计应该阻止它。最好不要在标识符中使用特殊字符——因为它们将在多个系统中使用。例如,标识符很可能是 URL 的一部分,冒号是保留字符,即使是 url。

如果您确实必须在标识符中允许特殊字符,则必须在代码中编写一个小包装器来编码特殊字符。URL 编码完全有能力处理这个问题。

尺寸效率

长键是有成本的,但不是太多。通常,您应该担心值的数据大小而不是键。如果您认为键占用过多内存,请使用 redis-rdb-tools 之类的工具对数据库进行分析。

如果您确实确定密钥大小是一个问题并且想要节省内存,您可以编写一个小型包装器,使用别名重写密钥。

于 2013-11-05T08:24:13.910 回答