第十一章 - 质量保证、运维及实践

  1. 质量保证体系
  2. 自研分布式存储系统需要两三年才能逐步成熟,其中的难点在于如何把系统做稳定,是否发展通用分布式存储平台取决于公司规模
    1. 员工人数 < 100 选择广泛使用的存储技术,如 MySQL
    2. 员工人数 < 1000 组合使用各种 SQL 和 NoSQL 存储技术,改进开源产品或基于开源产品二次开发,如 MySQL Sharding
    3. 员工人数 > 1000 自研核心存储技术
  3. 系统发展路径
    1. 起步:解决特定文档,满足业务的特殊需求
    2. 求生存:接入合适的应用,建立良好的口碑
    3. 平台化:提升易用性、可运维性
      1. 易用性:采用标准的使用接口兼容之前的使用方式
      2. 可运维性:将系统内部更多状态暴露给运维人员并开发方便的部署、监控、运维工具
    4. 成熟期:持续不断优化
  4. 架构理论学习:在学习过程中主动挖掘架构背后的设计思想和关键实现细节
    1. 阅读 GFS 论文尝试思考的问题
      1. 为什么存储三个副本?而不是两个或者四个?
      2. Chunk的大小为何选择64MB?这个选择主要基于哪些考虑?
      3. GFS主要支持追加(append)、改写(overwrite)操作比较少。为什么这样设计?如何基于一个仅支持追加操作的文件系统构建分布式表格系统Bigtable?
      4. 为什么要将数据流和控制流分开?如果不分开,如何实现追加流程?
      5. GFS有时会出现重复记录或者补零记录(padding),为什么?
      6. 租约(Lease)是什么?在GFS起什么作用?它与心跳(heartbeat)有何区别?
      7. GFS追加操作过程中如果备副本(Secondary)出现故障,如何处理?如果主副本(Primary)出现故障,如何处理?
      8. GFS Master需要存储哪些信息?Master数据结构如何设计?
      9. 假设服务一千万个文件,每个文件1GB,Master中存储的元数据大概占用多少内存?
      10. Master如何实现高可用性?
      11. 负载的影响因素有哪些?如何计算一台机器的负载值?
      12. Master新建chunk时如何选择ChunkServer?如果新机器上线,负载值特别低,如何避免其他ChunkServer同时往这台机器迁移chunk?
      13. 如果某台ChunkServer报废,GFS如何处理?
      14. 如果ChunkServer下线后过一会重新上线,GFS如何处理?
      15. 如何实现分布式文件系统的快照操作?
      16. ChunkServer数据结构如何设计?
      17. 磁盘可能出现“位翻转”错误,ChunkServer如何应对?
      18. ChunkServer重启后可能有一些过期的chunk,Master如何能够发现?
    2. 阅读 Bigtable 论文尝试思考的问题
      1. GFS可能出现重复记录或者补零记录(padding),Bigtable如何处理这种情况使得对外提供强一致性模型?
      2. 为什么Bigtable设计成根表(RootTable)、元数据表(MetaTable)、用户表(UserTable)三级结构,而不是两级或者四级结构?
      3. 读取某一行用户数据,最多需要几次请求?分别是什么?
      4. 如何保证同一个子表不会被多台机器同时服务?
      5. 子表在内存中的数据结构如何设计?
      6. 如何设计SSTable的存储格式?
      7. minor、merging、major这三种compaction有什么区别?
      8. TabletServer的缓存如何实现?
      9. 如果TabletServer出现故障,需要将服务迁移到其他机器,这个过程需要排序操作日志。如何实现?
      10. 如何使得子表迁移过程停服务时间尽量短?
      11. 子表分裂的流程是怎样的?
      12. 子表合并的流程是怎样的?
  5. 架构师的职责
    1. 权衡架构:从多种方案中选择一种与当前团队能力最匹配的方案,难点在于权衡(稳定性、性能、工程复杂度)
    2. 模块划分、接口设计、代码规范指定:在设计阶段就应该考虑清楚
    3. 思考清楚关键实现细节并写入设计文档

      如果架构师都不清楚关键实现细节,那么,团队成员往往更不清楚,最终的结果就是实现的系统带有不确定性

    4. 提前预知团队成员的问题并给与指导
  6. 大规模分布式存储系统的设计准则
    1. 容错:错误一定会发生
    2. 自动化:运维人员操作失误的概率远远高于机器故障的概率;集群规模越大,自动化的优势越明显
    3. 保持兼容:设计之初就应该考虑后续升级问题
  7. 分布式存储系统实现的关键在于可控性,包括代码复杂度、服务器资源、代码质量等
    1. 重试服务器代码资源管理:内存、线程池、socket
    2. 代码代码审查:避免形式主义
    3. 重试测试

      如果一个系统或者一个模块设计时没有想好怎么测试,说明设计方案还没有想清楚

  8. 如何保证系统的可运维性
    1. 吃自己的狗粮:开发人员自己维护系统,总结问题,保证运维相关的需求能够更快的解决
    2. 标准客户端:采用标准客户端,避免频繁升级,如 MySQL Client
    3. 线上版本管理:保证版本兼容,定期升级
    4. 自动化运维:运维动作自动化
  9. 工程现象
    1. 错误必然出现:理论上有问题的设计或实现,实际运行时一定会出现,不管概率有多低
    2. 错误必然复现:测试中发现的问题等到数据规模增大后必然会复现
    3. 两倍数据规模:在压力测试过程中,每次数据量或压力翻倍,都会暴露一些新问题
    4. 怪异现象的背后总有一个愚蠢的初级 bug
    5. 线上问题第一次出现后,第二次将很快重新:永远将线上问题当成第一优先级,尽快找出错误根源并修复
  10. 经验法则
    1. 简单性原则:如果某个方案很复杂,一般是实践者没想清楚
    2. 精力投入原则:开发资源总是有限的,应该把主要精力放在优化整体实践中占比较大或者频繁调用的函数上
      • 如果某个事件出现概率高,应该选择复杂但更完美的方案
      • 如果某个事件出现概率低,应该选择简单但不完美的方案
    3. 先稳定再优化:把一个高效但有Bug的系统做稳定的难度远远高于把一个稳定但效率不高的系统做高效
    4. 想清楚再动手