Cloudflare Global Outage 討論

一篇好的公關技術文可以看出什麼端倪?

ta-ching chen

1 minute read

介紹

前陣子 Cloudflare global outage 導致許多服務突發性異常,7/12 號時 Cloudflare 針對此次意外釋出了一篇文章, 其中清楚的解釋整件事的來龍去脈。內容部分就不多提,有興趣的人建議一定要看。

針對文章個人覺得幾點特別值得注意:

完整解釋 Cloudflare 整套測試、部署流程

一般比較少見大型公司完整說明內部的 CI/CD 流程,透過這篇文章能一窺出其內部針對產品上線、測試、驗證的流程,以及發生回滾 (rollback) 除錯的概略圖。

animal-deploy-1

Localhost 迷航記

當 localhost 不再是 localhost 時

ta-ching chen

2 minute read

Introduction

故事背景稍微介紹一下,使用者反映 Fission基於 Kubernetes 之上的 FaaS (Function-as-a-Service) 框架 在週末突發性的無法正常運作。作為一個興趣使然的工程師,遇到使用者反應問題當然要 (義不容辭) 協助排解。 經過各種遠端通靈一種在不知曉確切運作環境或對於問題毫無頭緒下,仍然嘗試除錯的技術 ,發現問題發生在當要初始化使用者的 function 時出現。

function-pod

Fig. 1 Fission function pod specialization process

整個初始化流程如 Fig. 1,首先 executor 會送出 specialize 請求給 fetcher,讓它取得 function code 後放至 share volume 內。 再由 fetcher 呼叫 env runtime,讓其載入 function code 後服務 HTTP 請求。

"logger":"fetcher"
"msg":"error connecting to function environment pod for specialization request, retrying"
"error":"dial tcp 10.58.152.224:8888: i/o timeout"

從日誌上來看錯誤是 i/o timeout。奇妙的地方在於本來是呼叫 localhost,卻顯示 10.58.152.224 超時 ?!

而用戶反應問題是在公司開始導入 proxy 後發生的,到這邊可能性有兩個:

  1. Proxy 設定出現異常,導致 Pod 內部的本地端 HTTP call 被攔截送往其他地方
  2. DNS 解析出現錯誤

原本想說會不會跟 docker 的 NO_PROXY 設定相關,但該設定主要跟 pull image 相關且測試後也驗證不是這個原因。

事已至此,剩下 DNS 解析出錯的可能性,也只能開始往最瞎的方向開始思考:

是不是在 namespace 底下有個名為 localhost 的服務存在?

Go defer 遇上 os.Exit 時失效

間單介紹 defer 使用與特性,並說明遇上 os.Exit 失效的原因

ta-ching chen

3 minute read

前言

在撰寫 Go 程式過程中,我們可能需要在函式執行完畢後執行特定動作以確保不會發生異常,比方說讀取檔案完畢後需要關閉 file descriptor。 為求程式簡潔,最常見的做法是呼叫 defer 進行處理。以下會對 defer 幾個特性做簡介,並且說明在什麼狀況下 deffered function 不會如預期般被執行。

若沒有耐心者,可直接跳到 當 defer 遇上 os.Exit 看本文重點 (笑)

defer 簡介

寫程式時常會遇到需要讀寫檔案、建立連線等行為,在 Go 內類似的操作往往伴隨著關閉 file descriptor 或 connection 的相關操作。

file.Close()

除非偏好波動拳寫法以外

波動拳

否則 early return 寫法往往會包含多個 return,若此時需要在每個 return 前寫同樣的程式碼往往導致簡潔性被破壞。

func fileCopyv1(srcFile, dstFile string) (int64, error) {
    src, err := os.Open(srcFile)
    if err != nil {
        return 0, err
    }

    dst, err := os.Create(dstFile)
    if err != nil {
        src.Close()
        return 0, err
    }

    src.Close()
    dst.Close()
    return io.Copy(dst, src)
}

Go HTTP Header 的那些坑

透過簡單範例說明 Go 開發時常見的 HTTP Header 操作誤區

ta-ching chen

3 minute read

前言

最近開發時常需要針對 HTTP Header 進行操作,過程中發現一些平常並不會特別注意但會造成問題的地方。

以下會以範例講解這陣子所遇到的坑(笑),文中範例程式可以到此 Github Repo 下載。

ResponseWriter.Write 導致客戶端收到錯誤 HTTP 狀態碼

首先請各位看下面的範例程式,並猜看看使用者會收到哪種 HTTP 狀態碼?

http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("foobar"))
    w.WriteHeader(http.StatusBadRequest)
})

覺得是 400 Bad Request? 其實正確答案是 200 OK。

$ curl -i http://127.0.0.1:8080
HTTP/1.1 200 OK
Date: Thu, 20 Dec 2018 06:31:33 GMT
Content-Length: 6
Content-Type: text/plain; charset=utf-8

foobar