得物CDN域名收斂及多廠商容災優化實踐

2022.12.14

得物CDN域名收斂及多廠商容災優化實踐


通過CDN域名收斂我們不僅收穫了CDN網絡性能、穩定性上的提升,而且實現了多個域名的統一和規範,大大降低了後續CDN域名的優化和維護複雜度。另外,也支持了CDN主域名的容災能力,保證了線上服務的穩定性。

​背景

CDN域名太多造成請求碎片化,導致以下幾個問題:

TCP建連頻繁,網絡請求性能差

用於請求CDN靜態資源的網絡連接池資源有限,由於不同域名會各自創建TCP連接,進而競爭TCP連接池資源,導致TCP連接頻繁中斷。再次發起網絡請求需要重新進行TCP建連增加了建連階段耗時(包括:DNS解析、TCP握手、TLS握手),導致總耗時升高。

域名太多,日常維護成本高

域名太多導致域名管理、性能監控、性能優化、線上變更複雜度增加,人力成本及運維成本高。

如:得物IPv6升級項目、TLS1.3協議升級項目都需要按域名分批執行多次線上變更流程(包括:測試回歸,變更申請,變更評審,變更驗證,性能監控)。

部分域名命名不規範,存在下線風險

由於歷史原因,存在多個不符合現有新域名規範的域名名稱(如:xxx.poizon.com,xxx.dewu.com)。非得物主體的域名,存在被強制下線的風險,比如舊域名下線項目,投入了大量人力成本進行改造。

DNS解析IP頻繁,阿里雲HttpDNS服務成本高

域名太多增加了每個域名在TCP建連時調用阿里雲HttpDNS解析對應IP的頻次,解析次數升高導致HttpDNS服務成本高。

為了解決CDN域名太多導致的問題,我們決定在客戶端側進行CDN域名收斂優化。

2、CDN域名收斂

2.1 收斂思路

我們先思考一個問題:怎樣實現在不影響業務的前提下,客戶端側將多個CDN域名收斂為統一域名?

主要需要考慮以下幾個點:

  • 服務端側無需做任何改造,依然按現有方式下發多個CDN域名的URL。
  • 客戶端側實現在不侵入業務代碼的情況下完成CDN域名收斂邏輯,對業務上層無感知。
  • 客戶端實現在最終發出網絡請求時,請求URL的域名已替換為統一域名。
  • CDN服務端接收到統一域名的URL請求後可以正常回源,返回所請求的靜態資源。

先看下CDN域名收斂前客戶端通過CDN服務請求靜態資源的示例圖:

圖片

一次靜態資源URL請求到源站的過程可以大體分為三段:

  • 客戶端側:業務上層-> 客戶端網絡庫;
  • 公網:客戶端網絡庫-> CDN服務;
  • CDN服務側:CDN服務-> 阿里OSS源站;

上圖紅框中第2段公網:客戶端網絡庫-> CDN服務這段為多條一對一關係,要實現多個CDN域名收斂為統一域名,主要就是將這段改造為單條一對一關係。因此,只要將第1段改造為多對一,第3段改造為一對多即可。簡單來說就是客戶端側如何收斂域名,CDN服務側如何分發回源站。

2.2 客戶端側收斂域名

在客戶端側網絡庫初始化時提前插入網絡請求攔截器,用於攔截網絡請求後在底層做統一處理,將各域名替換為統一域名。避免侵入業務層代碼,實現業務上層無感知情況下底層完成域名統一收斂。

以得物Android端為例,網絡庫使用的是OkHttp3,OkHttp3支持添加自定義攔截器,我們可以為所有的OkHttpClient對象添加用於CDN域名收斂的攔截器。通過ASpectJ插樁方式實現插入攔截器,既不侵入業務代碼,也可以保證後續新創建的OkHttpClient對像都自動插入攔截器。

