客户容灾案例--利用CDN备份源站实现COS双写双读

2021-10-18 16:55:56 浏览数 (1)

腾讯云对象存储 COS 为客户提供了99.95%的可用性和99.999999999%的可靠性。由此可见,数据可靠性是极高的,即使在极端故障场景下,也可以保证客户的数据不丢失。但实际线上系统更常遇见的是,因为网络拥塞、程序异常等原因,而导致的COS服务不可用,如对象读写失败,API调用异常等。当这些故障发生时,如果没有合适的冗余措施,即使存量数据不丢失,也会造成一段时间线上服务有损,影响用户使用体验。本文会结合一些客户的实际案例介绍一种COS服务的高可用方案。

基于存储桶复制的高可用方案

该方案的详细实现可参考腾讯云官网文档:https://cloud.tencent.com/document/product/436/37709。其架构示意图可见下图:

该方案的核心是基于存储桶的异地复制,来实现数据的全备份。但是作为主备切换的高可用层,需要用户业务侧自己实现。腾讯云侧也给出了其中一个解决方案,通过腾讯云云云函数SCF,来实现主备存储桶的定时拨测和邮件告警,在主存储桶宕机不可用的时候,有业务侧程序实现切换读写存储桶。这个方案的优点在于除了可以使用腾讯云COS产品实现容灾冗余,还可以接入自有源站或其他云厂商作为冗余。此外,还可以依赖监控和拨测的能力,做到故障的早发现、早切换,实现故障自愈的效果,把对线上的影响降到最低。但是,由于高可用层需要集成网络检测和业务调度等功能,对于业务侧来讲改造成本较大,实现起来并不容易。

利用CDN备份源站实现COS双写双读

如何用较小的改造代价实现一定程度的存储桶读写冗余呢?如果在读写时直接操作两个存储桶,只要有一个桶的读写操作成功了,在故障场景下也可以保证服务可用。具体来讲,写场景下:并行或者顺序的对两个异地的桶发起写操作,检查写状态,如果两个桶都写入成功了,便返回成功;如果只写成功了其中一个桶,或其中一个桶写入超时,也返回成功,并发送写入失败告警;如果两个桶都写入失败了,返回失败,进入异常处理程序。读场景下:客户端优先读取主桶,当主桶返回4XX/5XX返回码,或者请求超时后,再访问备桶获取资源。访问示意图可以参考下图。

写请求

其中,写请求需用户配置存储桶A和存储桶B的地址,用两个存储桶分别完成两次对象上传操作,可参考如下C 伪码:

代码语言:javascript复制
// 新建两个独立现成的任务
TaskList task_list;
TaskFunction<mt_cos::MtCosPutFunc, const std::string&, const std::string&, const mt_cos::CosConfig&, std::string*> cos_task(mt_cos::put_object, cos_path_, audio_, ConfigFileCommon::GetInstance()->cos_config_, &error_msg);
TaskFunction<mt_cos::MtCosPutFunc, const std::string&, const std::string&, const mt_cos::CosConfig&, std::string*> cos_task2(mt_cos::put_object, cos_path_, audio_, ConfigFileCommon::GetInstance()->cos_config2_, &error_msg);

// 每个线程处理一个存储桶的上传
task_list.push_back(&cos_task);
task_list.push_back(&cos_task2);
exec_all_task(task_list);

// 若两个存储桶都写成功,则返回成功
bool ret = true;
for (int i = 0; i < task_list.size();   i)
{
    if (!(ret = task_list[i]->GetResult()))
    {
        break;
    }
}
if (!ret)
{
    SetResultCode(RESULT_CODE_SERVICE_ERR_SYSTEM_WRITE_FILE);
    MsgError("mt_cos::put_object failed:", error_msg);
    break;
}            

上面代码的逻辑为先新建两个独立的子线程任务,每个线程分别传入主存储桶和备份存储桶的配置参数,然后并行地调用COS restful接口进行对象上传操作。然后分别检查两个子线程的状态返回码,如果两个子线程均返回成功,则这个对象写入成功。此处可以根据用户需求加入其他逻辑,如其中一个对象上传失败时,调用告警接口发送告警等。直接写两个桶的优点在于,简化了第一个方案中高可用层的复杂逻辑,在程序测直接存储了两份,以应付容灾需求。

