Saturday, December 30, 2017

microservices prerequisites

這兩天看了一篇文章, Enough with the microservices ,文章的大意是講,作者反對成長中的公司,盲目地將公司的軟體架構改成「微服務」,因為帶來的損害大過優點。

文章的最後,介紹了 Martin Fowler 的「微服務的先決條件 (microservices prerequisites) 」。即,要把公司的軟體架構改成微服務,要先做哪些事? 並且提到,對於許多公司,光是完成前兩項,大概就可以解決 90% 以上的問題,並不需要真的做到五項都完成,完整地把軟體架構改成微服務。

先決條件清單如下:

  1. 清理應用程序。確保應用程序具有良好的自動化測試套件,並使用了最新版本的軟件包、框架和編程語言。
  2. 重構應用程序,把它拆分成多個模塊,為模塊定義清晰的API。不要讓外部代碼直接觸及模塊內部,所有的交互都應該通過模塊提供的API來進行。
  3. 從應用程序中選擇一個模塊,並把它拆分成獨立的應用程序,部署在相同的主機上。你可以從中獲得一些好處,而不會帶來太多的運維麻煩。不過,你仍然需要解決這兩個應用之間的交互問題,雖然它們都部署在同一個主機上。不過你可以無視微服務架構裡固有的網絡分區問題和分佈式系統的可用性問題。
  4. 把獨立出來的模塊移動到不同的主機上。現在,你需要處理跨網絡交互問題,不過這樣可以讓這兩個系統之間的耦合降得更低。
  5. 如果有可能,可以重構數據存儲系統,讓另一個主機上的模塊負責自己的數據存儲。



Thursday, December 28, 2017

Clojure 函數與 Design Pattern

23 個 Design Pattern 一直是我覺得很不容易精通的東西。還好,  Peter Norvig 也提了他的看法,認為 Design Pattern 在 functional programming language 裡並不是很必要的東西,因為 FP 讓 function 成為 first class citizen ,會讓 Design Pattern 大幅簡化。

這邊還是記錄一下,在寫 Clojure 時,哪些 Design Pattern 會被 Clojure 的核心函數大幅簡化的。
1. Factory Pattern
    用 partial 即可
2. Visitor Pattern
 用 defmulti 即可
3. Observer Pattern
 用 add-watch 來寫的話,會簡單許多

Thursday, December 7, 2017

database and system design

最近要換工作了。換工作前,依然還沒有學完/學通公司的資深工程師 Mike 的 skills。只好先把他以前寫在 slack 的 comments 拷貝出來。

==================================================
1. 一張 table 的資料,一定只有一個順序存在「硬碟」中

2. Clustered Index,是一個用資料規則來決定資料在「硬碟中」的順序的方法

3. 當需要進行範圍查詢時,Clustered Index 可以利用到「硬碟」的循序存取效能

4. 不是有索引,資料庫的查詢最佳化就會使用,當資料量不多時,資料庫會直接使用 Full table scan

5. 就點查詢而言,WHERE 的條件在 Clustered Index 比 Secondary Index 還快,因為 Leaf Node 就是 Data Block

6. 資料庫效能是在「新增、修改、刪除」與「查詢」之間取捨 --- 註:前同事 Mike 對 relational database 的理解沒有錯。然而,在 Martin Kleppmann 的 Turning the database inside out with Apache Samza 這個 talk 裡,他探討了一種 system architecture,透過 event sourcing 與 CQRS ,可以達成不需要為了 Read 或是 Write 的效能而做出 trade-off。

7. Secondary Index Leaf 是 Clustered Index Key 是 MySql InnoDB 特有的實作方式

8. MySql 選擇了讓 Secondary Index 「新增、修改、刪除」容易,但查詢付出代價

9. MySql 是查詢最佳化很蠢的資料庫,意思要用很多索引,所以 InnoDB 實作 Secondary Index Leaf 到 Value of PK,在多個索引的情況下,PK 的順序不影響 2nd Index 的 Leaf Node 的值

10. 在那一篇引起戰文的為何用 MySql 取代 PostgreSql 的文章(UBer)中,關於索引的部份,他們在不斷更新資料的前提下,再加上有一堆索引,所以使用 MySql,更新的成本比 PostgreSql 低

11. 在 MVCC 的比較上,當 Transaction Log 與 Data Block 放同一個磁碟子系統時,
 假設 Read(50%) 與 Write(50%),PostgreSql 可能比 MySql 好太多,因為減少了大量的 Random Access

=============
資料庫先求正確,再求效能,不正確的資料會拖累效能,甚至無法 Tuning,因為隨著時間,相依的程式碼太多。

資料庫資料的修正與程式的 Patch 不是同樣成本的事,讓資料嚴謹至少佔了系統品質的 60%。程式出錯,還有資料庫把關。

資料庫嚴謹的代價是效能,但它是可調效的,資料出錯,通常是前端先發現,然後要一層層檢查是哪裡出錯,是查詢有錯、還是新增修改有錯、還是前端有錯。甚至可能只有正式機才會有資料範例,此時就可能要在正式機上除錯。

