Kerry 的筆記本
  • Table of contents
  • Kerry的Mac裝機必要
  • ASP.NET Core 教育訓練文件
    • .NET 9 OpenAPI 介紹與教學
    • 目錄
    • ASP.NET Core Authentication系列(一)理解Claim, ClaimsIdentity, ClaimsPrincipal
    • ASP.NET Core Authentication系列(三)Cookie選項
    • ASP.NET Core Authentication系列(二)實現認證、登錄和註銷
    • ASP.NET Core Authentication系列(四)基於Cookie實現多應用間單點登錄(SSO)
    • ASP.NET Core Consul 教學
    • ASP.NET Core Hangfire 排程管理
    • ASP.NET Core KeyCloak 實作
    • ASP.NET Core NLog-依照Environment使用Nlog.Config檔案
    • ASP.NET Core NLog-如何使用 NLog 將 log 寫到檔案
    • ASP.NET Core Nlog-發送訊息到ElasticSearch
    • 目錄
    • ASP.NET Core Quartz.NET 管理介面
    • ASP.NET Core RDLC 報表設計
    • ASP.NET Core SFTP (使用第三方套建 SSH.Net) - 類別庫為案例
    • ASP.NET Core 中使用 HttpReports 進行接口統計,分析, 可視化, 監控,追踪等
    • ASP.NET 使用 MassTransit 與 RabbitMQ,實現事件發佈、訂閱
    • Asp.Net Core 分散式Session – 使用 Redis
    • ASP.NET Core 前台會員修改個人資料
    • ASP.NET Core 前台會員忘記密碼與重設密碼
    • ASP.NET Core 前台會員登入
    • ASP.NET Core 前台會員註冊
    • ASP.NET Core 呼叫 API 發生 CORS 錯誤
    • ASP.NET Core 如何套網頁設計樣版
    • ASP.NET Core 客製化Model Validation 預設錯誤訊息
    • ASP.NET Core 後台查詢頁面教學
    • ASP.NET Core 網站生命週期
    • ASP.NET Feature Management 使用說明與教學
    • ASP.NET RulesEngine 介紹
    • ASP.NET WinForms APP 程式安裝檔
    • LinePay 支付完成後返回 LINE 應用而不跳出外部瀏覽器
    • EntityFramework
      • EF Core Migrations 完整教學手冊
      • EntityFramework Core DB Migrations
      • 使用 Entity Framework Core (EF Core) 的 Migrations 功能進行版本控制
    • NET 6
      • .NET 6 Autofac範例
      • .NET 6 Automapper範例
      • .NET 6 BenchmarkDotNet範例
      • .NET 6 Bogus範例
      • .NET 6 Dapper範例
      • .NET 6 Dapper語法說明
      • .NET 6 EFCore範例
      • .NET 6 EFCore語法說明
      • .NET 6 EPPlus圖表範例
      • .NET 6 EPPlus範例
      • .NET 6 Hangfire範例
      • .NET 6 HttpClient單元測試範例
      • .NET 6 MailKit前置作業
      • .NET 6 MailKit範例
      • .NET 6 Moq範例
      • .NET 6 NLog範例
      • .NET 6 NLog進階範例
      • .NET 6 Serilog範例
      • .NET 6 Serilog進階範例
      • .NET 6 Telegram.Bot前置作業
      • .NET 6 Telegram.Bot範例
      • .NET 6 Text.Json範例
      • .NET 6 swagger授權
      • .NET 6 swagger範例
      • .NET 6 xUnit範例
      • .NET 6 取得appsettings檔案內容
      • .NET 6 更改回傳Json時為大駝峰命名
      • .NET 6 解決System.Text.Json序列化後會將所有非ASCII轉為Unicode
    • WDMIS
      • CORS
      • FeatureManagement
      • Serilog
      • Spectre.Console
      • 資料模型實戰:從 MSSQL 設計到 .NET 8 WebAPI 實作(以刀具管理為例)
  • Azure
    • 如何在 ASP.NET CORE 5.0 WEB 應用程序中實現 AZURE AD 身份驗證
    • Azure App Configuration 使用教學
    • Azure Blob Storage
    • Azure DevOps 持續整合(CI) + Artifacts
  • CSharp
    • ASP.NET await 與 wait 的差異
    • AutoMapper —— 類別轉換超省力
    • C# 中的 HTTPClient — 入門指南
    • C# 正則表達式:從零到英雄指南
    • C# 集合, List<> 取交集、差集、聯集的方法
    • C#單元測試教學
    • CORS 介紹與設定方式
    • CSharp Coding Conventions
    • Using jQuery Unobtrusive AJAX in ASP.NET Core Razor Pages
    • 深入Dapper.NET源碼
    • 菜雞與物件導向
      • 菜雞與物件導向 (0): 前言
      • 菜雞與物件導向 (1): 類別、物件
      • 菜雞與物件導向 (10): 單一職責原則
      • 菜雞與物件導向 (11): 開放封閉原則
      • 菜雞與物件導向 (12): 里氏替換原則
      • 菜雞與物件導向 (13): 介面隔離原則
      • 菜雞與物件導向 (14): 依賴反轉原則
      • 菜雞與物件導向 (15): 最少知識原則
      • 菜雞與物件導向 (2): 建構式、多載
      • 菜雞與物件導向 (3): 封裝
      • 菜雞與物件導向 (4): 繼承
      • 菜雞與物件導向 (5): 多型
      • 菜雞與物件導向 (6): 抽象、覆寫
      • 菜雞與物件導向 (7): 介面
      • 菜雞與物件導向 (8): 內聚、耦合
      • 菜雞與物件導向 (9): SOLID
      • 菜雞與物件導向 (Ex1): 小結
  • DBeaver
    • 如何強制讓 DBeaver 在 Mac 上使用英文介面
  • DesignPattern
    • OAuth
    • Repository 模式 (Repository Pattern)
    • Single Sign On 實作方式介紹 (CAS)
    • 【SOP製作教學】新手適用,SOP範例、流程圖、製作流程全公開!
    • 【SOP製作教學】流程圖教學、重點範例、BPMN符號介紹!
    • 【SOP製作教學】流程圖符號整理、BPMN2.0進階符號教學!
    • 多奇數位 C# 程式碼撰寫規範 (C# Coding Guideline)
    • 軟體分層設計模式 (Software Layered Architecture Pattern)
    • 開源程式碼檢測平台 SonarQube
    • 菜雞新訓記
      • 菜雞新訓記 (0): 前言
      • 菜雞新訓記 (1): 使用 Git 來進行版本控制吧
      • 菜雞新訓記 (2): 認識 Api & 使用 .net Core 來建立簡單的 Web Api 服務吧
      • 菜雞新訓記 (3): 使用 Dapper 來連線到資料庫 CRUD 吧
      • 菜雞新訓記 (4): 使用 Swagger 來自動產生可互動的 API 文件吧
      • 菜雞新訓記 (5): 使用 三層式架構 來切分服務的關注點和職責吧
      • 菜雞新訓記 (6): 使用 依賴注入 (Dependency Injection) 來解除強耦合吧
      • 菜雞新訓記 (7): 使用 Fluent Validation 來驗證參數吧
  • DevOps
    • Repository 模式 (Repository Pattern)
    • pipeline工具研究
    • 單例模式 (Singleton Pattern)
    • 單元測試
    • 軟體分層設計模式 (Software Layered Architecture Pattern)
    • 雙重檢查鎖定模式 (Double-Checked Locking Pattern)
  • Docker
    • Docker 中部署 .NET 8 Web App 並支援 HTTPS
    • Docker指令大全
    • 第七章 安裝Nomad
    • Docker - 第三章 | 安裝 MSSQL
    • Docker - 第九章 | 安裝 datalust seq
    • 第二章 docker-compose 教學
    • Docker - 第五章 | 安裝 Redis
    • 第八章 安裝SonarQube
    • Docker - 第六章 | 安裝RabbitMQ
    • 第十一章 安裝 VtigerCRM
    • 第十二章 安裝KeyCloak
    • Docker - 第十章 | 安裝 Redmine
    • 第四章 安裝MySQL
    • Docker Desktop (含更改 Docker Image 路徑)
  • Git
    • Git Flow 指令大全(完整指令整理) 🚀
    • Git 安裝及配置SSH Key
    • Git 建立到上傳
    • 將現有專案的遠端儲存庫直接更改為新的儲存庫
    • Git 流程規劃
    • Git 語法大全
    • 30 天精通 Git 版本控管
      • 30 天精通 Git 版本控制
        • 第 01 天:认识 Git 版本控制
        • 第 02 天:在 Windows 平台必装的三套 Git 工具
        • 第 03 天:建立仓库
        • 第 04 天:常用的 Git 版本控制指令
        • 第 05 天:了解仓库、工作目录、物件与索引之间的关系
        • 第 06 天:解析 Git 资料结构 - 物件结构
        • 第 07 天:解析 Git 资料结构 - 索引结构
        • 第 08 天:关于分支的基本观念与使用方式
        • 第 09 天:比对文件与版本差异
        • 第 10 天:认识 Git 物件的绝对名称
        • 第 11 天:认识 Git 物件的一般参照与符号参照
        • 第 12 天:认识 Git 物件的相对名称
        • 第 13 天:暂存工作目录与索引的变更状态
        • 第 14 天: Git for Windows 选项设定
        • 第 15 天:标签 - 标记版本控制过程中的重要事件
        • 第 16 天:善用版本日志 git reflog 追踪变更轨迹
        • 第 17 天:关于合并的基本观念与使用方式
        • 第 18 天:修正 commit 过的版本历史记录 Part 1
        • 第 19 天:设定 .gitignore 忽略清单
        • 第 20 天:修正 commit 过的版本历史记录 Part 2
        • 第 21 天:修正 commit 过的版本历史记录 Part 3
        • 第 22 天:修正 commit 过的版本历史记录 Part 4 (Rebase)
        • 第 23 天:修正 commit 过的版本历史记录 Part 5
        • 第 24 天:使用 GitHub 远端仓库 - 入门篇
        • 第 25 天:使用 GitHub 远端仓库 - 观念篇
        • 第 26 天:多人在同一个远端仓库中进行版控
        • 第 27 天:通过分支在同一个远端仓库中进行版控
        • 第 28 天:了解 GitHub 的 fork 与 pull request 版控流程
        • 第 29 天:如何将 Subversion 项目汇入到 Git 仓库
        • 第 30 天:分享工作中几个好用的 Git 操作技巧
      • zh-tw
        • 第 01 天:認識 Git 版本控管
        • 第 02 天:在 Windows 平台必裝的三套 Git 工具
        • 第 03 天:建立儲存庫
        • 第 04 天:常用的 Git 版本控管指令
        • 第 05 天:了解儲存庫、工作目錄、物件與索引之間的關係
        • 第 06 天:解析 Git 資料結構 - 物件結構
        • 第 07 天:解析 Git 資料結構 - 索引結構
        • 第 08 天:關於分支的基本觀念與使用方式
        • 第 09 天:比對檔案與版本差異
        • 第 10 天:認識 Git 物件的絕對名稱
        • 第 11 天:認識 Git 物件的一般參照與符號參照
        • 第 12 天:認識 Git 物件的相對名稱
        • 第 13 天:暫存工作目錄與索引的變更狀態
        • 第 14 天: Git for Windows 選項設定
        • 第 15 天:標籤 - 標記版本控制過程中的重要事件
        • 第 16 天:善用版本日誌 git reflog 追蹤變更軌跡
        • 第 17 天:關於合併的基本觀念與使用方式
        • 第 18 天:修正 commit 過的版本歷史紀錄 Part 1
        • 第 19 天:設定 .gitignore 忽略清單
        • 第 20 天:修正 commit 過的版本歷史紀錄 Part 2
        • 第 21 天:修正 commit 過的版本歷史紀錄 Part 3
        • 第 22 天:修正 commit 過的版本歷史紀錄 Part 4 (Rebase)
        • 第 23 天:修正 commit 過的版本歷史紀錄 Part 5
        • 第 24 天:使用 GitHub 遠端儲存庫 - 入門篇
        • 第 25 天:使用 GitHub 遠端儲存庫 - 觀念篇
        • 第 26 天:多人在同一個遠端儲存庫中進行版控
        • 第 27 天:透過分支在同一個遠端儲存庫中進行版控
        • 第 28 天:了解 GitHub 的 fork 與 pull request 版控流程
        • 第 29 天:如何將 Subversion 專案匯入到 Git 儲存庫
        • 第 30 天:分享工作中幾個好用的 Git 操作技巧
  • Hands-On Labs - LineBotSDK 實作手札 (C#, .net core)
    • 00. 如何申請LINE Bot
    • CLI
      • 使用CLI來發送新的Channel Access Token(LINE Bot)
      • 使用CLI免費發送LINE Notify通知
    • basic
      • 如何發送LINE訊息(Push Message)
      • 如何發送LINE Template Messages
      • 如何發送ImageMap訊息
      • 如何發送Flex Message
      • 如何在訊息後面加上QuickReply快捷選項
    • liff
      • Lab 21: 建立第一個LIFF應用
    • webhook
      • 如何建立可Echo的基本LINE Bot
      • 如何在WebHook中取得用戶個人資訊(名稱、頭像、狀態)
      • 如何在WebHook中取得用戶上傳的圖片(Bytes)
  • Markdown
    • Markdown Cheatsheet 中文版
    • Markdown語法大全
    • 使用HackMD建立書本目錄
    • 使用HackMD建立簡報
  • SAP ABAP
    • ABAP開發環境和總體介紹
    • SAP MM模塊常用表總結
    • SAP QM數據庫表清單
    • SAP欄位與表的對應關係
  • SQL Server
    • [SQL SERVER] Like in
    • SQL Server 中,移除資料庫中所有的關聯限制
    • SQL Server 刪除資料庫中所有資料表
    • SQL Server View、Function 及 Stored Procedure 定義之快速備份
    • SSMS v18 清除登入畫面中,下拉選單歷史紀錄
    • [MS SQL]如何透過Database Mail進行郵件發送
    • [SQL SERVER]撰寫Stored Procedure小細節
    • 使用 Data Migration Assistant 移轉 SQL Server 資料庫與帳戶
    • 使用SSIS創建同步資料庫數據任務
  • Tools
    • 免費 FTP 伺服器 FileZilla Server 安裝教學 (新版設定)
  • VisualStudio
    • .NET CLI 指令碼介紹
    • Visual Studio 使用 Git 版本控制
    • 使用 Visual Studio 2022 可透過 .editorconfig 鎖定文字檔案的儲存編碼格式分享
  • Web API
    • ASP.NET Core 6 Web API 進行 JWT 令牌身份驗證
    • [ASP.NET Core]如何使用SwaggerAPI說明文件
    • ASP.NET Core Web Api實作JWT驗證筆記
    • ECFIT API 範例
    • JWT Token Authentication And Authorizations In .Net Core 6.0 Web API
    • 微服務架構 - 從狀態圖來驅動 API 的設計
  • Windows
    • [C#] 伺服器監控常用語法 (事件檢視器、CPU 硬碟使用率、程式執行狀況)
    • Configure IIS Web Server on Windows Server 2019
    • Log Paser Studio 分析 IIS W3C Log
    • Windows Server 2019 如何安裝 IIS 運行 ASP.NET 專案
    • 如何檢查安裝在 IIS 上的 .NET Core Hosting Bundle 版本
    • [IIS] 如何解決網站第一個請求 Request 特別慢 ?
    • IIS 不停機更版設置
    • SQL Server 2019 Standard 繁體中文標準版安裝
    • WINDOWS共用資料夾的網路認證密碼放在哪?如何清除?
    • 如何設定 ASP.NET CORE 網站應用程式持續執行在 IIS 上
  • 專案管理
    • SSDLC (Secure Software Development Life Cycle)
    • 系統開發原則
    • MIS及專案管理-使用Redmine
      • 第10章 - [日常管理]MIS部門週會工作進度追蹤
      • 第11章 - [日常管理]MIS部門主管月會報告管理
      • 第12章 - [日常管理]機房工作日誌
      • 第13章 - [日常管理]MIS部門耗用工時及工作進度檢討
      • 第14章 - [日常管理]MIS文件知識庫
      • 第15章 - [日常管理]整理及管理分享
      • 第16章 - [異常管理]使用者問題回報系統
      • 第17章 - [異常管理]資安事件及異常紀錄
      • 第18章 - [異常管理]整理及管理分享
      • 第19章 - [變革管理]MIS的專案及專案管理五大階段
      • 第1章 - [MIS及專案管理]中小企業MIS的鳥事
      • 第20章 - [變革管理]MIS的新專案管理:起始階段
      • 第21章 - [變革管理]MIS的新專案管理:規劃階段
      • 第22章 - [變革管理]MIS的新專案管理:執行階段
      • 第23章 - [變革管理]MIS的新專案管理:監控階段
      • 第24章 - [變革管理]MIS的新專案管理:結束階段
      • 第25章 - [變革管理]整理及管理分享
      • 第26章 - [ISMS管理]ISMS平台整體規劃
      • 第27章 - [ISMS管理]ISMS文管中心
      • 第28章 - [ISMS管理]ISMS表單紀錄的管理
      • 第29章 - [ISMS管理]整理及管理分享
      • 第2章 - [MIS及專案管理]專案管理的概念及MIS應用
      • 第30章 - 初心、來時路及感謝:系列文章總結回顧
      • 第3章 - [MIS及專案管理]管理工具的選擇
      • 第4章 - [Redmine]Redmine的安裝及設定
      • 第5章 - [Redmine]Redime系統邏輯說明
      • 第6章 - [Redmine]自行建立及維護表單
      • 第7章 - [Redmine]專案版面的規劃
      • 第8章 - [日常管理]AR管理
      • 第9章 - [日常管理]資訊服務申請
  • 微服務架構
    • DDD + CQRS + MediatR 專案架構
    • 微服務架構 #2, 按照架構,重構系統
    • 淺談微服務與網站架構的發展史
    • API First Workshop 設計概念與實做案例
      • API First #1 架構師觀點 - API First 的開發策略 - 觀念篇
      • API First #2 架構師觀點 - API First 的開發策略 - 設計實做篇
    • 基礎建設 - 建立微服務的執行環境
      • Part #1 微服務基礎建設 - Service Discovery
      • Part #2 微服務基礎建設 - 服務負載的控制
      • Part #3 微服務基礎建設 - 排隊機制設計
      • Part #4 可靠的微服務通訊 - Message Queue Based RPC
      • Part #5 非同步任務的處理機制 - Process Pool
    • 實做基礎技術 API & SDK Design
      • API & SDK Design #1, 資料分頁的處理方式
      • API & SDK Design #2, 設計專屬的 SDK
      • API & SDK Design #3, API 的向前相容機制
      • API & SDK Design #4, API 上線前的準備 - Swagger + Azure API Apps
      • API & SDK Design #5 如何強化微服務的安全性 API Token JWT 的應用
    • 建構微服務開發團隊
      • 架構面試題 #1, 線上交易的正確性
      • 架構面試題 #2, 連續資料的統計方式
      • 架構面試題 #3, RDBMS 處理樹狀結構的技巧
      • 架構面試題 #4 - 抽象化設計;折扣規則的設計機制
    • 架構師觀點 - 轉移到微服務架構的經驗分享
      • Part #1 改變架構的動機
      • Part #2 實際改變的架構案例
    • 案例實作 - IP 查詢服務的開發與設計
      • 容器化的微服務開發 #1 架構與開發範例
      • 容器化的微服務開發 #2 IIS or Self Host
  • 系統評估
    • RPA 與 WebAPI 評估
    • 數位轉型:從現有系統到數位化的未來
    • 數位轉型:從現有系統到數位化的未來
  • 面試
    • CV_黃子豪_2024
    • HR 問題集
    • .NET 工程師 面試問題集
    • 資深工程師 問題集
    • 資深開發人員 / 技術主管
    • 題目
Powered by GitBook
On this page
  • Part #2 實際改變的架構案例
  • 實際轉移案例
  • 一窩蜂驅動開發!!
  • 回到微服務化,我們最後做了那些改變?
  • 1. Content Service 從單純的 CDN 升級為 Courseware Service:
  • 2. 採用 SVN (subversion) 來取代原有的 file server。
  • 3. 系統之間的通訊方式,採用 Message Queue
  • 小結 - 微服務架構規劃的要點
  1. 微服務架構
  2. 架構師觀點 - 轉移到微服務架構的經驗分享

Part #2 實際改變的架構案例

PreviousPart #1 改變架構的動機Next案例實作 - IP 查詢服務的開發與設計

Last updated 1 year ago

實際改變的架構案例

實際轉移案例

講到: 轉移到微服務架構是有條件的,基本門檻還達不到的話就貿然轉移到微服務 架構是很冒險的。微服務架構先天就較複雜,在開發、部署及維運這三個部份的要求都比單體式架構的 APP 來的高。因此我過去的經驗中, 我是採取比較保守的策略在做這件事。什麼叫 “保守”? 意思是我會先花很多時間研究及了解微服務架構的優缺點,也會花時間逐一進行 POC 驗證每個改變的環節是否都能順利進行,包含開發的技術,還有團隊的流程與系統執行的環境等等,而不是冒然的就把既有的服務整個打掉重寫。

因此,我把既有的服務架構作了規劃,安排如何一步一步地進行微服務化。許多微服務化的架構建議我並沒有全面採用,因為我們的服務規模還不夠大,投入在這些環節上,短時間只會造成困擾,而不會有具體的改善,這類狀況我只要確保現在的架構不會成為將來進一步改進的阻礙就可以了。

在開始之前,先來看看我面臨的舊架構系統概況跟規模吧! 我試著盡量具體的量化 “規模” :

img

這服務是人資領域相關的系統,用於數位學習及人才發展的管理。這類系統的特色就是表單特多,流程複雜,每一頁都是滿滿的表單跟欄位要填寫 或是顯示。這系統的特性造成程式碼之間的耦合度過高,維護的成本居高不下,因此降低維護的複雜度是主要目標。傳統的作法,例如模組化等等其實 都有用上了,不過仍然在系統運行時碰到一些挑戰,例如更新升級不易等等大型單體式架構的常見問題。另外,這系統需要同時提供單機版本的 建置 (private cloud), 同時也提供雲端服務及代管模式 (SaaS, public cloud)。讓軟體架構同時適應這兩種 hosting 環境也是改版 的目標之一。

這是改變之前的系統架構圖。基本上就是很傳統的設計,主要是由 WEB + DB 兩種角色組成的典型架構。其中商業邏輯的部分雖然有適當的切割 (用 library 與 component 的型態),但是在執行期間仍然是被放在同一個 process,部署的架構上並沒有明確的將之獨立出來。除此之外, 因為系統包含數位學習,需要管理大量的教材內容,因此多了 file server 與 content server 的延伸架構。

各位可以想像一下,這狀況其實完全命中了微服務架構想解決的問題點啊! 這麼大規模的 code base, 改了任何一行就需要整個服務重新部署, 我們在這樣的基礎上導入了 CI / CD, 但是冗長的編譯時間也導致 CI / CD 的作用大打折扣。另外,商業邏輯也包含在 WEB 內,任何一個 模組失效 (如 out of memory exception 等等) ,都會導致整個系統掛掉…。

在當時,我歸納了整個系統架構上有四項主要的問題等著被解決:

即使如此,微服務架構仍然不是萬靈丹,因為前面有提到,微服務架構是有進入門檻與代價的啊! 經過評估之後,我們決定按照實際問題的影響程度, 逐步進行改善。對我們當時的狀況而言,最優先處理的是 維護困難、還有 雲端化困難 這兩項。而 部署困難 則是緊接著雲端化 問題解決後緊接著會面臨的問題,因此也一併考慮在內。因此我們著手進行微服務化架構的改進,切割的策略及進行順序都按照這重要性來安排。

一窩蜂驅動開發!!

我只能說,這篇文章講的實在太傳神,太到位了! 甚至文內舉了幾個常見的例子,就包含了微服務架構 XD,根本完全命中我擔心的狀況啊…

其實多看看別人的解決方案,多看看新的技術,並不是壞事。糟糕的地方在於對自己過度自信,聽到很棒的新技術就相信自己能 100% 駕馭, 不顧後果的就往前衝,往往會讓自己 (及團隊) 陷入進退兩難的困境。通常會陷入這種 “一窩蜂” 的困境的人,都有幾種特質:

  1. 好奇心強,喜歡新的技術。

  2. 高度自信,認為自己無所不能,或是高估團隊的能力。

  3. 過度樂觀,缺乏替代計畫。

  4. 過於躁進,未做仔細評估就決定執行。

  5. 過於熱血,追求新技術的衝動,遠高於解決問題的企圖。

其實,這幾個特色並不算是缺點,甚至很多成功的人都會有這些特質。有往前進的動力是很好的,危險的是過於衝動及躁進的態度,沒有搭配 良好的執行計畫,才是致命傷啊! 過程我就不多說,文章裡面其實已經講得很精采了 XDD,我針對主題 (導入微服務架構) 拉回來討論:

因此我採納了其他微服務的大師及成功案例的作法,改採 “重構” 的策略,逐步的把系統調整成微服務架構。系統太大,就把他重構切割為幾個小系統。 不好切割? 那就先重構 source code, 將 code 調整為較好切割的架構 (例如透過 interface 來使用 library 或是 component)。並且在那之前, 我花了不少時間,針對我有興趣的技術,做了各種 POC 及驗證,先用最短的時間,確認這些技術真的能夠解決我們面臨的主要問題。

這正好符合這篇文章講到的幾點避免陷入一窩蜂的做法:

快速測試 (Spikes) - 我做了非常多的小型 POC,每個都是針對我最在意的問題,寫一段驗證的 code, 確保過程跟我想像的是一致的,真的 能解決問題才結束。以我的例子來說,對我們的系統及團隊來說,微服務化我最在意的是 API 的相容性怎麼維持? 拆解成大量服務的話怎麼 解決部署的問題? 熱門的容器化技術,是否能對我們這種 pure .net develop team 發揮功效? 過程中我甚至花了一個禮拜,把其中一個小模組 親自改寫成微服務架構 + 容器化部署,包含 web api, sdk, 以及 schedule job 等部分,都改成用 windows container + asp.net mvc webapi 來實作。這部分的過程,我會在之後另外寫一篇文章介紹過程跟心得。

在投資報酬率很高的時候下手 - 書上講的 guidelines 有很多條,但是不是每條都對我的現況有幫助。我花了不少時間了解每條指引準則, 是為了解決甚麼問題? 同時檢視看看這問題是否是最困擾我們的問題? 重新思考及排序之後,我優先挑選對我們幫助最大的幾點做準備及改善。 而非清一色無腦的照著書上講的方式來進行。

經驗 + 有札實技術背景的人 - 這項其實講的就是,團隊裡要有個稱職的架構師啦!

這… 容我自誇一下… 哈哈,整個過程我最自豪的地方,就是過去學了那麼多 OOP,Design Patterns, 還有一堆軟體工程的知識及技巧, 終於派上用場了! 在單純專案開發,或是功能開發的階段,這些流程或是軟工領域的技能常常會被忽略,但是在碰到這種架構層面的改變時, 我過去累積的這些能力就幫了我很大的忙。

不說別的,光是重構的技巧 + 單元測試的觀念,就讓我閃開不少地雷,切割微服務的過程中順利許多。表面上我好像浪費了很多時間在做改 code 以外的事情 (如 POC,花時間先整理 Code,寫測試,同時比對新舊架構執行結果等等),但是換來的好處是整個過程都很可靠很平穩地進行。 雖然不見得是最快速度,但是是風險最低的做法,同時過程中隨時都能維持可出貨可使用的狀態。這些都要歸功過去累積的知識及經驗。

奉勸各位 (尤其是技術決策者),看到我寫的這系列微服務架構的文章,千萬別太興奮就想要你的團隊一頭衝進來啊! 做這種事情,最關鍵的 角色就是團隊裡要有個稱職的架構師。架構師最重要的職責,就是負責平衡整個系統的各個環節。微服務架構,其實是過去十幾年來,分散式系統 與雲端服務等等技術的縮影,架構上的複雜度是很高的,因此要適度借重各種既有的服務、元件、基礎建設來降低使用微服務架構的門檻。但是 要能熟練地運用這麼多東西,如何挑選及組合,就是最重要的事情了。

經驗不足的 tech leader, 往往會高估團隊對技術的掌握能力, 貿然採用無法掌握的架構時,就會發生這篇文章描述的狀況 - 一窩蜂 XD… 這時你能做的,就是先做好各種事前驗證 (POC),盡早掌握這技術架構的可行性,還有盡早掌握可能面臨的風險在哪裡。如果要失敗,那就在 POC 先 失敗吧! 很多軟體工程的方法論鼓吹 Fast Fail 的道理就在這裡。

稱職的架構師,除了挑選及規劃架構的能力之外,還要具備良好的 coding 的能力,要好到什麼程度? 要能把你腦袋中想像的解決方案,實際 用 code 把核心部分寫出來,同時盡可能簡化或是略過非必要的部分。這能力至關重要,因為這是架構師如何能跟團隊溝通的重要工具。對外, 你可以用這樣的技能做出 POC,跟老闆與客戶證明你的構想與架構是可行的,對內,你則能給團隊信心,同時取得團隊對你的信任,眼見為憑, 工程師們眼裡只有 code, 只有親眼看到你能寫出 code 證明你的概念可行,才會相信你後面的判斷及規劃。

架構師要有足夠的 coding 能力,原因就在這裡。這一切對團隊的幫助,都不是其他外面請來的技術顧問能夠取代的,因為這是要完全融入團隊 例行的開發流程。架構師擁有夠好的 coding 能力,就能用工程師共通的語言 - source code, 跟團隊其他技術人員溝通,也能透過 source code 指導團隊其他成員。這種事只要你經歷過就知道,再多的文件,都不如一段真的可執行的 source code 來的實際, 可以讓你底下的工程師了解你 到底要表達什麼。

想了解架構師到底要做什麼,可以參考這幾篇,講得很到位:

因此,如果你們家的架構師是不寫 code 的 (不管是不會寫,還是不想寫都一樣),那麼上面講的事情,他應該很難做到… 你就別指望他能做好 這件事了。很多管理的文章也都講到,主管不肯親自動手做,不肯把手弄髒,是無法做好事情的。這句話套用到架構師身上也適用。

套句鄉民的句型: 好的架構師是很重要的,沒有的話快點去找一個 XD

補個我常被問到的問題:

有人問我,若團隊內沒有架構師,能否聘請技術顧問來取代?

我的答案是: 能找到跟架構師 (上面描述的) 有同等能力的技術顧問,當然是件好事。不過我判斷的標準也一樣,外部顧問如果沒辦法 從過程中引導團隊進行,而是只出一堆文件與規劃,但是一行 code 都寫不出來 (或是不寫),那對團隊一樣是沒有幫助的。如果你不確定 顧問是否符合你的期望,也可以試試在正式合作前,先從小的案子,或是企業內訓等等方式開始合作,從中觀察就可以得知。

雖然在執行這改版計畫時,我的身分是 CTO,屬管理職,不過在這過程中我同時身兼架構師 (當然是很愛寫 code 的那一類), 才順利的 跨過微服務的門檻 (不然也就不會有這麼多篇文章了)

回到微服務化,我們最後做了那些改變?

一窩蜂完畢,回到主題: 微服務化。回頭來看看我面臨到的問題與當時的系統架構,還有我對新架構的期望。原本的架構我再重貼一次:

典型的 WEB + DB 架構,WEB 可以 scale out, 配合數位學習有大量內容管理需要,後端搭配 file server,與類似 CDN 的分散式部署 方式 (file sync based) 來解決流量問題。

這樣的架構其實蠻落伍了,最大的問題在於,這架構的思維完全是早期企業內部的網路架構,完全是 intranet based 的思維設計出來的架構。 其實這也沒什麼不對,因為這是 2000 年就規劃出來的架構啊 XD (是,也是我設計的… Orz)。這樣的架構最大的缺點就是 CP 值很低,所有 關鍵的環節都是自己來,建置與維護成本很高。雲端時代的優勢完全沒有用到啊,廣大的 open source 資源也沒用到啊,更別提微服務架構了..

過程中其實我想過很多符合 “熱門” 技術下的架構規劃,不過都被我自己否決了,因為我發現我自己陷入了一窩蜂的坑了啊… 後來我重新思考 熱門技術到底能帶給我甚麼優勢? 我才逐漸掌握到我需要的架構是什麼。我先歸納這幾點,後面再逐一說明:

  1. 服務的細粒度要夠高 - 慎選既有系統的切割方式

  2. 部署方式要夠靈活 - 能同時適應企業內部環境,也能適應混合雲 (public cloud + private cloud) 的環境

  3. 要能充分運用 cloud service 的特性,包含 public cloud 無窮盡的運算資源,也要考慮 cloud service 的商業及營運模式

這裡每一項拆開都可以再寫個一兩篇文章 @@,我先跳到結果,這張圖是調整後第一步要進行的架構:

這是我初步規劃,調整後的架構。主要的改變有幾個地方:

1. Content Service 從單純的 CDN 升級為 Courseware Service:

原本的 content service 很陽春,就是個處理靜態檔案的 web app, 做個簡單的 url routing, 自動選擇正確版本目錄的 asp.net mvc web application。 目錄同步的功能就用現成的工具替代。重新調整之後,這服務沒有被切割成更細微的服務 (這樣還能再切什麼出來?),反而把部分跟教材相關 的功能,從主系統那邊合併過來,甚至替他配置一個專屬的 SQL database,整個運作的規模變得較大較完整了。這邊主要考量是,微服務應該是個能獨立自主運作,能夠把某一件事完整地做好,同時要能夠集中部署在公有雲為主要考量 (我們都放在 Windows Azure, 架構也都配合 Azure 做過最佳化調整)

微服務的概念中提到一個很重要的觀念,就是每個服務該要有 獨立自主性,能夠獨立部署運作,其他服務都要透過 API 來跟她溝通;服務本身 同時應該要 小巧,專注做好一件事情。我從這角度思考,content server 要做好的那一件事情到底是什麼? 單純的分流? 還是做 edge server (CDN)? 這些應該不是他主要的目的。我的構想中 content service 應該要做好的,是對客戶要做好教材代管服務才對。主系統應該要能有效率地 把教材內容委託給 content server 運用,使用者若能透過類似 oauth2 那樣的認證機制,不論來自哪個系統,content server 若都能服務 好這個使用者,讓他順利的完成教材閱讀,同時做好學習紀錄與考試,之後有統一的 API 能夠讓其他系統來取回學習歷程與紀錄回去做後續的 管理,這才是我心目中理想的微服務啊。

因此,原本單純的 content service, 就從靜態網站升級為具備下列功能的完整服務了:

  • content publish api: 提供主系統遠端做教材管理及傳遞的 api

  • 與主系統之間的使用者認證資訊傳遞,還有 session 的管理

  • 內容的使用 (閱讀,追蹤紀錄,計時 or 計次等所有計費所需紀錄)

  • 處理 HLS + AES 的加密與金鑰的管理

2. 採用 SVN (subversion) 來取代原有的 file server。

現在把視線移回主系統本身。要有教材傳遞給 content service 之前,主系統本身必須先做好教材的儲存與管理。在這領域裡, 其實有很多實作上的難題,包括:

教材的版本控制 - 過去就是在目錄結構裡,切一層出來當作版本號碼,每個版本都存有一份該版本完整教材檔案,管理不易,且儲存空間使用效率很低。 理想的狀況是儲存時能夠做到壓縮及差異儲存。一份教材動輒 500mb, 但是兩個版本之間可能只是修正幾個錯字,或是替換幾段文字。 儲存方式是否最佳化,會極大的影響佔用空間。若是搬移到雲端空間 (例如: Azure storage), 費用是按照每個月每GB付費的,影響更大。 儲存方式必須能同時符合這幾項要求。

教材的同步與傳輸 - 過去採用 IT 的各種檔案同步的工具,不外乎是 robocopy, DFS… 等等,大都需要透過 SMB 的通訊協定。這類協定開放到 internet 上面會面臨到資安的問題。另外單純的目錄同步服務也很難配合系統自動化,只同步某份教材或是某個版本。整個機制在自動化管理 並沒有很簡潔的做法。若在考慮傳輸上的安全問題,需要配合用 HTTP 才能突破防火牆,有時則需要採用加密的連線 (HTTPS or SSH), 甚至是極度簡化的單機版本,可能要跳過網路層,直接 access local file system 都有可能…。

教材庫的維護 - 為了改善前面幾點問題,通常都要設計專屬的儲存結構,以及索引的建立與維護方式。這些設計做下去,將來在系統運作一段時間後,就會 面臨儲存庫的結構檢查,一致性檢查與修復,資料備份,還原,異地備援等等問題都得自己來。一般軟體開發團隊很難將自己設計的儲存庫 實做到這麼完整的地步。

因為有這些需求,我本來想找些其他分散式檔案系統來解決這問題,或是其他現成的內容管理系統。不過看來看去都有點殺雞用牛刀的感覺… 直到某天,我才想到,為何不直接用 developer 最熟悉的版控系統? 經過一連串的 POC 與研究,證實 SVN 能同時解決我這些需求之後, 這時 subversion 變成我的首選。不採用當紅的 git, 是因為 subversion 集中式的架構更適合我的需求啊,svn 在運作模式上也更貼近 我的需求,同時他也發展得夠久夠可靠了。只是單純的挑當紅的 git, 其實對我並沒有甚麼幫助。

3. 系統之間的通訊方式,採用 Message Queue

過去系統架構單純的時候 (複雜度都在單一一套 web application 內部),沒甚麼這種跨系統之間的溝通問題。大概就 WEB + DB + JOB 就可以解決完所有的事情了。不過當你切割成越來越多獨立的服務時,跨越系統之間的通訊問題就來了。最常見的就是用 HTTP + REST API, 不然就是 share file / share database, 並且不斷地用 pooling 的方式偵測異動來進行通訊。不過缺點實在不少啊,隨便舉幾個都是坑啊:

被動的呼叫/回應模式 - 缺乏推送通知的能力 服務如果只實作 REST,那就只能被動的被呼叫。沒有主動 call back 的能力。甚至某些動作暫時失敗,你想要實作 wait 30 sec 後 重新執行一次也沒辦法,因為你總不能等 30 sec 時,叫 user 的瀏覽器在那邊轉轉轉吧? 若你想實作一些簡單的 background job 也沒辦法。 通常 HTTP Request 在 server 端執行太久,就會被 web server 強制中斷執行了。例如: IIS 預設就有 90 秒的 Script TimeOut 限制。

這問題可以靠排程解決,不過排程的時間精確度大概只能到分鐘的等級,而且密集的執行,其實就是 pooling 的模式,會對效能有很大的影響。 你要越高的時間精確度,就要付出越高的效能代價。現在的使用者都要求要 “即時” 回應,如果驗證簡訊要等個一分鐘才寄出,應該會收到一堆 客訴吧~

只能同步 (sync) 通訊 這點尤其在牽扯到交易時最明顯。交易系統常有這種模式,下單後續的處理及檢查很冗長,要花很多時間。這時 只能同步通訊的話就很頭痛,呼叫端 (caller) 必須等到動作完成後才能繼續下一步的動作。若通訊機制能支援非同步通訊的話, 呼叫端就可以不必一直在那邊等待了。

不過請留意,也許有人會這樣想:

“那我用 C# 的 async / await 不就可以了嗎?”

請留意,C# 只是在語法層面上讓你實作非同步的操作,但是兩個服務之間的連線與通訊仍然是同步的,只是你的 code 不用一直在那邊等而已。 兩者有甚麼差別? 第一: 連線還是一直占用,直到呼叫結束為止。第二: 執行到一半時若碰到 IIS restart, 或是 App Pool 回收等等狀況, 這個連線仍然會被中斷,而且無法回復。我們需要的是在通訊機制層級的非同步方案。

以這個交易的案例來說,除了非同步通訊之外,若被呼叫方能先把訊息儲存起來,再按照順序取出執行,那整個系統的運作會更有效率,也可以 提高可靠度。因為這麼一來,取出執行失敗的話,就還能有機會重新嘗試一次。這也是我這次主要的改善方向: 改用 message queue。

不適合長時間的通訊 HTTP 很多情況下是不適合長時間通訊的。他的設計基礎就是建立在很多大量小型的 Request / Response 的通訊模式。長時間的連線,通常 會佔住 connection pool, 如果 web server connection 數量達到上限,那其他的 Request 就得被迫排隊,或是根本無法進來了。

另外長時間的通訊,也會導致通訊很不可靠。Web 的設計大都是無狀態的,這類長時間的連線,往往會阻礙負載平衡的進行,也會阻礙部分 Web Server 的暫時離線、重新啟動、或是回收等等動作。長時間的通訊,或是需要推送的機制時,都可以用前面的技巧替代。例如改成 非同步通訊,執行完畢再用推送的機制把執行結果傳回原呼叫端。

點對點通訊,不支援廣播或是發布訂閱模式 HTTP 是很典型的點對點的傳輸協定,架在上面的 REST API 就是 client - server 的呼叫。如果通訊系統的需求複雜一點,要用廣播 (client 送出訊息,多個服務都要共同去接收處理) 機制的話是很頭痛的。這類的應用可以建構出跨越服務的事件處理機制 (event handler)。 如果跨越整個系統的事件處理機制夠可靠的話,這甚至能處理跨越不同資料庫或是儲存系統之間的交易。

跨服務的通訊其實考量很多,這些在後面的微服務基礎建設會統一介紹。我這次的微服務化野心還沒那麼大,只要先處理可靠度 及非同步通訊而已。因此這次在關鍵的任務部分,底層直接採用 Message Queue (MSMQ) + Worker 建構起來的 RPC 機制,來取代 直接呼叫 REST API。

小結 - 微服務架構規劃的要點

以上這些調整,最終的成果就是這張系統架構圖了。你會發現,很多微服務架構指南提到的準則,我並沒有每一條都照表操課。我只挑選真正對我們 團隊有足夠的效益,我才採納。其他價值不是那麼高的設計,我就放在心裡,隨時優化系統,只要做好準備,將來需要時可以用最快速度重構就可以了。 真的要嚴格的檢視,我其實還沒做到微服務的架構,頂多只是做到 “準” 微服務架構而已,有人稱作 microservice ready, 或是稱作 miniservice ..

雖然主題一直圍繞在 “微服務” 身上,不過這個案例其實還不夠到位,只是朝向微服務在調整架構的過程而已。但是我想在台灣,這才是大部分 團隊面臨的狀況吧! 因此我特地拿實際的案例,讓大家了解我做這件事的思考方向與過程。其中最關鍵的部分永遠在如何讓服務的架構配合你的 商業流程或是組織流程。兩者之間能夠有效的對應,你的系統才能順利地跟著你的組織一起成長改善。

從這逐步演化的角度來看,我認為這階段最重要的架構考量有這幾項,想清楚就可以繼續往下個階段進行了。分別是:

現有系統如何切割成獨立服務? (例如: 我舉的案例裡的 content service)

整個微服務化的藍圖,有哪些地方能改採用成熟的第三方服務替代? (例如: 我用 subversion 取代原本的 file server)

整個微服務化的藍圖,有哪些必要的基礎建設? (例如: reverse proxy, message queue 等等)

這些考量不需要一次到位,但是架構上的規畫以及執行順序要先想清楚,才不會做到一半又得打掉重練。所有架構師要考量的要點,永遠都包括 這一條 “Think Big, Start Small.” 先想好你期望你的系統發展成甚麼樣子,在過程中你才知道有哪些環節是需要改善的,需要改成甚麼樣子。 你可以帶領你的團隊逐步向目標靠近,而不會總是修修改改搖擺不定,過了幾年系統仍然在修修補補毫無進展。

–

在這邊也感謝當天到現場參加的朋友們,給我平均 6.59 分的滿意度 (滿分 7.0 分), 有任何意見或看法, 也都歡迎在這邊討論!

原本想說這篇應該可以帶到為何要選擇容器化部署了,沒想到寫著寫著又寫太多了 @@ 下一篇會繼續聊聊微服務的基礎建設,還有容器化的部署考量,敬請期待 Part 3 XDD

img
img

回顧這決策的過程,我覺得 “” 最能描述我當時的心境了! 這是在事後才讀到的文章,不過這篇文章講的內容完全就是我當初思考的啊! 不分享不行,我特地花了點篇幅來介紹這篇文章要講的內容…

img

原文:

img

前面才說到,微服務架構的進入門檻是很高的,這點會讓過度樂觀的人更容易掉入陷阱。我如果早個五年十年來經歷這些事情,我可能會毅然決然的 決定把整個架構砍掉重練 (Orz, 馬上中槍)。不過現在的經驗告訴我,沒事千萬別丟掉現有的 source code 從頭改寫。之前分享過一篇文章就是 在講這件事: 。舊的 code 再怎麼不堪,至少它的邏輯是符合使用者期待的,只是可能會伴隨著很糟的效能、很差勁的可靠度… 等。用新的架構改寫,的確可以一勞永逸的 解決這些問題,不過所有的系統開發案都一樣,你終究需要一段時間,不斷的經歷測試->修正->測試… 的循環,bugs 才會逐漸下降,系統的品質 才會逐步提高到可接受的水準。砍掉重練的話這部分是很難速成的啊! 這時不論解決了多少其他問題,你的新系統終究無法立即上線,專案終究必須 度過很長的一段黑暗期…

img
img

與主系統之間的授權管理 (參考這篇: , 2016/12/01)

當這些都完成後,就商業的角度來看,content service 就不再只是個處理頻寬問題的解決方案了,而是提升為能負責服務用戶所有教材相關 需求的獨立服務,可以是我們整個平台中的一個重要服務,也是邁向 PaaS (platform as a service) 的關鍵之一。跟前面講的一樣,這其實 也算不上是新觀念了。古早以前我在學物件導向設計時就看過這原則: Single-Responsibility Principle,觀念上是相通的,只是過去 OOP 的範圍主要是應用在物件與類別的設計規劃,而套用到微服務,則是組成整套系統裡的每個個別服務該如何設計規劃而已。 順手貼個 2011 的文章:

於是這部分也被我切割成獨立的服務了。只是這次這個服務並不是我們自己開發,而是直接找現成且成熟的系統: subversion 來使用。不但有 全球上億開發人員的使用經驗背書,穩定可靠的 API,完整的文件 (Deployment Guide / Maintainess Guide …) 等等工具樣樣不缺, 連 .NET 版本的 API 都有很完整的實作 () 可以使用。對我而言,SVN 就像是專門儲存教材的 database,專門針對檔案的版本管理,同步,儲存等等操作做最佳化的服務。我的團隊只要熟悉基本的 svn 與 svnadmin 指令,就能完成絕大部分的 儲存庫維護的動作,上面列舉的功能每樣都能完美達成…,實在沒甚麼好挑剔了 (即使她已經是個古老的版控系統了)。我想這樣的功能, 自己的團隊,砸下幾百萬的經費,投入一年的人力也做不到這樣吧?

這篇文章的內容,其實我在 2017/02/22 那個場次有現場分享過這篇的內容,我補充一下相關的連結,方便大家參考:

投影片分享

投影片分享 (含討論)

主辦單位 也有分享

這篇文章: 一窩蜂驅動開發
一窩蜂驅動開發
程序员,为什么千万不要重写代码?
軟件架構師是什麼?他們應該寫代碼嗎?
2014-09-11 如何培養架構性思考 (談軟體架構師必經之路) - 投影片分享
是什麼讓軟體架構師成功?
API & SDK Design #5, 如何強化微服務的安全性? API Token / JWT 的應用
亂談軟體設計(3):Single-Responsibility Principle
SharpSVN
DevOps Meetup #4
SlideShare
Facebook
DevOps Taiwan
活動紀錄
Part #2
上一篇