10月18日晚上 22:00 ,我們對處於灰度發布階段的新版博客后台(Angular 8.2.7 + .NET Core 3.0)進行了一次發布操作,在發布后由於清除緩存 web api 的一個 bug 造成在發布后通過新版博客后台修改的博文無法訪問(404錯誤);在發現問題后,我們回退至發布之前的版本,但是由於 appsettings.Production.json 配置文件的不一致造成回退后的版本出現 500 錯誤;在修復配置文件問題后,在 docker swarm 集群上部署時又遭遇奇怪的容器健康檢查失敗的問題,多次部署后才成功,直至 23:00 左右才恢復正常。
非常抱歉,這次故障給使用新版博客后台的園友帶來了很大的麻煩,請您諒解。
在這次發布中包含一個比較大但卻沒有引起我們足夠重視的變更,原先在博客后台代碼中進行的清除 memcached 緩存(修改博文時清除對應的緩存)的操作改為調用 web api ,在實現清除緩存 web api 時由於沒有足夠重視在沒有寫集成測試覆蓋的情況下就發布了,從而沒有及時發現其中埋藏的一個 bug ,這個 bug 是由下面的 C# 代碼引起的:
await _cacheService.RemoveAsync(CacheKeyManager.GetBlogPost(blogId.Value, postId.Value)); var post = await blogPostService.GetCachedPostById(blogId.Value, postId.Value); //... if (post.DisplayOnHomePage) { await ClearHomePostsList(blogId.Value); } //..
上面的代碼中在清除所修改博文的緩存后,又獲取該博文進一步清除與該博文相關聯的緩存,調用 GetCachedPostById 方法時又創建了緩存,但由於實現時漏寫了 DTO 映射配置代碼,造成緩存的 BlogPostDto 字段值不完整從而 PostId 的值為 0 。在我們的緩存機制中,對於不存在的博文,會 new 一個空的 PostId 為 0 的 BlogPostDto 放入緩存,所以 PostId 為 0 的緩存數據都當作不存在的博文直接響應 404 ,故障因此而引發。
針對這次故障,在修掉 bug 代碼的同時我們將采取以下改進措施:
1)對從緩存中獲取的數據進行校驗並自動修復,這樣即使出現錯誤的緩存數據,也可以減少對業務的影響。
else if (blogPost.PostId != postId) { blogPost = await GetBlogPostById(blogId, postId); await _cacheService.UpdateAsync(cacheKey, 3600, blogPost); }
2)加強 Code Review
3)提高集成測試的覆蓋率
4)解決生產環境配置管理的問題
5)改用 k8s 部署生產環境
最近的新版博客后台發布故障暴露了我們在團隊開發能力上的落后,我們正在努力改進與提升,希望大家能夠諒解我們暫時的 low 。