在這個硬體成本不算高的年代,記憶體的使用通常都略微不那麼謹慎;往往在宣告數字型別時不會太謹慎(還是剛好我遇到的都…),例如只有short 需求卻宣告成 int 這種狀況屢見不鮮。

若要好好地控制記憶體使用量,避免溢位的需求就要特別注意,尤其這種狀況通常發生在執行期,log也可能也無法完整紀錄當時狀況,因此 Checked 語法就派上用場了。

1
2
3
4
short shortNumber = 32767;
Console.WriteLine($"Org short number: {shortNumber}");
shortNumber += 1;
Console.WriteLine($"Plus 1 to short number:{shortNumber}");

顯示結果如下:

1
2
Org short number: 32767
Plus 1 to short number:-32768

明明只有加1卻出現了意想不到的數字。為了避免這種情況發生,可以使用Checked語法來做檢查,至少如果有問題會先彈出exception。

1
Console.WriteLine($"Plus 1 to short number:{checked(shortNumber+=1)}");

結果是直接跳出exception並告知以下結果:

1
Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow.

當然我們也可以預先使用try catch來攔截相關的錯誤

Read more »

環境準備

這篇主要是講在mac os下,.Net core 的程式如何連線至MySql資料庫。需要具備的工具如下

  • MySql
  • .Net core 2.1 or later
  • MySql workbench (option)
    這套軟體是Mysql的管理GUI,如果習慣使用terminal的就不需要

安裝Mysql

這個基本上毫無難度,除非不熟mac的使用者可能會需要學習如何安裝程式。
特別要注意的是安裝後要從“系統偏好設定”裡面開MySql的服務,如果沒看到的話,就重啟OS即可。

alt
alt

習慣使用指令的人也可以直接到安裝目錄開啟

1
2
# cd /usr/local/mysql/bin
# sudo ./mysql -u root -p

建立資料庫/資料表與資料

1
2
3
4
5
6
create database TestConn;
use TestConn;
create table Connection(ConnStr varchar(100), Remark varchar(100));

insert Connection(Connstr, remark) values('conn1', 'remark1');
insert Connection(Connstr, remark) values('conn2', 'remark2');
Read more »

.Net Core 2.0 之前

在 .Net core 專案底下編譯出來的只有 dll 與 json 的設定檔,有時候一些情況下還是使用 .exe 來執行 console 專案會比較方便。

.Net core 2.0 以前必須要在 csproj 裡面設定這個屬性,並且指定相對應的 os

1
2
3
<PropertyGroup>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>

上述就是建置出可在 win10 x64執行的 exe檔案。

.Net Core 2.0 之後 (Terminal Command)

當然也可以執行在terminal 執行輸入指令

1
dotnet publish -c Release -r win10-x64

-c 是建置的configuration,預設資料夾是 Debug
-r 是建置目標的 framework,就是本篇文章的目的

Platform 清單

Read more »

交換器(Exchange)是什麼?

當訊息寫入RabbitMQ時,並非直接將訊息寫入佇列中,而是透過交換器(Exchange)將訊息正確分派到佇列中,而依據就是訊息自帶的RouteKey是否與BindKey相符合;若完全沒有符合的佇列,則會自動遺棄該訊息。

交換器有哪幾種?

常用的交換器有四種 Direct, Fanout, Topic and Headers.

  • Direct: 預設的模式,即直接將訊息分配到 RouteKey 與 BindKey 完全相同的佇列上。
    Case1: BindKey: “log.info
    log.debug -> 不符合
    log.info -> 符合
    log.infomation -> 不符合
  • Fanout: 顧名思義就是將此訊息分配到每一個佇列上,等於是複製了n次。若設定fanout的話會自動忽略 BindKey與RouteKey。
  • Topic: Topic是較常用也是靈活度最高的模式,有點像是.net的routing概念,只要符合規格的RouteKey就會被傳遞到正確的queue。
    特殊符號分別是: * (一個任意字)與 # (零以上個任意字)。

    Case1:

    1
    2
    3
    4
    5
    BindKey: "*I.am.*"
    I.am.boy -> 符合
    I.am.girl -> 符合
    I.amNot.girl -> 不符合
    I.am.boy.too ->不符合

    Case2:

    1
    2
    3
    4
    BindKey "#.strong"
    He.is.strong -> 符合
    Not.strong -> 符合
    I.am.not.strong.neither -> 不符合
  • Headers: 從訊息中的header與BindKey做批配比較,並寫入queue中。這部分我也很少用,之後有特別研究再來補上怎麼使用。

    使用上的效能當然還是 fanout > direct > topic,但我認為除非在很極端的狀況下,否則比較這個的意義並不大,畢竟工具的使用還是以符合需求為主。
    另一點要注意的是RouteKey長度限制為255 bytes。

