正经一点的云端 Web 架构
GCP vs AWS 的负载均衡器选型,加一个典型 Web 应用的部署示例。
~/posts/aws-web-architecture $ cat post.md
架构的目标
只给五个人用的软件其实谈不上架构——AWS 可,ThinkPad 可,树莓派也可。但既然要谈云端 Web 应用,目标就指向负载能力和可用性。
地理
一台机器跑的服务谈不上架构。多台机器后,机器所在的地理位置就要考虑了。用户和服务之间需要负载均衡器把请求散到不同实例上。
任何一家云厂商都有”可用区”的概念。简单场景下,挑你软件主要服务的那个区就行。AWS 没有提供真正全局的负载均衡器——Route 53 也是要选可用区的。这不是说 AWS 没法服务全球,但 ELB 在跨可用区的 IP 来源是动态、不可控的。
GCP 有全局负载均衡器,能让一个 IP 服务全球(Global forwarding rules)。要做全球性的软件,GCP 这块更省事。
选型对比
GCP
直接说结论:GCP 在负载均衡这块功能比较全。当前提供三种 LB:
HTTP/HTTPSProxy:支持 TCP 和 SSLNetwork:支持 TCP 和 UDP;不支持全球可用区
对外暴露用 HTTP 或 Proxy,内部服务之间用 Network。
除全局可用区外,GCP 的几个加分项:
HTTP/HTTPS负载均衡器支持 WebSocket。- 分配算法更细——AWS 的
Auto Scaling Group和 ELB 之间通信较弱,基本是平均分配;GCP 可以基于 CPU 占用之类的信号动态分配。 HTTP负载均衡器可以按 URL 把流量路由到不同实例(甚至不同可用区)。
Proxy 和 HTTP/HTTPS 都能转 HTTP?
是的。两个都能作为 HTTP 入口。区别是 Proxy 转发的是请求的克隆,HTTP/HTTPS 转发的是请求本身——前者会丢失用户的连接信息。
AWS ELB
首先,所有 ELB 都不支持跨可用区——这是前提。面向全球的服务不应该(不是不能)用 ELB。其它短板还包括分配算法、跨域配置等。
这不是个对已有项目容易换的决策,且 GCP 这些服务也上线得比 ELB 晚很多——这里只是指出确实存在的差距,不是说 ELB 不好用。
物理布局
负载均衡的前提是无状态服务——每个请求落到哪台机器我们都不在乎。即便如此,ELB 对开启 Keep-Alive 的 HTTP 请求会尽量复用同一条 TCP 连接,复用时每次新请求只走两次握手而非三次。
下面看一个具体例子。
示例:典型 Web 应用
假设有这样一个应用:
- 前端用 React + webpack 打成
bundle.js、index.html、style.css,配合 Express 做服务端渲染分发(暂不考虑同构)。 - 后端用 Spring Boot 写 RESTful API。所有 API 无状态,数据来自一台 Redis 和一台 MongoDB。
- 一个 Scala 写的 ETL 服务每天跑几次,把数据装进 MongoDB,把未同步的数据带出。
部署上:
- 前端和后端都对外暴露接口,挂在同一个域名下的不同子域名上。各自指向自己的负载均衡器。
- 每个负载均衡器后面挂一个 Auto Scaling Group:压力大时自动扩容;实例崩了就重启。
- 同子网内,后端用内网 IP 直连 Redis / MongoDB。
- ETL 服务也跑在这个子网里,不对外暴露任何接口或 IP。