任何微服务的容量都是有限的, 但是理想情况下一般的微服务应该只局限于服务器的数量(计算能力), 存储的容量和网络的带宽.
当用户的请求和用量增加时, 只要财务预算上没有问题, 理论上是可以接近无限地扩展的.
实际上, 这个假定往往并不成立, 更大的数据量, 更多的请求, 更高的并发量, 你的服务会撑不住.
你会想到加内存, 加存储, 加带宽, 加服务器, 然而事情没那么容易, 你的应用的服务能力必须能够随着资源的增加而线性增加
由于单机的内存, 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();'
如何自动扩展和收缩
基本要求:
- 高峰期增加服务器,快速提供服务
- 低谷期减少服务器,提高资源效率
- 而增减服务器由监控和分析程序来触发
下面这个传统结构显然不够
根据Monitor 和 Metrics 系统所得出的结果决定, 实时增加服务器, 注册到类似 Consul 的服务发现系统中, 利用它的服务发现和健康检查功能, 用 consul-template 来刷新更改 HAProxy, Nginx 这样的软件负载均衡系统的配置文件并重载 ( F5 , NetScalar 这样的硬件负载同理), 减少服务器也是一样的过程.
如图所示
当然, 你的服务器最好是无状态的, 否则就很麻烦, 增加服务器时可能要做状态同步, 关闭服务器时要先将服务器设为 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
网友评论