Fanout模式的演示

首先我們在宣告Exchange時將type指定為 “fanout”,當然在訂閱端也是需要的,程式碼一樣就不再貼上。

1
channel.ExchangeDeclare(exchange: "logs", type:"fanout");

其他部分沒有改變,將專案建置好後,開啟兩個訂閱者程式,然後執行Sender.exe以fanout模式送出一個訊息,就可以看到兩個視窗幾乎同時收到該訊息,且進行處理。
alt

程式範例檔

Read more »

交換器(Exchange)的路由(Routing)功能

現在我們已經更正確的使用交換器功能,而非將訊息直接寫入佇列,為什麼需要這樣做呢?因為RabbitMQ交換器擁有路由功能,當訊息進入交換器時,可以透過種類來分配到不同的佇列裡,以官網的例子就是LOG處理機制。

LOG的重要程度可大致分為 Debug, Info, Warning, Error, Fatal.
Warning以上要分配到 Queue1
Debug與Info 等級則要放到 Queue2

這樣在宣告佇列時就可以綁定到該分配器,但指定不同QueneName, RouteKey. EX:

1
2
channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "INFO");
channel.QueueBind(queue: queueName, exchange: "direct_logs", routingKey: "WARNING");


以下會用publisher分別發送兩個訊息到交換器,並指定不同的RouteKEY

Publisher

宣告兩個訊息並指定RouteKey分別為”ERROR”與”INFO”

1
2
3
4
5
6
7
8
9
10
11
12
channel.ExchangeDeclare(exchange: "direct_logs", type: "direct");
var msg_error = $"This is Error msg.";
var msg_info = $"This is Info msg";

channel.BasicPublish(exchange: "direct_logs",
routingKey: "ERROR",
basicProperties: null,
body: Encoding.UTF8.GetBytes(msg_error));
channel.BasicPublish(exchange: "direct_logs",
routingKey: "INFO",
basicProperties: null,
body: Encoding.UTF8.GetBytes(msg_info));

Subscriber

Read more »

佇列的功能

當系統已經繁忙逐漸無法及時回應需求,或是需求本身需要一段時間處理,以及複雜的HTTP請求這些狀況都很適合搭配訊息佇列來做處理。
這邊用sleep來模擬處理很久的訊息。

Publisher (範例命名為Sender)

基本上與範例一的內容一樣,就不多著墨。

Consumer (範例命名為Receiver)

為了模擬處理很久的訊息,在收到訊息後將內容逐一字元顯示。

1
2
3
4
5
foreach (var i in message.ToCharArray())
{
Thread.Sleep(150);
Console.Write("{0}", i);
}

其他內容也與範例一是相同的,如果有不理解的可以回頭看第一篇文章。

為了更幫助理解,建議可以執行兩個 receiver.exe,再分別多次執行 sender.exe 這樣看以看多個訊息進入佇列後,每個 receiver 在繁忙中如何分配處理。

訊息處理確認機制(Acknowledgement)

Read more »

什麼是RabbitMQ

RabbitMQ是訊息的中介層,可以想像是一個幫你保管、處理的佇列,只要發布者(Publisher)將訊息寫入後,該訊息會被放入指定的佇列,等待接收者(Consumer)的拿取。
特性大概有以下幾種:

  • 由Erlang開發
  • 符合進階訊息佇列協定(AMQP)
  • 支援非常多種語言與平台
  • 訊息接收、處理的可靠性
  • 高度靈活的路由功能
  • 高可用性(Availability)
  • 內建監控與管理介面
  • 可建立集群,提昇資料安全與服務不中斷
  • 提供各種插件(plugin)靈活運用

細節會在日後的文章陸續揭露或探討,而安裝方法非常簡單,網路上也有很多範例就不在這邊贅述了。
本文所使用的程式語言是 .NET Framework C#

Hello RabbitMQ

如果是.net core使用者須先建立專案,這邊以console模式當範例,依序建立兩個專案並進入專案加入RabbitMQ.Client package

1
2
3
4
5
6
7
dotnet new console -n Sender
cd Sender/
dotnet add package RabbitMQ.Client
cd ..
dotnet new console -n Receiver
cd Receiver/
dotnet add package RabbitMQ.Client

撰寫Publisher (範例命名為Sender)

  1. 建立連線的物件,hostname目前都是在本機所以localhost即,UserName與Password則需要另外建立。
    若是剛安裝好,預設是guest/guest為唯一且admin帳號。
1
2
var factory = new ConnectionFactory()
{ HostName = "localhost", UserName = "admin", Password = "pass123" };
Read more »