微服务实战之扩展性

任何微服务的容量都是有限的, 但是理想情况下一般的微服务应该只局限于服务器的数量(计算能力), 存储的容量和网络的带宽.

当用户的请求和用量增加时, 只要财务预算上没有问题, 理论上是可以接近无限地扩展的.

实际上, 这个假定往往并不成立, 更大的数据量, 更多的请求, 更高的并发量, 你的服务会撑不住.

你会想到加内存, 加存储, 加带宽, 加服务器, 然而事情没那么容易, 你的应用的服务能力必须能够随着资源的增加而线性增加

由于单机的内存, CPU 及带宽毕竟有限, 所以尽量把你的服务设计成由多个相对独立的, 无状态的自治节点组成, 这样你可以轻松地增加节点来应对不断增长的服务请求

术语

  • Scale up: 向上扩展或垂直扩展
  • Scale out: 向外扩展或水平扩展
  • Failover: 快速切换从 primary 节点或分区切换到 slave 节点或分区, 以减小对用户的影响
  • Stateless: 无状态的, 服务器节点本身不存储状态, 好处在于可以随时增加和减少节点, 有利于水平扩展
  • Stateful: 有状态的, 状态总是存在的, 就看你把它放在哪里, 服务器内存, 数据库, 或共享的缓存服务器
  • Sharding: 根据数据的分布特点以及用途, 将数据集分布在多个数据库上来存储, 以避免单机处理能力及存储限制

要点

服务分离 Separation of services

从自给自足的小农社会到现代化的社会化大分工, 单个人掌握的技能变少了, 不同的人有不同的分工和专长, 社会的生产效率大幅度提高了

微服务就是要把服务做小,做精, 专注于一个相对独立的领域, 以利于分散风险, 和重用组合, 也有利于服务的扩展, 哪块是瓶颈, 就优化和扩展哪一块,而不是所有服务器都要一起升级.

例如我要做一个网络会议服务器,需要支持文字聊天,音频视频对话,桌面共享,文件分享,远程控制,会议录制等等,既有控制信令的处理,又有媒体的传输,编码解码和混音处理,如果都放在一起,可想而知,系统的复杂性大大增加不说,调优和扩展很难做,音视频的编码解码是极其耗费CPU 资源,允许丢包,而控制及文字聊天则不同,必须保证消息可靠传达,所以还是各自分开为不同的服务为好

无状态 Stateless

状态总是存在的, 关键看你把它放在哪里, 内存里, 文件里, 数据表里, 还是缓存里?
假如我们把状态放在单个服务器的内存或文件系统中, 扩展起来就会非常麻烦, 高可靠性也有问题.

状态需要在不同的服务器之间同步, 才能做到避免单点失败, 每个服务器保持一致显然不可能应对海量请求和数据.

  • 单台独有状态
  • 多台同步状态
  • 外置共享状态

只有第三种,你的服务器才可以随意增加,线性扩展

数据分片 Data sharding

根据地理位置, 用户组织或数据中心及服务区集群都可以进行数据分片, 假设你有多个客户, 这些客户分布在不同的地域, 不同的客户服务请求和数据大小也不同, 如何进行数据分片呢?

假设你提供的服务是在线教育平台, 域名是天天向上 www.day-day-up.com, 客户是各个大大小小的补习班,以及一些在线的教育机构。

你可以根据为不同的客户(租户tenant )进行数据分片

  • 东方补习学校 https://east-school.day-day-up.com, 这个学校比较大, 有两个大校区:
    • 大中华区
    • 东南亚区
  • 西方补习学校 https://west-school.day-day-up.com, 这个学校比较小, 只有一个主校区

于是, 我们有如下配置数据表, 放在一个中央数据库中, 并缓存在 Redis 中

  • Tenant 表
tenant_id tenant_name expire_date
d423b7f7-aa2f-40ee-afe7-6b4e5a245ff3 东方补习学校 2018-12-31
c5ae1066-522b-4cf3-aba7-923f72f7f07d 西方补习学校 2018-12-31
  • Org 表
org_id org_name tenant_id
b30bae13-75ca-4b3c-8998-2d46ba6f74ff 大中华区 d423b7f7-aa2f-40ee-afe7-6b4e5a245ff3
c3cd2f82-dde6-481d-b441-d7e4e50e3eb6 东南亚区 d423b7f7-aa2f-40ee-afe7-6b4e5a245ff3
b18dde72-de20-4952-b33c-73da44ebe95a 主校区 c5ae1066-522b-4cf3-aba7-923f72f7f07d
  • Sharding 表
tenant_id org_id database_pool_id
d423b7f7-aa2f-40ee-afe7-6b4e5a245ff3 b30bae13-75ca-4b3c-8998-2d46ba6f74ff ajpc_a1
d423b7f7-aa2f-40ee-afe7-6b4e5a245ff3 c3cd2f82-dde6-481d-b441-d7e4e50e3eb6 us_a1
d423b7f7-aa2f-40ee-afe7-6b4e5a245ff3 b30bae13-75ca-4b3c-8998-2d46ba6f74ff ajpc_b1
  • DbPool 表
db_pool_id primary_db_pool backup_db_pool
ajpc_a1 mysql://username:password@hosta1/mysqldb_name mysql://username:password@hosta2/mysqldb_name
ajpc_b1 mysql://username:password@hostb1/mysqldb_name mysql://username:password@hostb2/mysqldb_name
us_a1 mysql://username:password@hosta1_us/mysqldb_name mysql://username:password@hosta1_us/mysqldb_name

小贴士 -- 快速生成 UUID
python -c 'import uuid; print uuid.uuid4();'

如何自动扩展和收缩

基本要求:

  • 高峰期增加服务器,快速提供服务
  • 低谷期减少服务器,提高资源效率
  • 而增减服务器由监控和分析程序来触发

下面这个传统结构显然不够

微服务实战之扩展性_第1张图片

根据Monitor 和 Metrics 系统所得出的结果决定, 实时增加服务器, 注册到类似 Consul 的服务发现系统中, 利用它的服务发现和健康检查功能, 用 consul-template 来刷新更改 HAProxy, Nginx 这样的软件负载均衡系统的配置文件并重载 ( F5 , NetScalar 这样的硬件负载同理), 减少服务器也是一样的过程.

如图所示

微服务实战之扩展性_第2张图片

当然, 你的服务器最好是无状态的, 否则就很麻烦, 增加服务器时可能要做状态同步, 关闭服务器时要先将服务器设为 suspend 状态, 不再接受新的服务, 等到所有服务在这台服务器已经结束了, 才能关机

参考资料

  • Cloud Architecture Patterns for Mere Mortals by Bill Wilder
  • Web Scalability for startup engineers
  • https://cloud.google.com/solutions/autoscaled-load-balancing-using-haproxy-and-consul-on-compute-engine

你可能感兴趣的:(微服务实战之扩展性)