读请求

和方案一相比,用户读请求仍然使用CDN进行加速。不同的是,这里可以引入腾讯云CDN的热备源站能力,来实现备份源站的热备份。热备源站的功能是,正常情况下,用户读取对象只会优先请求主存储桶,只有当主存储桶返回4XX/5XX返回码,或者主存储桶请求超时时(超时时间可配置),CDN后台会自动回源到备存储桶获取改对象。由于该重试逻辑是CDN后台的逻辑,对用户透明,所以用户客户端只需访问一个固定地址即可,无需配置多个地址,便免去二楼客户端自己处理重试和切换逻辑。备份源站的配置方法如下:

1、进入CDN控制台域名管理页面(https://console.cloud.tencent.com/cdn/domains),点击添加域名。请确保你的域名已经存在切完成备案,配置可参考下图,配置说明如下:

加速域名:用户自定义,已备案的域名

加速类型:静态加速

源站类型:自有源(不要选择COS源,否则会和后面需要配置的热备源站产生配置冲突)

源站地址:主COS存储桶的访问域名,可在对应存储桶的概览页面查看到

回源host:同COS源站地址

2、域名新建成功后,进入刚刚新建的域名详情界面,点击【添加热备源站】按钮,添加自有源站,在会员地址一栏配置备份存储桶的访问域名,配置可参考下图:

3、其他配置,建议在【回源配置】中打开301/302跟随,并配置回源超时时间均为5s。

CDN热备源站注意事项

CDN热备源站的逻辑是在主源站访问失败的情况下有兜底处理逻辑,但是无法根据主存储桶的健康状态切换成被存储桶。也就是说,即使主存储桶完全不可用的情况下,新的请求仍然会先访问主存储桶,然后再向备存储桶发起重试。此时,主存储桶在两种不同场景下会存在差别:

场景1. 主存储桶中不存在资源,或服务端错误(返回码4XX/5XX):此时CDN后台会立即访问备存储桶发起重试,若重试成功,则将对应的对象返回给客户端。重试行为会多消耗一个访问备用桶的RTT时延。

场景2. 主存储桶宕机,或主存储桶所在可用区网络故障,导致访问主存储桶超时:此时必须在TCP连接超时时间(缺省值为5s,控制台可配置,最短为5s)过期后,才会向备存储桶发起重试,重试行为会多消耗5s 备存储桶RTT的时延。

常见业务场景中,如果客户端和存储桶同region部署,访问备存储桶的RTT一般在5ms内,业务完全可以接受。但是在场景2中,每次访问对象会存在至少5s的延时,部分业务场景下就会存在问题。在场景2的实际测试中,客户端基本可以在6s以内获取资源,后续访问相同资源,会触发CDN缓存直接返回,而无需回源。所以,利用CDN热备源站进程读请求容灾,具备一定的局限性,如果客户端属于会对同一个资源发起多次访问的场景,适合采用本方法。如果客户端是对不同对象仅访问一次,或访问频率很高,在主存储桶故障故障发生时,可能不能起到较好的容灾效果。

此外还需要注意,客户端的TCP超时时间设置,一定要大于5s,否则还没有来得及触发CDN后台的超时重试,请求便会被客户端直接Rst,从而导致请求失败。

两种容灾方案的对比

根据上文的说明,我们总结了两种容灾方案的对比供参考,业务侧可根据实际情况做适配选择。

基于CDN热备源站

基于存储桶复制

费用成本

由于外网上行流量免费,故不产生额外费用

收取内网跨地域复制流量费用

业务侧改造

改造量较小,周期短,仅需在客户端加入双写逻辑

改造量大,周期长,需要用户侧自己开发高可用切换相关逻辑

容灾效果

无法自动切换,部分场景下业务有损

可以自动切换,自动回切,适配行更强,需客户侧开发

0 人点赞