-
Notifications
You must be signed in to change notification settings - Fork 65
htree:结构,冲突处理,内存和速度优化
Yang Xiufeng edited this page Apr 18, 2019
·
3 revisions
- htree
- 每个跟bucket 一个
- 是一个16 叉完全树,数组分配,高度在配置中指定。
- 每个叶子 对应一个 “list”
- key hash 8 bytes, 高位到地位分三部分:
- 第一部分 定位在那个 bucket。
- 第二部分 定位在 bucket.htree 的哪个叶子
- 第三部分 在叶子对应节点中定位 key 对应的 item
伪代码
def get(key):
pos = collisions.get(key) or htree.get(hash(key))
rec = data.get(pos)
if rec.key != key:
pos = get_pos_slow(key)
rec = data.get(pos)
return pos
思路
- 结构
- 内存 htree 记录 hash(key): pos
- 外存 dtree 记录 key:pos
- 比如放在 leveldb 中: (<hash, key>: pos), 就可以把相同 hash 的可以聚到一起。
- 要求打配合:比如 fast write, 没有太多内存开销等
- pos 对应 record = (key, value)
- 算法
- 读 htree 的得到 pos 对应 record 的中 key 是错的。 fallback 到 dtree 中找即可。
- 找到冲突后就记在内存中(当然同时也持久化)
- 只要概率足够低,不影响整体性能
- 此外
- htree 天然方便存 hash,并且自己隐含了一部分 hash, 能减少 list 存储 的部分 hash 的长度。
用 hint 实现 get_pos_slow 的原因
- 透明,方便管理(迁移,备份)
- 可以对应一个 data,方便快速查看等
- 性能可控,主要是写和 gc;读慢点,发生概率低,可以接受
- 不算复杂
- 大内存使用对go 内存管理压力比较大,可能出现 gc 时间长,碎片多, 为了减少其影响 , 每个叶子节点 对应的 list 用一整块内存分配,并且用 c 分配。
- 因为 cgo 慢, douban 场景下读多写少, 在增减新key时重写分配 list 时用 cgo, 读和更新用go 数据结构映射过去,没有cgo开销。