2019年2月27日 星期三

(書籤) 微服務的管理

微服務在最近幾年蠻盛行的,嗯…或者該說是非常盛行?不過概念上我目前的認知是,它把本來巨大的服務拆解成很多比較小的服務,以達成讓每個比較小的服務容易維護的目的。但同時這會帶來副作用,也就是微服務之間的管理成本會大幅提昇 [1]。實際上這也是很容易想像的事情,因為本來我們認為巨大的服務內部有混亂的互相呼叫的關係(Spaghetti Code [2] 的一種),讓程式碼變得難以維護;而當我們把它拆解成比較小的服務時,各個微服務內就會比較沒有那麼混亂的關係,進而讓每個微服務變得容易維護。但到這裡其實我們根本沒有解決問題!微服務跟微服務之間依然需要互相呼叫,也就是那些所謂的 Spaghetti Code 的關係並沒有被消除,只是被從程式碼內拿到程式碼外而已。所以雖然每個微服務的維運變容易了,但那些混亂又複雜的關係依然存在,而且變成存在於微服務和微服務之間,從程式碼問題變成是架構問題。這點在 [1] 這本書中開頭就有明確地提到,微服務是一種取捨、而不是 silver bullet,它不會解決所有的問題。當我們選擇微服務時,必須同時意識到它將要帶來的缺陷,並且要明確地確認組織能夠處理這個缺陷,才能夠往微服務發展。

在 TWJUG 的活動 [3] 中聽到 Apache Camel 這個工具,雖然說嚴格來講覺得沒有真的打到點,不過再看到最近社群到處轉貼的文章 [4],就覺得好像有點靈光一閃 (?),所以就先做個紀錄 XD。

參考資料
  1. 建構微服務|設計細微化的系統 (Building Microservices)
  2. Wikipedia - Spaghetti code
  3. Camel & Camel K & Camel K on K native
  4. 使用 Workflow Engine 來實作 Microservices SAGA pattern

2019年2月20日 星期三

使用其他工具透過 SSH 連接 GCP 的 VM

網路上其實已經有很多文章在講要怎麼用其他工具 SSH 連進 GCP 的 VM,不過中間大多有個小地方寫得不太清楚。

通常來說,多數文章會講說可以用 PuTTYgen 這個工具來產生 RSA 金鑰,然後這裡要記得選一下演算法和金鑰長度。產生好金鑰以後,PuTTYgen 會直接在介面上顯示出 public key,然後可以選填 key comment 和 passphrase。這時最重要的問題來了!這裡其實輸入的 key comment 就是未來用這個金鑰作為 SSH 登入管道時的使用者帳號,並不是一定要輸入什麼指定的東西,所以不必限定在一定要用 GCP 帳號的名稱、當然也不要直接用 PuTTYgen 預設的字串(雖然說預設字串也蠻不容易被猜到的啦….)。

後面就是一般操作,把 private key 存檔,並且把 public key 貼到 GCP 的 metadata 裡面,稍微等一下下,就可以用這個金鑰去 VM 登入了。

參考資料
  1. [教學] Google Compute Engine ( GCE ) 使用 PuTTY SSH 登入實例
  2. 使用進階方法連線至執行個體

2019年2月7日 星期四

Java 的 Collection

Java 的 Collection 在現在(指 Java 8)主要還是分成三個大類:List、Set、Map。其中每個大類幾乎都有 Thread-Safe 跟 Non-Thread Safe 的區別。有些實作因為比較少用到,會慢慢從我的記憶中消失(表示為金魚腦)….。另外因為我上一次認真看這些東西是在 Java 6 的時候,到現在有些東西有可能有變化了,所以還是需要定期複習和更新一下認知,以確保在合適的時機使用合適的結構。

2019年1月27日 星期日

分散式系統的 CAP

每次看完就會重新想起來,然後一段時間之後又會忘記定義,所以想說整理一下推導這個概念的過程。

CAP 分別代表的是以下三個概念:

  • 一致性(Consistency)
  • 可用性(Availability)
  • 分區容錯性(Partition tolerance):我個人認為白話來說就是是否允許系統中有節點與其他節點完全斷線。

最重要的關鍵在於 Partition tolerance 的問題,也就是當節點間的連線被切斷了的時候,狀況會變成如何?

  1. 滿足 AP 時無法滿足 C-如果節點連線被切斷了,例如被切割成 A 群和 B 群節點,但整個分散式系統的所有節點依然都能夠繼續提供服務,這時就滿足了 Availability 和 Partition tolerance。但因為 A 群和 B 群互相連不上對方,因此在 A 群當中做的變更,將無法反應在 B 群中。亦即此時 Consistency 就無法被滿足了。在 GlusterFS 當中,這個現象被稱為 split brain,就是系統存在兩顆大腦,兩顆大腦會同時做不同的思考。
  2. 滿足 CP 時無法滿足 A-如果節點連線被切斷了,變成 A 群和 B 群節點,但因為要確保整個系統資料的一致性,因此依照某些規則決定把被認為斷線的那個部份停用,例如認為 A 群才是 master,把 B 群暫時停用,直到 B 群重新連上 A 群為止。此時能夠保證 Consistency 和 Partition tolerance,但是因為在被分區的這個當下,部份節點會處於不可用的狀態,因此就無法滿足 Availability 了。
  3. 滿足 CA 時無法滿足 P-如果永遠要確保在系統中所有節點的資料一致,而且所有節點都要保證可用,那麼可想而知,就不能允許發生像上面講到的,網路斷線產生兩群節點互相連不上對方的狀況(因為一旦發生斷線,只要雙方都持續提供服務,則一定會 split brain;要不 split brain 只能選擇停用其中一方)。也就是這時就無法滿足 Partition tolerance 了。

