事情的起因是因?yàn)槲铱吹搅诉@樣一張圖:
Write Throughput Exceeded (Count / Request) — Average
這張圖一開始我還不怎么重視存谎,因?yàn)樗腨軸數(shù)字才幾十甚至個數(shù)候齿,這對于每小時上千萬的請求量來說最爬,完全不能引起我的注意力啊。
直到后來發(fā)生的一些事崖媚,讓我對幾乎所有系統(tǒng)監(jiān)控都警覺起來痛单。
這張圖的意思,是 Producer 寫入 Kinesis 時超出預(yù)設(shè)容量的部分须误,單位是 個/每次請求挨稿,這個說明什么呢,說明數(shù)據(jù)的寫入太快京痢,超過預(yù)設(shè)容量了奶甘。
但是我算了一下,當(dāng)前 Kinesis 的 Stream祭椰,我是開了 4 個 Shard 的臭家,理論上來說疲陕,它的寫入的吞吐量應(yīng)該是 4 * 1000 = 4000/s,然而钉赁,我們目前每小時的流量才 8,000,000 蹄殃,算下來應(yīng)該是 8,000,000/60/60 = 2222.22/s,遠(yuǎn)小于 Kinesis 的吞吐量最大值你踩,按理來說不應(yīng)該出現(xiàn)超量的情況诅岩。
所以我去研究了一下代碼,這一研究就研究了好幾天带膜,經(jīng)過不斷地測試吩谦,終于發(fā)現(xiàn)問題出在批量寫入后的判斷邏輯上。
原先我們的邏輯是這樣的:
for i := 0; i < maxRetry; i++ {
_, err = kinesis.PutRecords(input)
if err == nil {
return
}
time.Sleep(backoff(i))
}
可以看到膝藕,如果出錯的話式廷,我們是會進(jìn)行重新寫入的。但是經(jīng)過我的反復(fù)測試束莫,我發(fā)現(xiàn)其實(shí) WriteProvisionedThroughputExceeded 這個錯誤并不會出現(xiàn)在 err 里面懒棉,而是出現(xiàn)在 PutRecords() 返回的第一個參數(shù)里面。
PutRecords() 會返回一個 output 和 err览绿,其中 output 的定義是:
// PutRecords results.
*type*PutRecordsOutput *struct*{
_ *struct*{} `type:"structure"`
// The encryption type used on the records. This parameter can be one of the
// following values:
//
// * NONE: Do not encrypt the records.
//
// * KMS: Use server-side encryption on the records using a customer-managed
// AWS KMS key.
EncryptionType *string `type:"string" enum:"EncryptionType"`
// The number of unsuccessfully processed records in a PutRecords request.
FailedRecordCount *int64 `min:"1" type:"integer"`
// An array of successfully and unsuccessfully processed record results, correlated
// with the request by natural ordering. A record that is successfully added
// to a stream includes SequenceNumber and ShardId in the result. A record that
// fails to be added to a stream includes ErrorCode and ErrorMessage in the
// result.
//
// Records is a required field
Records []*PutRecordsResultEntry `min:"1" type:"list" required:"true"`
}
其中策严,F(xiàn)ailedRecordCount 會返回此次寫入失敗的 record 數(shù)量,Records 里面會返回所有 record 的狀態(tài)饿敲。
我們要想判斷是否 WriteProvisionedThroughputExceeded妻导,首先要判斷是否 FailedRecordCount > 0,其次怀各,要遍歷 Records倔韭,檢查是否 Record.ErrorCode != nil ,如果是瓢对,表示該記錄寫入失敗寿酌,需要放回重試隊(duì)列中。