在设计和构建服务时,弹性和可靠性是非常重要的。虽然,很多云服务已经提供了弹性和可靠性的解决方案,但是如何将他们运用在自己的服务中还需要更多的思考。我现在所在项目中,我们的搜索平台给不同地区用户(包括东京、香港、马来西亚、印度尼西亚)提供信息搜索服务。
起初我们的服务只部署在了AWS新加坡区域,并且只有很少的用户量,在这种情况下这看起来也并没有什么问题,但随着更多的地区集成到搜索平台和用户数量的增多,解决我们的系统中的一些问题变得紧迫:
- 距离AWS新加坡区域远的地区的用户请求延时比较高。
- 如果AWS新加坡区域出现灾难,那么我们的搜索服务也将停止服务,并且数据可能会永久丢失。(也许,你会觉得整个AWS区域出现灾难几乎不太可能,但就在几天前整个AWS北京区域发生故障:据传是由于多处光缆被挖断,历经 11 小时才完全修复。)
为了解决这些问题,我们决定利用AWS全球基础设施将搜索服务部署在多个AWS区域上。
AWS全球基础设施
我们知道,AWS区域是一组AZ(可用区),可用区实质上是AWS的物理数据中心,同一组可用区它们地理位置上彼此靠近,AWS已经在全球范围内部署它们,以使其全球客户群能够利用它们建立低延迟的连接。
例如,位于伦敦的公司A为整个欧洲的客户提供服务,但公司A如果将服务部署在AWS悉尼(澳洲),那么其实是非常不合理的,因为这样欧洲客户请求响应延迟会非常高。而正确的做法是,公司A应该选择最适合他们及客户群的AWS区域,可能是伦敦、法兰克福或者爱尔兰Region。
对于我们的搜索服务来说,我们的客户群分布在东京、香港、马来西亚、印度尼西亚和新加坡,根据AWS现在所支持的区域列表,我们选取了AWS东京和AWS新加坡来部署服务。因此,服务的架构也发生了变化:
我们将搜索服务同时部署在了AWS东京和AWS新加坡,我们期望:
- 用户优先访问延时低的区域的搜索服务。
- 如果其中一个区域的搜索服务挂掉或者不健康时,所有用户请求会自动被路由到另一个区域的搜索服务。
为了实现上述期望,我们就得使用到AWS路由策略。
AWS 路由策略
当我们在AWS Route53上创建记录时,我们可以选择路由策略,该策略决定了AWS Route53如何响应查询。
AWS Route53提供了多种路由策略可供选择:
- Simple 路由策略
- Failover 路由策略
- Geolocation 路由策略
- Geoproximity 路由策略
- Latency 路由策略
- Multivalue answer 路由策略
- Weighted 路由策略
对于我们的搜索服务,我们需要一个路由策略能够同时支持:
- 减少不同区域用户请求网络延时。
- 能够支持区域故障转移。
而Latency路由策略和Failover 路由策略正是我们所需要的路由策略。
AWS Latency 路由策略
如果你的应用程序托管在多个AWS区域中,则可以使用提供最低请求延迟的AWS区域来响应用户请求,以此来提高用户请求的性能。
如图,当使用AWS Latency路由策略后,则可以实现用户优先访问延时低的区域的搜索服务:
- 当用户请求延时到AWS东京低的时候,用户请求会被路由到AWS东京的搜索服务来响应。
- 当用户请求延时到AWS新加坡低的时候,用户请求会被路由到AWS新加坡的搜索服务来响应。
但是,如果AWS区域上的搜索服务挂掉的话,那么又会怎样呢?假设,当用户请求延时到AWS东京低的时候,如果此时AWS东京搜索服务挂掉的话,那么用户请求依然会被路由到AWS东京的搜索服务。看来事情没有那么简单,我们还得需要另一个功能的支持:区域故障转移。
AWS Fail Over 路由策略
AWS Fail Over 是一个主从策略。在主记录健康的情况下,默认采用主记录。否则采用从记录。而判断记录健康则交由AWS Route53 Health Check来管理。
如果,我们将AWS新加坡作为主记录,AWS东京作为从记录。那么我们可以实现区域故障转移:
- 当AWS新加坡的搜索服务挂掉或者不健康时,所有用户请求会被路由到AWS东京的搜索服务来响应。
- 当AWS东京的搜索服务挂掉或者不健康时,所有用户请求会被路由到AWS新加坡的搜索服务来响应。
但是,使用AWS Fail Over路由策略同一时间只有一个AWS区域的搜索服务给用户提供服务,所以AWS Fail Over 路由策略提供的是一种active-passive(单活跃,单备份)故障转移。而我们真正想要的是active-active(双活)故障转移,即多个AWS区域的搜索服务同时在服务。
使用active-active故障转移可以减少资源浪费,并且可以分担服务的负载压力。但遗憾的是AWS 路由策略并没能直接支持。
结合AWS Latency路由策略 和 Fail Over 路由策略
如果我们单独使用AWS Latency路由策略或者AWS Fail Over路由策略,你会发现他们只解决了部分问题,而通常情况下我们是希望能够将他们两个结合起来使用,不幸的是AWS路由策略并不能直接支持两种路由策略的结合,这看起像是鱼和熊掌不可得兼的事情。所幸的是我们可以自己手动实现AWS Latency路由策略和Fail Over 路由策略的结合。
如下图所示,我们将AWS Latency路由策略和Fail Over路由策略两者级联起来使用,首先使用AWS Latency 路由策略,然后使用Fail Over路由策略。
举个栗子,位于马来西亚的用户请求了www.example.com,由于www.example.com使用的是AWS Latency路由策略,所以AWS Route53会计算马来西亚用户到AWS新加坡和到AWS东京的网络延时,我们知道马来西亚和新加坡地理位置靠近,所以通常情况下马来西亚用户到AWS 新加坡的网络延时会更低一些。所以,马来西亚用户请求首先会被路由到www.example.com | SG(新加坡)
。
然后,马来西亚用户请求被路由到一个使用了Fail Over路由策略的记录:test1.example.com
。test1.example.com
有两个记录:主记录和从记录,这里的关键是将AWS新加坡的API作为主记录的资源,而将AWS东京的API作为了从记录的资源。当主记录健康的时候,所有请求都会路由到主记录,即路由到AWS 新加坡的API。而当主记录不健康而从记录健康的时候,所有请求都会发到从记录,即路由到AWS东京的API。
反过来,位于日本的用户请求了www.example.com,那么,日本用户请求很可能首先会被路由到www.example.com | TK(东京)
。然后,日本用户请求被路由到了一个使用了Fail Over路由策略的记录:test2.example.com
。这里的关键是将AWS东京的API作为了主记录的资源,而将AWS新加坡的API作为了从记录的资源。
通过这种方式组合两种AWS路由策略,我们实现了多区域异地双活架构。它同时支持:
- 减少不同区域用户请求网络延时。
- 能够支持区域故障转移。
如何定义你的服务是否健康?
在上面的方案中,你可能会有一个疑问:在Failover路由策略中我们如何定义服务是否健康呢?
AWS Route53 健康检查支持多种方式来实现健康检查:
通过Endpoint响应的状态
这中方式通常是使用HTTP/HTTPS来请求Endpoint(比如:API),然后通过Endpoint 响应的状态来决定健康检查是否健康。通过AWS Cloudwatch Alarm的状态
这种方式则通过你所定义AWS Cloudwatch Alarm的状态来决定健康检查是否健康。这种方式有一个好处,就是不需要暴露一个公开的API来检测服务是否健康。
由于我们的搜索服务的API上加了API Key,所以更加不可能使用第一种方式实现健康检查。
如下图所示,我们通过启动一个定期执行的AWS Lambda(每分钟运行一次)来收集AWS API Gateway和SOLR Cluster的健康信息,然后通过一些逻辑计算得出我们的搜索服务是否健康。比如,如下任意一个条件满足则认为此时搜索服务不健康:
- API Gateway Latency > 5000ms
- API Gateway 5XXErrorr percentage > 10%
- SOLR Cluster CPU average usage rate > 90%
并将结果放到AWS Cloudwatch Metric中,然后通过AWS Cloudwatch Alarm来定义Alarm的状态。比如,如果连续3次检查搜索服务为不健康,则触发Alarm。
然后将AWS Route53 健康检查与我们定义的AWS Cloudwatch Alarm集成。通过这种方式就实现了AWS Failover路由策略的健康检查。
总结
对于面临区域化延迟的服务而言,转向多区域异地双活架构往往是一种自然而然的发展趋势。但是,当纯粹将多区域作为故障转移策略加以采用时,它的合理性就需要进一步讨论了。在某些情况下,你可能会发现多AZ(可用区)方法就可以满足故障转移需求,而不需要承受多区域架构的额外开销。
最终,当转向多区域异地双活架构时,一定要清楚推动你采用区域异地双活架构的原因。审视可用选项时,我们应该权衡这些选择对架构的整体复杂性的影响。