==============
資料庫有兩本書就用了
The Art of SQL
Database: Principles, Programming, and Performance

Tuesday, November 28, 2017

SQL insert after join table

最近寫 SQL 的時候,遇到了有趣的「寫入」問題。問題如下:

有三張 table
table host 有 id, hostname
table grp   有 id, grp_name
table grp_host 有 grp_id, host_id => 這張表用來記錄 grp 和 host 之間的 relation

需求是:要寫入 grp_host 這張表,但是,原始資料的 grp 與 host 的 relation ,是用字串來記錄的,也就是 (string, string) 這樣子的 tuple。

總之,這個寫入的合理作法,要用一點小技巧:
建立 temporary table,然後 insert into ... select ,還有,要包在一個 transaction 裡頭!





Saturday, November 4, 2017

postgreSQL 常用指令

這兩天因為要把自己寫的 web app 布署到 amazon EC2 ,也試用了一下 postgreSQL ,比想象中的好用一些。

在 ubuntu 安裝:
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

linux shell 模式下常用指令:
sudo -i -u postgres         // 切換 postgres 的使用者身分,用來操作資料庫
createuser -P  peter        // 使用 createuser 這隻指令來設定一個使用者 peter ,並且提示設定密碼
createdb         peterdb    // 使用 createdb 這隻指令來建立一個資料庫 peterdb
dropuser         peter     
pg_dump --column-inserts --data-only -d [database_name] -t [table_name]  > file.sql    // 備分資料庫

連進資料庫:
psql                             

又或是在連進資料庫之後,建立使用者 enzo/資料庫 plenish / 給予權限:
CREATE DATABASE enzo;
CREATE ROLE plenish WITH LOGIN PASSWORD 'plenish';
GRANT ALL ON DATABASE enzo TO plenish;

連線後常用指令:
\l                                  // 列出所有的資料庫
\d                                 //  列出所有的資料表
\d+ [tablename]                    //  顯示 table 的 schema
\c  [databasename]               //  切換其它的資料庫
ALTER SEQUENCE users_id_seq RESTART WITH 1000;    //  將 user_id_seq 這個 sequence 設定成從 1000 開始起跳。

< 範例 1 >  (可用於 luminus 專案開發)
create database mydb;                             
create user        myuser     with encrypted password  'mypass';
grant all privileges on database mydb to myuser;
// 建立特定的使用者、資料庫、並且給予完整的權限

< 範例 2 >
alter user <username> with encrypted password '<password>';

< 範例 3 >
alter user <username> createdb;

Tuesday, October 31, 2017

讀網路上的技術文章有感

身為中文的使用者,偷懶的時候,還是會傾向先讀一下中文的資料。此外,國外的一些進階者寫的東西有時候相對比較難、多用了專有詞彙,我又會偷懶看一般人寫的心得。

然後就出現了一些問題:以訛傳訛

比方說像 microservices 。我看了很多文章都把 microservices  的重點放在 docker 、放在 container ,而不是 database 的獨立性:『每個微服務應該有自己獨立的持久性資料儲存,而且這些資料只能透過微服務本身的 API 來存取。』這些搞錯重點的文章居然還一大堆,無形中也助長了人的無知、誤了好多人。

此外, concurrency model 也是一個例子。Golang 很紅。然後就會有一些介紹 Golang 的文章錯誤地把 Erlang 的 Actor model 講成說這跟 Golang 的 CSP model 是一樣的、差不多的。這也是差很多啊…。

Friday, October 27, 2017

要不要用 cronjob ?

要不要使用 cronjob ,我覺得這是一個設計的問題:

我最近在重構的一隻 Script ,它做了下列幾件事:
(1) 每分鐘執行一次,依賴 cronjob 來啟動
(2) 每次執行,它都會呼叫數個外部的 http API

如果考慮布署的方便性,其實我可以考慮把 cron 的部分,直接在 script 裡做掉。這樣子 Devops team 就不用設定 cronjob ,Devops 的成本會比較低。此外,cronjob 因為是系統共用的,有時候運氣不好,就被改掉了。

另一方面,如果是讓 script 自行做 scheduling 的話,我就必須考慮 exception handling 。因為呼叫 API ,有時候網路如果斷掉,就會產生 exception 。產生 exception 的話,有時候整個程式就 crush 掉了,甚至連下一週期也受到波及。然後,我想有想到 Erlang 的設計就是每個 process 都是完全獨立的。任何一個 process 就算 crush 掉也沒有關系。照這個想法的話,用 cronjob 來跑的 script ,每一次的執行也都是獨立的 執行環境,確實也比較簡單。

上網查了一下:似乎也有其它人跟我有類似的疑問? 解法也很妙,還分成兩類:
(1) ofelia 的解法是,重新實作一個類似的 cron 的程式。但是適合跟 docker 合作。
(2) supercronic 的解法則是,實作一個適合在 docker 內部執行的 cron