// ASpectJ插桩@Aspectpublic class OkHttpAspect {
    /**    * 在okhttp3.OkHttpClient.Builder.new(..)方法后插桩,    * 可以保证OkHttpClient使用new方法或buidler方法创建都被覆盖    */    @After("execution(okhttp3.OkHttpClient.Builder.new(..))")    public void addInterceptor(JoinPoint joinPoint) {        OkHttpClient.Builder target = (OkHttpClient.Builder) joinPoint.getTarget();        addMergeHostInterceptor(target);    }
    /**     * 添加CDN域名收敛拦截器MergeHostInterceptor     */    private void addMergeHostInterceptor(OkHttpClient.Builder builder){        // 避免重复添加,判断当前是否已经添加了拦截器,如果已添加则返回        for (Interceptor interceptor : builder.interceptors()) {            if (interceptor instanceof MergeHostInterceptor) {                return;            }        }        builder.addInterceptor(new MergeHostInterceptor());    }}
  • 1.
  • 2.
  • 3.

當客戶端側業務上層發起靜態資源URL網絡請求時,網絡庫攔截器攔截該請求,並執行CDN域名收斂邏輯。將各域名替換為統一域名,並通過插入代表各域名的path前綴(與各域名一一映射)攜帶原域名信息。

原域名與Path前綴的一一映射表

原域名

Path前綴

image.xxx.com

/image

product.xxx.com

/product

community.xxx.com

/community

image.xxx.com域名的原URL進行請求被攔截後生成新URL的示例

先替換image.xxx.com域名為統一域名cdn.xxx.com,再插入path前綴/image生成新URL。 

原URL與新URL對比如下: 

https://image.xxx.com/xxx.jpg替換為https://cdn.xxx.com/image/xxx.jpg

具體實現代碼如下:

/** * 收敛域名逻辑,进行域名与path映射 * * @param urlStr 原url * @param sourceHost 原域名 * @param targetHost 统一域名 * @param pathPrefix 原域名映射的path前缀 * @return 拼接好的新url */public static String replaceMergeHostUrl(String urlStr, String sourceHost,                                     String targetHost, String pathPrefix)
    if (!TextUtils.isEmpty(urlStr)) {        //替换域名        urlStr = urlStr.replaceFirst(sourceHost, targetHost);
        if (!TextUtils.isEmpty(pathPrefix)) {            //插入path前缀            StringBuilder urlStrBuilder = new StringBuilder(urlStr);            int offset = urlStr.indexOf(targetHost) + targetHost.length();            urlStrBuilder.insert(offset, pathPrefix);            urlStr = urlStrBuilder.toString();        }    }
    return urlStr;}
  • 1.
  • 2.
  • 3.
  • 4.

網絡庫使用新URL請求CDN服務,如果CDN服務節點不存在新URL的資源緩存或緩存已過期,則觸發CDN服務側分發源站邏輯。

2.3 CDN服務側分發源站

  • CDN服務側分發源站方案選型

方案1:CDN邊緣腳本重定向

CDN邊緣腳本阿里雲官方文檔:https://help.aliyun.com/document_detail/126588.html

編寫CDN邊緣腳本並部署在CDN服務節點上,支持將請求通過重定向的方式還原轉發到源OSS。

方案2:阿里雲OSS鏡像回源

鏡像回源阿里雲官方文檔:https://help.aliyun.com/document_detail/409627.html

對統一OSS配置鏡像回源規則,當統一OSS不存在靜態資源時發生404錯誤,觸發鏡像回源到源OSS。從源站成功拉取資源後在統一OSS存儲一份副本,下次訪問時統一OSS便直接返回存儲的資源副本,不再觸發鏡像回源。

鏡像回源原理示意圖(來源於阿里雲官方文檔)

圖片

兩種方案各有優劣,具體對比如下表:

回源方案

優點

不足

CDN邊緣腳本重定向

CDN服務側實現,無需依賴阿里雲OSS鏡像回源

邊緣腳本開發和維護成本較大

執行重定向邏輯對性能有一定影響

邊緣腳本迭代上線的穩定性風險較大



阿里雲OSS鏡像回源

僅需進行鏡像回源配置,無開發成本

鏡像回源可以將多個OSS資源遷移到統一OSS,對OSS進行了收斂

鏡像回源僅全網首次,後續請求直接返回資源副本,性能影響忽略不計



依賴阿里雲OSS鏡像回源能力

從改造成本及性能影響兩方面考慮,最終選擇“阿里雲OSS鏡像回源”作為CDN服務側分發源站方案。

  • 阿里雲OSS鏡像回源具體實現

在統一OSS鏡像回源配置規則中匹配path前綴,映射還原為原域名對應的源OSS,實現準確鏡像回源到源OSS。

Path前綴與源OSS的一一映射表如下:

Path前綴

源OSS

/image

image_oss

/product

product_oss

/community

community_oss

如域名community.xxx.com的OSS鏡像回源配置示例圖

圖片

實現客戶端側收斂、CDN服務側分發源站後,再來看下客戶端通過CDN服務請求靜態資源的示例圖:

圖片

左側紅框中為客戶端側收斂完成多對一改造的示例,右側紅框中為服務側OSS鏡像回源完成一對多改造的示例,架構上基本已經實現CDN域名收斂的目標。但我們還需要考慮如何保證功能上線階段的穩定性及上線後域名收斂的靈活性。

2.4 上線階段穩定及靈活放量

通過支持功能整體可灰度及監控日誌保證穩定性

配置AB實驗開關作為客戶端功能灰度開關,支持按百分比放量,控制客戶端CDN域名收斂功能的灰度比例,保證功能上線的穩定性。

客戶端

key

value

描述

Android

merge_host_android

1-開啟,0-關閉(默認)

Android端CDN域名收斂AB實驗開關

iOS

merge_host_ios

1-開啟,0-關閉(默認)

iOS端CDN域名收斂AB實驗開關

客戶端通過AB實驗控制CDN域名收斂功能可灰度的示例圖:

圖片

在CDN域名收斂功能的關鍵代碼邏輯處預埋日誌(支持採樣),上報到阿里雲日誌服務SLS,在SLS平台配置監控告警,便於及時發現線上異常進行處理。

CDN域名收斂功能代碼級監控埋點定義

字段

描述

類型

是否必填

bi_id

業務描述

String

必填

"mergeHost"

section

代碼執行關鍵點

String

必填

"init_config_data"

desc

描述

String

可選

"域名收斂數據初始化"

host

當前host

String

可選

"cdn.xxx.com"

url

當前url

String

可選


originHost

原始host

String

可選

"image.xxx.com"

code

http狀態碼

int

可選

5xx

stack

報錯堆棧信息

String

可選


通過支持待收斂域名單獨放量保證靈活性

客戶端配置中心下發待收斂域名列表配置數據,按單域名維度支持待收斂域名動態下發及逐步放量。

{
    "mergeHostConfigs": [{ //待收敛的CDN域名列表
        "host": "image.xxx.com", //原域名
        "pathPrefix": "/image", //原域名一一映射的path前缀
        "rate": 1 //单域名收敛灰度率
    }, { 
        "host": "product.xxx.com",
        "pathPrefix": "/product", 
        "rate": 0.5 
    }, { 
        "host": "community.xxx.com",
        "pathPrefix": "/community", 
        "rate": 0.1 
    }]
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

現在,我們再看下CDN域名收斂後客戶端請求靜態資源的流程圖:

圖片

開發、測試、發布階段的灰度放量流程

AB實驗放量流程

階段

事項

App端新版本開發及測試階段

T1測試環境AB實驗開關關閉,通過白名單命中實驗。

測試通過後到灰度前

T1測試環境AB實驗組開50%,觀察所有安裝測試包的內部同事是否有問題反饋。

App灰度期間

線上AB實驗組和對照組各開1%,觀察線上穩定性。

正式發布

實驗組和對照組逐步放量5%,10%,30%,50%。

實驗組和對照組各開50%後

觀察實驗組與對照組數據,在此期間進行待收斂域名按單域名維度收斂放量。

待收斂域名按單域名維度收斂全量後

實驗組擴大放量70%,90%,100%。

單域名維度收斂放量流程

階段

事項

放量前

制定灰度放量時間表。

拉灰度放量通知群,便於線上變更及時通知運維及各業務方。

配置OSS鏡像回源規則,通知測試同學進行線下驗證,包括:



命中AB實驗組,域名收斂功能生效,使用拼接新URL且資源訪問正常。

未命中AB實驗,域名收斂功能不生效,使用原URL且資源訪問正常。

放量中

按放量時間表操作配置中心,發布新灰度量。

線上變更同步到灰度放量通知群,at相關方共同關注各項指標。

同步測試同學進行線上環境回歸驗證。

觀察各監控平台指標1個小時。




放量後

持續關注各項監控指標及用戶反饋。

3、CDN多廠商容災

得物作為電商平台,無論是大促活動(如618,七夕節,雙十一,雙十二等)還是日常服務,都需要給用戶提供穩定可靠的CDN服務。

阿里雲CDN服務SLA僅支持99.9%,即每月存在43分鐘線上服務不可用的風險阿里雲CDN服務SLA官方文檔:http://terms.aliyun.com/legal-agreement/terms/suit_bu1_ali_cloud/suit_bu1_ali_cloud201803050950_21147.html?spm=a2c4g.11186623.0.0.7af85fcey4BKBZ

因此,將多個CDN域名收斂為統一域名後,我們決定再對統一域名進行CDN同廠商、多廠商容災改造升級。

3.1 容災思路

主要考慮以下幾個點:

  • 單個主域名存在不可用風險,可以通過動態下發域名列表給客戶端。
  • 客戶端在主域名不可用時自動容災降級,選擇備用域名進行網絡請求。
  • 域名列表中所有域名都不可用時,可以還原使用域名收斂前的原域名作為兜底。
  • 對域名列表中不可用的域名,可以通過可用性檢測,自動恢復域名可用狀態。

3.2 動態下發域名列表

客戶端支持CDN域名可配置,根據配置中心下發的域名列表選擇加載靜態資源時使用的域名。選擇域名的優先級策略是按域名在域名列表中的順序,默認取域名列表第一個可用域名作為當前域名,列表中還可配置同廠商、多廠商的其他域名作為備用域名。域名切換優先級:主域名-> 同廠商備用域名-> 多廠商備用域名。


{
    "hostListConfig": [{//CDN域名列表
        "host": "cdn.xxx.com", //主域名
        "rate": 1
    },{
        "host": "cdn-ss.xxx.com", //同厂商备用域名
        "rate": 1 //单域名灰度率
    },{
        "host": "cdn-bak.xxx.com", //多厂商域名
        "rate": 1 //单域名灰度率
    }],
    "reviveProbeInterval":600000, //域名复活探测时间间隔,单位ms
    "configRequestInterval":600000, //配置兜底接口请求时间间隔,单位ms
    "configVersion":1, //配置内容版本号,每变更一次配置就需要版本号+1
    "publicIpList":["223.5.5.5","180.76.76.76"] //国内公共DNS服务IP
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

3.3 域名自動容災降級

客戶端業務層發起靜態資源URL網絡請求時,在網絡庫CDN域名收斂攔截器中執行域名替換邏輯,替換原URL的域名為從域名列表中選擇的當前域名,發起加載靜態資源網絡請求。

監聽當前域名請求的異常回調,如果判定當前域名不可用,則更新當前CDN域名的可用性狀態字段isDisabled賦值為true(不可用為true,可用為false(默認))。當前域名不可用的判定條件如下:

Http協議狀態碼返回5XX(500<=code and code <600)

socket連接超時/失敗,並且客戶端網絡狀態正常(排查客戶端網絡原因)。

客戶端網絡狀態判斷方法: 

通過InetAddress.isReachable函數(Android)或者ping命令(如:ping -c 1 223.5.5.5) 檢測國內公用的DNS服務中 (配置下發IP列表,如:223.5.5.5, 180.76.76.76 ) 至少有一個能ping成功。 

如果ping成功,說明客戶端網絡正常;如果ping失敗,說明客戶端網絡異常。


/**
 * 判断客户端网络是否正常
 */
public static boolean isNetworkStatusNormal() {

    //IP列表中有一个公共IP可触达则认为网络状态正常
    for (int i = 0; i < publicIpList.size(); i++) {
        String ip = publicIpList.get(i);
        try {
            if (!TextUtils.isEmpty(ip)) {
                InetAddress inetAddress = InetAddress.getByName(ip);
                boolean result = inetAddress.isReachable(3000);
                if (result) {
                    return true;
                }
            }
        } catch (IOException e) {
            DuLogger.t(TAG).e(ip + " test is bad, error e = " + e);
        }
    }
    return false;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

如果當前CDN域名不可用,遍歷CDN域名列表,獲取下一個可用CDN域名作為新的當前CDN域名。再次替換URL的域名為新的當前域名,發起靜態資源網絡請求,實現端側域名自動容災降級支持同廠商、多廠商容災的能力。

如果CDN域名列表中所有域名都不可用,則執行兜底邏輯,還原使用CDN域名收斂前的原URL,再次發起請求。

域名自動容災降級流程圖:

圖片

3.4 域名可用性自動恢復​

對於域名列表狀態字段isDisabled已被賦值為true的CDN域名,在CDN域名解禁、CDN服務器故障恢復後,客戶端側需要及時感知並自動恢復CDN域名可用性,保證客戶端網絡請求流量從優先級低的備用域名逐步切換回主域名。

域名可用性恢復的具體步驟如下:

  • 客戶端實現域名可用性探測邏輯,支持檢測CDN域名是否恢復可用。
  • 網絡庫攔截到靜態資源URL網絡請求後,如果當前時間距離上次探測時間大於間隔時間(配置下發,如10分鐘),異步執行域名可用性探測邏輯。
  • 在子線程中遍歷CDN域名列表,依次取出列表中可用性狀態字段isDisabled被賦值為true的不可用域名,替換原URL的原域名生成新的URL。
  • 使用新URL發送Http HEAD請求進行探測,如果請求返回的Http狀態碼為2XX,則說明該CDN域名已恢復可用,將狀態字段isDisabled賦值為false;否則跳過。
  • 繼續遍歷並探測下一個不可用域名的可用性,直到CDN域名列表遍歷結束。
  • 重新恢復可用性的CDN域名在後續靜態資源網絡請求中可按優先級被重新選擇使用。

域名可用性自動恢復流程圖:

圖片

4、遇到的挑戰

4.1 存在少量資源動態更新的場景

  • 挑戰點

客戶端通過CDN服務請求的靜態資源(圖片,視頻,zip文件)一般文件內容不會更新(URL不變,文件被覆蓋更新)。但存在部分業務場景請求的資源是json文件,會動態更新json文件內容,如客戶端配置中心平台發布配置數據,就會覆蓋更新json文件。

在上面我們已經介紹過OSS鏡像回源工作原理,從源OSS拉取資源後統一OSS會存儲一份副本,下次訪問時便直接返回存儲的資源副本,不再觸發鏡像回源。因此,這類資源動態更新的情況需要進行單獨兼容處理。

  • 解決方案

梳理出所有存在資源內容動態更新的業務場景(可枚舉的),推動進行OSS雙寫兼容改造。資源內容需要動態更新時,對源OSS和統一OSS進行同步更新,保證統一OSS上資源的文件內容是最新的。

4.2 CDN服務控制台監控不支持Path維度監控

  • 挑戰點

客戶端完成CDN域名收斂後,多個原域名被收斂為統一域名,原域名以Path前綴形式進行區分。業務側期望域名收斂後可以支持按Path維度查看性能監控報表,但阿里雲CDN服務控制台目前僅支持域名維度監控。因此,需要考慮自研Path維度監控報表。

  • 解決方法

客戶端網絡監控平台支持Path維度監控指標,包括:請求次數,回源次數,流量,帶寬,成本。

通過阿里雲CDN提供的獲取Path維度監控數據API查詢數據,包括請求次數和流量。

圖片

通過阿里雲CDN提供的回源熱門URL接口API查詢熱門URL的回源次數,然後統計Path維度回源次數。

圖片

Path維度監控報表示例:

圖片

4.3 後續新申請的CDN域名、OSS如何卡口​

  • 挑戰點

雖然對現存的多個域名和多個源OSS做了域名收斂和鏡像回源,但還需要考慮如何保證得物App端不會新增新的CDN域名。

  • 解決方法

找運維同學溝通後,在新域名及新OSS申請流程中加入審批環節,實現卡口。

4.4 配置數據也是通過CDN域名下發的,存在不可用風險​

  • 挑戰點

由於配置數據也是通過CDN域名下發的,當域名不可用時,客戶端通過配置中心SDK無法拉取到最新的配置數據(如配置平台新配置的域名列表),客戶端資源請求故障將無法通過調整配置數據的方式得到及時恢復。

  • 解決方法

為了保證配置數據的及時性和可靠性,我們可以添加獲取配置數據的專用API接口作為兜底。當App冷啟動或CDN域名列表中所有域名都不可用時,異步發送專用API接口請求獲取配置數據。


获取配置数据的专用API接口
接口定义:/app/config-center/module-config
请求方式:Post
  • 1.
  • 2.
  • 3.
  • 4.

由於配置中心SDK和專用API接口都是獲取同源的配置數據,且相互獨立,因此客戶端在使用配置數據時,需要對2個數據來源的配置數據進行對比,使用最新的配置數據。如何實現呢?我們通過增加一個configVersion字段代表配置數據的版本,每次更新配置數據時對configVersion進行遞增+1,版本號越大,代表數據越新。客戶端就可以通過判斷兩個數據來源的配置數據中configVersion的大小確定哪個配置數據為最新數據,並進行使用。


//客户端获取最新的配置数据
private ConfigModel getConfigData() {
    ConfigModel configModel = DataSource.getConfigCenterData();
    ConfigModel apiConfigModel = DataSource.getConfigApiData();

    //使用配置中心下发配置数据与兜底接口下发配置数据中最新的数据
    if (configModel != null && apiConfigModel != null) {
        if (configModel.configVersion < apiConfigModel.configVersion) {
            configModel = apiConfigModel;
        }

    } else if (configModel == null && apiConfigModel != null) {
        configModel = apiConfigModel;
    }

    return configModel;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

5、上線後效果

完成8個CDN域名收斂收斂為統一主域名,並支持CDN域名同廠商、多廠商容災能力。

網絡請求性能提升

  • Android 平均耗時:354ms -> 277ms,降低77ms(21%)
  • iOS 平均耗時:226ms -> 194ms,降低32ms(14%)

網絡請求異常率降低

CDN域名收斂功能上線後,TCP連接復用率明顯提升,DNS解析失敗、TCP建連失敗導致的異常次數明顯減少,雙端異常率均有明顯降低

  • Android 異常率:3.42% -> 2.56%,降低0.86%
  • iOS 異常率:0.61% -> 0.13%,降低0.48%

穩定性提升

  • 域名主體統一為dewucdn.com,避免類似舊域名下線全域改造風險。
  • 容災能力提升,CDN域名支持同廠商、多廠商容災兜底, SLA從99.9%提升到99.99%+。

支持阿里雲&騰訊雲多廠商容災能力,用戶網絡正常情況下訪問阿里雲CDN服務請求資源失敗(http code 5xx,或socket失敗),自動重試切換備用域名走騰訊雲CDN請求資源,SLA從單廠商99.9%提升到99.99%+。

HTTPDNS成本降低

阿里雲HttpDNS服務成本降低24%

圖片

6、踩坑經驗

灰度放量階段,內部同學反饋鑑別頁面存在部分鑑別圖片模糊問題

原因:OSS鏡像回源規則配置問題,勾選了“回源參數:攜帶請求字符串”。

這意味著統一OSS在鏡像回源時會將“?”後的請求參數攜帶給源OSS,源OSS按裁剪參數返回給統一OSS裁剪後的縮略圖,而非原圖。客戶端再次請求時,統一OSS便會以該縮略圖作為原圖,再根據圖片裁剪參數做了二次裁剪,導致返回給客戶端的圖片尺寸很小,被View拉伸後造成圖片模糊。

需要注意的是,全網首次請求攜帶的裁剪參數越接近原圖,對圖片的清晰度影響越小;裁剪參數越小,二次請求的裁剪參數越大,對圖片被拉伸的程度越大,圖片越模糊。

全網首次請求示例URL:https://cdn.xxx.com/image-cdn/app/xxx/identify/du_android_w1160_h2062.jpeg?x-oss-process=image//resize,m_lfit,w_260,h_470 二次請求示例URL:

https://cdn.xxx.com/image-cdn/app/xxx/identify/du_android_w1160_h2062.jpeg?x-oss-process=image//resize,m_lfit,w_760,h_1500

如示例URL,原圖是一張寬1160、高2062的圖片,因客戶端View(寬260,高470)展示的需要,拼接了阿里雲圖片裁剪參數"x-oss-process=image//resize,m_lfit,w_260,h_470"。命中CDN域名收斂灰度後,全網首次使用替換為統一域名的新URL請求該圖片。CDN服務無此URL緩存,回源到統一OSS,統一OSS觸發鏡像回源,攜帶請求參數給源OSS。源OSS會根據請求參數中的圖片裁剪參數返回寬259、高473的縮略圖給統一OSS,統一OSS將該縮略圖存儲做為原圖副本。

二次請求時,統一OSS按二次請求的裁剪參數寬760,高1500再做裁剪,然而原圖副本的寬、高均小於裁剪參數(寬260 < 760、高470 < 1500),最終返回給客戶端寬260、高470的縮略圖。客戶端View(寬760,高1500)拉伸縮略圖進行展示,導致圖片模糊。

測試階段僅驗證了圖片是否正常返回並展示,未關注攜帶圖片參數鏡像回源會導致圖片模糊問題。

解決方法:

關閉image.xxx.com灰度放量配置。

重新配置OSS鏡像回源規則,去掉勾選“回源參數:攜帶請求字符串”。使用新的Path前綴作為映射,保證重新觸發鏡像回源正確拉取原圖。

進行測試驗證,確認無圖片模糊問題後重新放量。

刪除/image-cdn下錯誤的縮略圖片,避免oss存儲成本浪費。

7、小結

通過CDN域名收斂我們不僅收穫了CDN網絡性能、穩定性上的提升,而且實現了多個域名的統一和規範,大大降低了後續CDN域名的優化和維護複雜度。另外,也支持了CDN主域名的容災能力,保證了線上服務的穩定性。