Posts
Node.Js - Getting started
Node.Js 安裝完後,開個 Js 檔來撰寫簡單的 Hello World 程式。
console.log("Hello World"); 然後調用 node 命令並帶入程式位置。
node ${file} 即可運行程式,顯示程式運行後的結果。
再來看一下稍微複雜點的 Hello World。
var http = require("http"); var port = 3000; http.createServer(function(reqst, resp) { resp.writeHead(200, {'Content-Type': 'text/plain'}); resp.end('Hello World!'); }).listen(port); console.log('Load http://127.0.0.1:' + port + ' and watch the magic'); 會在特定 Port 號起一個 http 服務,該服務會回應 “Hello World!” 字樣。
將服務啟動。
用瀏覽器訪問服務的位置,即可看到服務回應我們預期的結果。
read morePosts
Two-phase commit protocol
Two-phase commit protocol 簡稱 2PC,也就是所謂的二階段提交。可用來解決分散式服務架構下各服務之間交易資料一致性問題。
該做法有幾個假設前提:
該分散式系統中,存在一個節點作為協調者(Coordinator),其他節點作為參與者(Participants)。且節點之間可以進行網絡通信。 所有節點都採用預寫式日誌,且日誌被寫入後即被保持在可靠的存儲設備上,即使節點損壞不會導致日誌數據的消失。 所有節點不會永久性損壞,即使損壞後仍然可以恢復。 2PC 會有協調者與參與者兩個角色,參與者就是系統中的服務,協調者負責協調參與者。
流程上可分為兩個階段,一個是提交請求階段(Commit request (or voting) phase),一個是提交執行階段(Commit (or completion) phase)。
提交請求階段是讓所有需參與的參與者決定是否能處理這次的請求。其細部流程如下:
首先協調者會先通知需要參與的參與者做準備 參與者收到通知後做準備 參與者將準備結果告知協調者 提交執行階段會依參與者的回應決定是否繼續請求,並通知所有的參與者,參與者做完對應的處理後回應協調者。其細部流程如下:
協調者匯整參與者的回報 決定要提交還是回滾交易 通知參與者提交或回滾交易 參與者通知協調者完成動作 這邊在交易的提交或回滾協調者會由參與者的回報決定,如果所有需參與的參與者都準備成功,就提交交易。反之,若有需參與的參與者準備失敗,則回滾交易。
整個 2PC 流程做起來會像這樣。
該演算法雖然能解決分散式交易的問題,但因為是阻塞式的演算法,交易存留時間會比較長,會有效能上的問題。
Link Two-phase commit protocol - Wikipedia 二階段提交 - 維基百科,自由的百科全書
read morePosts
DotLiquid - Drops
使用 DotLiquid 做範本渲染時,如果需要使用到非基礎型別當作參數,我們可以為其建立對應的 Drop 型別。
該 Drop 型別繼承自 DotLiquid 的 Drop 型別,在建構子將原型別實體帶入,將原型別具有的成員屬性封裝並開出。
using System.Drawing; namespace DotLiquid.Drops.Model { public class PointDrop : Drop { private readonly Point _point; public PointDrop(Point point) { _point = point; } public int X { get => _point.X; } public int Y { get => _point.Y; } } } 渲染時將參數改成自建的 Drop 型別帶入即可。
... var model = new {points = points.Select(item => new PointDrop(item)).ToArray()}; return Generate(templateContext, model); .
read morePosts
DotLiquid - LiquidTypeAttribute
使用 DotLiquid 做範本渲染時,如果需要使用到自訂型別當作參數,自訂型別可加掛 LiquidTypeAttribute 指定範本會使用到的屬性。
using System; namespace DotLiquid.LiquidType.Model { [LiquidType(nameof(Person.Id), nameof(Person.Name), nameof(Person.NickName))] public class Person { public string Id { get; set; } public string Name { get; set; } public string NickName { get; set; } public Person() { } public Person(string name) { this.Id = Guid.NewGuid().ToString(); this.Name = name; this.NickName = name; } } } 加掛 Attribute 後範本就可以使用自訂型別來渲染。
{% for person in persons -%} hi {{person.NickName}}({{person.Id}}, {{person.Name}})~ {% endfor -%} 渲染時注意要設定使用 CSharpNamingConvention,不然會使用到 Ruby 的命名規則,設定的屬性名稱會被轉為小寫且用底線隔開,會找不到對應的屬性。
read morePosts
DotLiquid - Getting started
要在 DotNet 中使用 Liquid 範本,可先加入 DotLiquid 套件參考。
套件參考加入後,開始撰寫程式部分。
程式撰寫起來很簡單,只要解析範本,然後將範本需要的資料帶進去渲染即可。
... var template = Template.Parse("hi {{name}}"); var result = template.Render(Hash.FromAnonymousObject(new { name = "Larry" })); ... 運行起來就會看到 DotLiquid 將資料帶進範本渲染出來的結果。
最後提供比較完整的使用範例,筆者將範本放在內嵌資源中,從內嵌資源讀出範本、透過 DotLiquid 將範本與資料帶入渲染。
using System; using System.IO; using System.Reflection; using System.Threading.Tasks; namespace DotLiquid.GettingStarted { class Program { static void Main(string[] args) { var result = GenerateHelloWorld("Larry", "Mylin", "Andrew"); Console.WriteLine(result); } static string Generate(string templateContext, object model) { var template = Template.Parse(templateContext); return template.
read morePosts
Saga pattern
Saga pattern 是用來解決分散式服務架構下各服務之間的交易資料一致性問題。
在單體服務的架構下通常會使用同一個資料庫,交易可以直接交給資料庫處理,處理失敗交易資料就會整個還原,不會有交易一致性的問題。
反觀在像微服務這樣的分散式服務的架構下,每個服務都有各自的資料儲存體,資料會被散在不同的服務身上,且商業邏輯上的交易可能需要多個服務協同完成,在這種狀況下交易的一致性無法很單純的交由資料庫處理就好。
像是假設商業邏輯上的交易要依序經過 A、B、C 三個服務,若是處理到 C 服務時失敗,C 服務的資料還原是沒什麼問題的,可直接由資料庫的交易幫我們還原資料。但是對 A、B 服務來說處理是成功的,資料庫的交易已經 Submit 了,也不會知道後面有依賴的服務處理失敗。這時就會有資料一致性的問題產生。
Saga pattern 可用來處理分散式交易或是 Long lived transaction (LLT),會定義商業邏輯上的交易依序要調用的服務,將一連串的服務交易串起。每個服務被調用時會去更新服務的資料庫,接著輪到下一個服務被調用。當錯誤發生時會對調用過的服務做補償還原,像是付過款就退款、建立了訂單就取消訂單、保留了座位就將座位釋出,用以確保資料的最終一致性。
依實作方式的不同又可細分為 Choreography 與 Orchestration 兩種模式。
Choreography 是分散式的處理方式。每一個服務處理完自行去調用下一個服務處理,每個服務自己要知道下一個要調用的服務為何。
服務之間可透過 Rest 或 RPC 直接通訊。
或是透過事件訂閱的方式。
Orchestration 是集中式的處理方式。會有一個管理中心知道商業邏輯上的交易要怎麼去調用服務,會偵測服務的處理,如果服務處理完會負責調用下一個服務,當服務處理出錯會負責調用服務去補償還原。
Saga pattern 實際應用上,為了確保服務重覆調用不會造成問題,可能在實作上得考慮賦予服務冪等(Idempotent)特性,可將交易紀錄存放起來查驗,用以忽略相同的交易觸發,以免重複調用造成重複補償。
另外協調者與服務之間或是服務彼此之間的通訊如果有丟失的可能,設計上可能需考慮是否外加 Timeout 機制,用以判定服務調用是否失敗。且需考慮是否外加背景處理機制,用以處理補償還原,確保補償還原的動作不會因協調者或服務重啟而漏處理。
Link Sagas - Microservices.io
read morePosts
gRPC - Create service with ASP.NET Core
在 .NET Core 3.0 後,我們可透過 gRPC Service 範本建立方案或是專案,如果是用方案範本,除了 gRPC 的 Server 專案外,還會有 Client 的專案。
像是筆者這邊直接透過範本建立一個 gRPC 方案。
方案建立完會看到內含 Server 與 Client 兩個專案,需參考的套件以及要使用的 Proto 檔設定都已經設好了。
編譯檔案時會將 Proto 編譯成對應的程式碼,產生在 obj 下。
{% asset_img 5.png%}
另外是 .NET Core 3.0 的 gRPC Service 已經被整進 ASP.NET Core 去了,只要在 Startup.cs 中的 ConfigServices 將 gRPC 服務開啟。
... public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); } ... 並設定 gRPC 服務對應的處理類別,gRPC Server 就好了。
... public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { .
read morePosts
tree - Install with HomeBrew
在 Mac 下可以透過 HomeBrew 安裝 tree 命令。
brew install tree 可能會得到像上面這樣的錯誤,這時調用指示的命令。
再次嘗試安裝即可。
安裝完就可以正常使用 tree 命令了。
read morePosts
BloomRPC - Install with Homebrew
要使用 Homebrew 安裝 BloomRPC,可以調用如下命令:
brew cask install bloomrpc 安裝完就可以在應用程式這邊看到 BloomRPC。
read morePosts
Docker - Remove all unused local volumes
Docker 用久了本地可能會殘留許多的資料卷。
像是筆者電腦中就殘留了那麼多。
docker volume ls 這時可以透過 volume 的 prune 命令將本地沒在使用的資料卷給清除。
docker volume prune 這邊會顯示清出了多少的空間。
再次查詢做個確認,應該會看到資料卷正常的被清掉。
read more