【问题标题】:What is a good way to manage keys in a key-value store?在键值存储中管理键的好方法是什么?
【发布时间】:2013-10-17 06:15:11
【问题描述】:

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

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

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

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

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


我考虑过的两种选择是:

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

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

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

非常感谢!

【问题讨论】:

    标签: database namespaces redis key key-value-store


    【解决方案1】:

    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 之类的工具分析数据库。

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

    【讨论】:

    • 很好的答案。非常感谢您花时间解决这个问题。很抱歉之前没有为您点击“赏金”按钮,但这是我第一次使用它。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 2010-10-10
    相关资源
    最近更新 更多