background

linkedin 的 blob storage 实现, 已经开源了, 还是java写的. 以前是基于 nas + oracle 搭建的media server落地的, 但是大量的小文件导致巨量的metadata, 内存和cpu都面临 无法水平扩展的窘境. 新的设计, 相比于已有的 facebook hystack/f4 或者 twitter, 更加注重 rebalance 特性 和 geo地理复制.

design

abstraction

partition 是一组blob的逻辑抽象, 倾向于称呼 logic partition, 映射到 一组机器的副本 (会考虑到故障域隔离): physical placement. 在 physical placement 上, blob 不断追加到 data 文件, 除此之外, 还需要维护 indexing、journal、bloom filter 的额外数据结构, 每个data 文件 100GB, 写到 80%-90% 的容量空间的时候, partition 会从 read-write state 转换为 read-only state (需要额外的空间负责delete).

架构

  • cluster manager: 负责集群管理: physical/hardware layout(node & disk placement, up/down state)、partition state/logic layout(read-write/read-only, mapping: partition(state)->placement info(dc+datanode+disk))

  • frontier: 负责 安全检查、路由&转发请求, 以及 operation capture 同步给外部 cdc

  • dataNode: 写数据, 配备多份disk

IO 路径

  • put: 每个 blob 经由 frontier 顺序写入 partition, http 调用 或者 cdn. blob 如何选择合适的 partition 呢? 大对象, 比如 video 会被拆分成多个chunk, 避免大对象影响 小对象的读写吞吐. 每个chunk差不多 4MB-8MB, large object->chunkid slice 会维护在 metadata. 获取 large object 的时候, 通过 sliding buffer 限制避免 IO spike 影响其他的服务.

  • delete 也是put操作. 会周期性的通过 compaction 回收delete的空间. 空间满了之后 文件会变成 read-only, 回收可能变成 read-write.

  • 一致性 read-after-write put 操作随机选择一个partition执行操作. 支持一致性选项: (one, k, majourity, all). 对于 put/delete, 会同步到所有 但是可以选择 ack的一致性选项, get 随机选择一致性的数量的节点. 目前 2 是 延迟&一致性的折中 multi-dc: local dc sync, other dc async

数据文件的设计: 每个写入的blob entry格式: header+blob id + delete flag, blob id = partition id(8 byte) + uuid(32 byte), 可能冲突, datanode 通过failure解决. header: predefined properties(blob size+ttl+create time+content type) + user-defined properties

batch write 降低disk seek, 并将维护不多的 file handle keep open, 利用 os cache + zero copy 降低复杂度并提升性能.

索引文件的设计: 为了充分释放内存给 文件读写, 索引采用了 sst file 的lsm设计, 将index 分段 segment, 当memory segment 超过最大大小 就 flush to disk. old segment 存储在磁盘上. 并维护相应的 bloom filter. index file crash了, 直接从 data rebuild

可用性

传统的三副本机制, 多dc容灾, 通过跨dc异步复制降低延迟. 没有(但是打算)使用 纠删码 来降低副本因子

sync

out-of-sync 的同步算法两阶段实现:

  • 找到 last sync point 丢失的blob, 就是请求 last sync point 之后所有的 blob id 然后本地过滤出丢失的 
  • 执行复制

本地维护了 journal 数据结构, 维护最近的 写入的 blob

failure detection:

基于熔断算法, 论文称之为 zero-cost

feature

除了传统的 static balance(largre split + cdn), 还设计了 动态负载均衡, 负载不均衡的特点: 新加入节点可能 100x 老节点. ambry 设计了 balance triplet: (idealRW, idealRO, idealUsed), 会计算一个均线 划分 high/below. 针对 high, 设计了两阶段算法:

  • 将 above-idea 的partition 迁移到了 partition pool, 保证没有disk above idea. 这里需要处理下 read-write 和 read-only partition 的不同策略. read-write 选择最小空间占用的 partition, read-only 随机选择一个 (因为都满了)
  • 将partition 从 pool 迁移到 below-idea 的disks (random round-robin)

参考