最近看到好幾篇有內容的討論串,都提到 “抽象化思考” 是個很關鍵的能力。我就在想 “什麼才是正確的抽象化思考” 案例? 看了很多講理論的文章,也看了很多定義, 我相信很多人還是一樣有看沒有懂,或是你真的理解抽象化的概念了,但是真正應用在工作上,你也不一定用的到位啊! 於是就有了寫這篇文章的念頭。我一樣不喜歡只講 “理論”,理論說的容易,要落實才是最難的那一步,因此我決定拿個實際上工作相關的案例來說明 “抽象化” 概念。
我就拿我在 面試架構師常問的問題 之一: “折扣機制的設計方式” 當作這篇文章的主題吧! 只要做過銷售網站,或是相關的系統,我相信一定都被這個主題弄得牙癢癢的,你想的再週全,你的客戶就是有辦法想出你意料不到的折扣規則來折磨你…。不過,這是個很好的例子啊,正好拿來驗證你的抽象化思考夠不夠到位。該說是職業病嗎? 從開始學寫 code 後,我就習慣在日常生活中,碰到大小事情,我都會在腦袋裡想一下 “這東西我該怎麼寫 code 來處理?” …,就是這個折扣計算的問題,每次我在收銀機等結帳時就在想:
這個第二件六折的折扣我該怎麼去計算?
這個第二件加一元我該怎麼設定才合理?
這個即期品半價優惠的機制我該怎麼設計,POS 機才能搞的定?
這麼多種折扣混在一起,結帳時怎麼用一致的規則來處理才不會算錯?
這些問題我就這樣,在我腦袋裡面轉過好幾次了 XDD (所以一時之間想不出來的朋友們不用難過)。我就用這篇文章的篇幅來說明一下該如何將這問題抽象化,然後一步一步解決現在跟未來的問題。
好久沒寫微服務系列的文章了,這篇算是 Message Queue 的進階版本,如果你有越來越多的任務需要 Message Queue 後端的 Worker 來處理,後端 Worker 的架構其實是個很有意思的架構思考練習題。會想解決這個議題: Task Management, 需求有點類似 serverless, 我希望有個 pool 能很快的消化掉我丟進去的 task …。其實我需要的架構就類似 message queue + serverless 就能符合了,但是有些因素, 我得認真評估自行建置最關鍵的那一塊該怎麼做。不過這篇我沒打算把主題擴的那麼大,我就專注在 Process Pool 上面了。
本來打算先講我打算如何解決問題,再來講實作的,不過架構題的決策,往往就是需求、架構跟實作的平衡啊,不先交代一下基本的實作技術,有點講不下去 XDD,我決定先花點篇幅說明程式碼隔離機制 (Isolation) 的架構選擇,再來講應用考量,最後說明 Process Pool 的實作。我分三個段落來說明最終 Process Pool 這個構想是怎麼誕生的:
挑戰: Isolation 的機制研究:
了解與比較各種執行環境隔離的技術 (InProcess / AppDomain / Process), 以及如何橫跨隔離環境進行有效率的通訊 (IPC)
為何需要建立隔離環境:
交代我工作場合面臨的需求與挑戰,Container + Orchestration / Serverless 無法滿足的需求
挑戰: Process Pool 的設計與開發
在技術與平台的選擇與平衡, 如何設計與開發 Process Pool
在這過程中,其時用了很多我過去文章個別提過的好幾種技巧,算是個終極的綜合應用篇吧! 最遠可以追溯到 10 年前那系列 Thread Pool 設計與實作的相關文章。只是這篇的應用,把 “Thread” Pool 的觀念,擴大到 “Process” Pool 了。現在的技術,Process 層級的隔離期時有更多的工具可以運用了,例如 Container 就是一例;所以過程中我也花了不少時間在拿捏,站在巨人的肩膀上 vs 重新發明輪子 的取捨;對這部分有興趣的讀者們,可以直接跳到第二段。
好久不見的 水電工日誌 又出現了 !
自從 12 年前,家裡重新整修了一番,花了不少時間把家裡的區域網路弄起來後,就再也沒花功夫去搞他了,只能說在家裡先佈好足夠的網路線,還有一個可靠的機櫃真是好用啊 (果然是阿宅的夢想)。不過四個多月前,一次台電計畫性的停電,就把我家的 router 跟 switch 搞掛了, 雖然 router 兩天後莫名其妙的又活起來, 但是終究壽命已盡, 撐到一個月前雙十一前夕又掛了, 再也救不起來…
事後發現,停電根本不是真正的原因啊 (我有 UPS, 又有事先主動關機…), 根本原因就是裡面的電容都鼓起來了, 單純關機就再也開不起來而已… 雖然掛掉的 router 被 蘇老 妙手回春救回來, 不過我替他安排好退休生活了, 趁著雙十一敗家合理 (其實根本沒優惠啊啊啊) 的氛圍下,我把家裡的網路設備都換了一輪了… Orz
這篇也是個練習題,這次換個實際一點的主題,”排程任務” 的處理機制。
後端服務做久了,一定有碰過這類需求: 使用者想要預約網站在某個指定的時間點執行預先排定的工作。不過,Web Application 先天的框架,就都是 Request / Response 的被動處理模式,有 Request, 才有 Response… 這模式先天就不擅長處理預先排定時間執行的任務。因此這類需求,通常都必須另外處理。雖然有不少現成的套件或是服務可以解決,不過我還蠻期待工程師都能思考看看,如果我找不到合適的套件,必須自己處理時,我知道該怎麼做嗎?
別誤會我不是要大家丟掉現成的服務,全部都自己造輪子…,但是現實狀況的確不是每個情境都完全適用的,這個練習就是讓你先做好準備,有必要時就有能力自己打造。當你能理解背後的設計時,你也同時有能力更精準的評估現有方案的好壞。擁有這能力,你也開始有機會做到更好的整合性。當你必須在既有的系統限制下實做這功能,又不想增加太多不必要的相依姓,或是更動既有的系統架構,都是運用的好時機。
如果不考慮 “預約” 這因素,其實這問題很簡單啊,用 message queue 搭配 worker(s) 就解決了,但是 message queue 都是一瞬間的事情, 預約一小時後才要執行的任務,丟到 queue 然後再讓它佔個位子等一小時才消化,實在不是個好主意。於是我就把這主題簡化一下:
在資料庫內維護排定工作的時程表, 你的解決方案只能用 pooling 輪詢的方式, 在指定的時間啟動工作。需要同時解決高可用,以及降低輪詢對於 DB 的效能負擔。
這練習題是我在公司,拿來給架構團隊的 team member 練習思考用的題目,同時也準備實際應用在要上線的專案身上。我想既然都做了準備了,因此也在這邊開放給大家練習看看。規則跟 上一篇 一樣,有興趣的請自行到我的 GitHub 取用,願意的話,也歡迎將你的 solution PR 放上來,我會在後半段文章用我的角度幫你 code review 。
前面兩篇聊了不少 CLI / PIPELINE 開發的技巧跟基本功夫,這篇換個方式,來聊聊後端工程師該如何自己練習基本功夫吧。這次談的是 “精準” 控制的練習。
我在公司負責架構的團隊,兩個月前,我出了個練習題讓團隊的人練習,目的是測驗大家對於處理大量複雜的任務的精準程度。所謂的 “精準”,是指你腦袋裡面能很清楚的掌握你 “期望” 程式該怎麼跑,以及實際上你的程式是否真的如你預期的執行。這篇文章,我想換個方式,把這練習題的 source code 公開出來,用實際的 Hands-On Labs 練習的方式來進行。有興趣的朋友可以親自練習看看。練習的目的,是讓你思考如何精準的處理任務,而不是學習一堆大部頭的框架,因此我設計的這練習題,你只要熟悉基本的 C# 語法與 BCL (Basic Class Library) 就足以應付了,困難的地方在於你如何解決問題。
練習可以很簡單,也可以很複雜;我還蠻想試看看收集大家的解法,在這篇文章的後半段統一做個評論的;如果你願意將你的 solution PR 放上來,我會在後半段用我的角度幫你 code review 當作回報。之前會想在內部讓 team member 做這練習,目的很簡單,現在的工程師越來越容易忽略掉一些開發的基礎能力,面臨問題就越來越依賴外部的工具或服務來解決。使用不得當,往往就會在執行效率,程式碼維護,或是系統維運的階段付出代價。我們都用 public cloud, 光是 VM 的 instance 數量就超過百台,工程師們你知道你寫的 code 會直接反映在成本上嗎? 只要改善 1% 的效能,每個月的費用成本就可以降低 1% …, 這情況在你的流量很大的時候,加上背後的運算資源都來自雲端服務時會更明顯…。
因此,在公司我都會跟工程師在一對一面談的時候,問問 developer 自己是否想過這些問題: