今天准备给大家讲讲我在工作中遇到的困难以及经过各种实践到认知再实践最终实现目标的过程之一: 我是如何思考动静分离架构并最终实现的
先来说说需求, 我之前所在的团队的商业方向是做电商平台saas,类似于有赞和微盟, 电商saas顾名思义, 它是电商+saas,意思就是普通的电商那一套不够,还得加上saas:)
现在不是要双十一了么? 他们都想搞私域的双十一直播,平时的那点流量一下子蹿了十几倍甚至几十倍, 怎么应对? 啊! 动静分离! 团队的研发小伙伴们和问过的朋友以及CEO特意请的顾问都这么说. ok! 那就搞动静分离. 但是具体咋搞? 没人给我好的方案, 因为具体情况具体分析, 动静分离每家每个程序员每个架构师都有自己的想法, 在电商saas的场景下,商品详情, 店铺装修, 商品列表 都是高频请求, 都要实现动静分离, 而且复杂的一点是, 作为saas平台,每个商家的页面和分佣和细节需求都会不一样,这给静态化和动态化增加了困难.
经过一周的头秃思考和实践认知再实践再认知的迭代过程, 我还是最终把动静分离方案实现了出来, 下面我就详细说说我的方法.
首先说下为啥要实现动静分离, 咱们都清楚啊, 首先关系型数据库是有连接数限制的, 如果只是读, 增加只读实例就可以以低成本的方式增加连接数, 但是如果涉及写, 就需要对数据库进行升级. 简单来说, 对于用户的请求, 每次都从数据库获取数据如果连接数够用并且没有额外的sql执行开销其实并没有什么问题, 问题就在于大量数据的io响应依然会阻碍并发数的提升, 并且会导致系统中的其它业务受影响. 所以解决方案就是nosql, 对常见的用户请求,并不会到达数据库这一级.
先拿商品详情页面来举例子吧, 商品详情页面是商品的展示页面, 在视频号直播时访问的频率最高, 肯定首先要实现商品详情的动静分离, 咱们来先区分下哪些归为静态, 哪些归为动态.
静态内容:
与当前访问者无关的内容为静态内容, 如:
- 商品基本信息
- 优惠券列表信息
- 评价信息
- 商品所属的商家信息
- 商家最新的商品列表
动态内容:
与当前访问者有关的内容为动态内容, 如:
- 已领取的优惠券
- 针对访问者单独显示的优惠券
- 访问者能够拿到的商品的自购返奖金等
出于篇幅问题, 本文只说静态部分, 也就是与访问者无关的页面信息, 咱们来个小目标, 假定有100万用户通过抖音或视频号同时抢购某个限量商品A, 商品A假定库存只有5万件, 可以理解为100万个用户不停的在刷相同的页面, 可以理解为理想情况下要达到100万qps.
如果采用增加数据库读节点的方案,咱们来分析下情况:
1. 要求用户的请求2秒内返回.
2. 每个请求的执行时间理想情况下是200-300毫秒
3. 考虑到sqlalchemy对协程的支持仍处于早期阶段, 对于数据库的请求采用多线程模式
基于以上情况, 因为可以2秒内返回, 所以咱们可以假定下每秒只需要达到50万qps就可以了,再看每次请求需要200-300毫秒, 因为在fastapi线程模式下或者flask或者django来说, 每个请求一个线程, 可以理解为每个线程每秒能执行3个请求. 也就是说需要50/3=16.6万个线程. 按照python线程的实际情况, 一般线程数是核数的2-4倍, 假定就是纯io情况, 这里咱们取2倍, 在GIL的情况下, 2倍和4倍其实没什么变化, 实际我测试下来2倍反而更好一些, 每个进程就是cpu_count() *2个线程, 进程数一般也是cpu数的2倍, 按照阿里云的ecs最高配置256核1024G内存的配置, 256*2*(256*2)=262144, 可以理解为需要2台顶级配置的ecs服务器就能够支撑商品详情的请求, 但是考虑到客户端的并发请求情况,咱们豪爽的来4台, 每台阿里云的顶级配置的ecs每小时的费用是56.32元, 4台就是228元, 假定活动前后执行4个小时,可以理解为1000元的成本.
按照每个线程一个连接的映射理论, 就需要17万的数据库连接池连接数. 阿里云按量付费的postgresql数据库最高配置是64