2019年1月19日 星期六

(書籤) Java Memory Model

很久沒用到,覺得已經不太記得細節了…。一般在工作上會優先架構成能夠允許最終一致性的狀況,不過如果遇到強一致性的多執行緒需求,還是必須考慮到 Java Memory Model。

大體上來說,因為硬體上 Thread 會有自己的本地快取,因此在不同 Thread 間對同個物件的「視野」可能是不同的。概念上很像是在資料庫上會遇到兩個 Transaction 看見的內容不同的那種狀況。由於硬體終究會將本地快取 flush 回主記憶體,所以最終還是會保持一致性,只是在過程中不見得永遠會滿足執行緒間的一致性,這時就需要 volatile 登場了。

參考資料
  1. Wikipedia - Java memory model
  2. Java Memory Model
  3. 深入理解 Java 内存模型(一)——基础
  4. Stack Memory and Heap Space in Java
  5. Difference between volatile and synchronized in Java
    1. JAVA多執行緒之volatile 與 synchronized 的比較
    2. Volatile vs Static in Java

    2019年1月14日 星期一

    Dependency Injection 與 static

    最近一直在思考 Spring 與 static 之間的關係。一般來說,Spring 會管理由它生成的 Bean,不過如果類別本身是以 static 形式呼叫(例如程式碼呼叫 MyClass.callStaticMethod() 這種方式)的話,正常來說就不會被 Spring 所管理,自然在類別內的自動注入(如果有的話)也不會生效。雖然是有一些小技巧可以姑且繞過問題,不過感覺上從 Spring 的角度,好像應該用別種思考模式來思考這個問題。

    關於這個問題,在請教 qrtt1 大神之後獲得了解惑,請大家一起膜拜 qrtt1 大神~(拜)。不過其實概念也並不困難,只是不知道為什麼原本一直想不通。

    PostgreSQL 的索引:B-tree

    開這篇之前,其實本來是想要了解 PostgreSQL 10 裡實現索引的原理,畢竟在了解原理的情況下,比較容易想像在什麼情況下索引能夠具有優勢、什麼情況索引幫不上忙。不過花了一段時間搜尋…也不能說沒有找到,但沒有找到我想要的類型。所以這篇雖然標題在講 PostgreSQL 的 B-tree 索引,但實際上會先紀錄的是一般關聯式資料庫以 B-tree 做索引時的狀況。如果想參考看看我找到的其他在談 PostgreSQL B-tree 原理的文章,可以看看 [1-5]。

    這篇當中實際會紀錄到的東西,有很大一部份並非來自 PostgreSQL 的官方文件,因此這並不一定完全就是 PostgreSQL 實現的方法,嚴格來說其實這個標題並不是太合適。不過理想上….應該不會差太多….吧!此外這篇文章紀錄的事項,除了我個人的觀點以外,有許多部份是來自 USE THE INDEX, LUKE! [7] 這個網站的解說。因此如果想要有條理地細讀,推薦可以直接去閱讀這個網站的內容。

    然後呢,理想上我是想要依序了解所有 PostgreSQL 的索引結構,並分別做點紀錄。所以它有可能會是個系列文,這篇作為系列文的第一篇就會參雜一些奇怪的廢話了。但…也不保證真的會寫出來就是,以前有編號的系列文絕大多數都虎頭蛇尾了 Orz,所以這次索性不編號了。

    2019年1月5日 星期六

    演算法的細緻之處…

    在 LeetCode 上有個簡單的題目:Two Sum [1],題目很單純,就是給定一個陣列以及一個目標值,找出能夠滿足相加會等於目標值的兩個數字。

    這個問題最容易想到的自然是暴力破解,暴力破解的複雜度是 O(n2)。而另一種想法大概是左右逼近,但這存在一個前提是陣列必須是已排序的陣列,所以考慮排序的話,複雜度會是 O(nlogn)(實際來說複雜度可能是 O(nlogn + 2n) 吧)。然後如果有想到可以用空間換取時間的話,利用 HashMap 就可以達到 O(n)。

    接著三種解法都送出的話,想像上效能應該是 O(n) > O(nlogn) > O(n2),不過實際上呢?(但我沒有嘗試送出 O(nlogn) 的版本,所以時間直接引用 [2])