嘗試用圖表的方式,從不同的角度來看 Microservices。
2015/7/27
2015/7/20
Microservices 微服務
microservices 其目標是將應用程式切割成多個單純的、小型的功能,每一個獨立的小功能都各自成為一個服務,每一個服務有自己的 process,各服務之間透過輕量的 protocol 互相溝通,並發佈到多個 server 上。
microservice 就像是在遵循著汽車工廠的進化歷史
在進行系統開發時,通常會先採用單一獨立的應用系統架構,也就是使用一個大型的應用程式伺服器(ex: weblogic),並在上面部屬自己的大型應用程式。
但隨著應用程式組件的輕量化,應用程式部屬環境也慢慢地往輕量化位移,我們可以用比較小型的應用程式伺服器(ex: nodejs),進行應用程式的開發。
由於應用程式的開發成本的降低,系統開發再慢慢地朝向多個伺服器同時運作的環境,也逐漸產生將系統切割成多個 microservice 開發後,再進行組裝的概念。
整個進化的過程就像是汽車工廠的演進一樣,一開始是由一個獨立的工廠開發設計並進行組裝,後來慢慢地出現零組件工廠,汽車工廠只需要整合多個衛星工廠,就可以組裝一台車輛。
這個過程當然也可能會出現一些特殊的工廠服務,例如只提供汽車設計的公司,只提供組裝代工的工廠,只提供螺絲、引擎或外殼的工廠等等。基本上這都是從最初的汽車工廠中,慢慢地進化而來的,其切割且獨立重點在於:
- 該服務是否可獨立運作
- 該服務是否有獨立獲利的能力
能夠獨立出來的服務,在其運作的過程中,也會慢慢更趨近於最佳化,變成一種專業的服務。
優點
每個 microservice 只提供一個小型並獨立的功能,程式開發時因耦合度較低,可以專注在該功能的實作上。
各 microservice 經由不同的組合,可組成不同的應用程式
每一個 microservice 可由不同的開發單位進行開發
microservice 因功能獨立且單純,開發人員較容易維護與修改程式
microservice 僅包含 business logic code,沒有 user interface components
當服務規模擴大時,系統很容易擴展
microservice 可運作於中低效能的 server 上
缺點
多個獨立 process 代表需要更高超的 DevOps 管理技術
分佈式系統的管理會很複雜
軟體出錯時,需要多個單位協同處理,較耗時間
RPC 呼叫需要花費時間
Docker 簡化了 service deployment
Docker透過Container技術可以將任何小程式打包成可獨立執行的映像檔,發佈到任何可執行Docker的平臺上執行。開發者只要將應用程式所需的功能程式打包成Docker image file,部署到伺服器就能成為提供不同功能的微服務。
原本需要幾分鐘開機時間的 VM,到了 Docker 變成了幾秒,deployment 的速度成了 microservice 最有效率的部屬平台的原因。
業者更進一步開發了 Container OS,一種只保留OS核心和Docker所需執行環境,以及管理Docker叢集的工具的輕量化作業系統,這更能有效提昇 container 的整體性能。
問題在如何切割服務
對於 architect 來說,最麻煩的問題不在了解 microservices 的優點與概念,問題在於要如何正確且有效地切割應用程式。
一個好的開發者在開發獨立應用程式時,會嘗試將系統分成不同的模組,也就是模組化的系統設計,讓模組與模組之間的耦合度降低,以降低系統的複雜度。
切割模組對於應用程式來說,並不是一件難事,我們總能快速地將系統模組化,通常一個應用程式可識別出來的模組數量大概都是 5~10個。
但進入到 microservices 的概念之後,我們要識別的是更小型且能夠獨立運作的服務規模,這就像是在系統設計初期,就要有效地判斷出商業邏輯層中,哪些可以劃分為同一個物件類別,這是一件困難的工作。
問題在 API 的設計
每一個服務或零組件,都需要提供一個 API 界面讓其他服務存取,API 的設計可能會經歷多個版本的沿革,這等於同時造成了 API 使用者以及開發者的困擾。
對開發者來說,為了保持 API 的相容性,不讓使用舊版 API 的其他服務掛點,需要耗費精神同時維護多個版本的 API,並等待其他服務都順利轉移至新版 API 之後,才能將舊版的 API 關閉。
對使用者來說,由於 API 的不穩定,相對就造成一些使用上的問題,比較簡單一點的更新,可能就是增加了參數或是新的 API,比較麻煩的,可能是整個 API 的商業邏輯變動,這可能會造成牽一髮動全身的疑慮。
如果說要讓 API 在「設計好了」的時候,再釋放給其他服務使用,這就等於消滅了 microservice 的初衷,可「快速」開發小型的服務的能力,我們什麼時候才能確認 API 是「好的」?
References
2015/7/13
Scalable Web Architecture
在網頁服務的運算環境中,通常得面對 scalable 的問題,其實在 J2EE 的標準裡,一開始就已經考慮到這個問題,架構上都是切割為三層:Web Layer,Application Layer(Business Logic) 跟 Backend Service Layer(DB 或其他系統)。然而複雜的 EJB container 與通訊問題,造成了這個技術式微,所有人的目光都轉向 light-weight,但在輕量化之後,我們還是得面對大量使用者同時使用的服務架構,技術人員總是得一直追求著,以越少的系統資源提供越多的使用者使用的技術架構。
Concurrent Programming for Scalable Web Architectures 是作者 Benjamin Erb 的畢業研究報告,目標是要找到一個適當的 concurrency model 能用在 multi-core processor,分散式 backend 環境,且能支援新的 web 技術。
在前言中,作者提到網頁將會取代更多桌面的應用程式。接下來十年內,將會專注在 multi-core 與 multiprocessor 的運算環境,而不會增加 CPU 的工作時脈。我們需要選擇適當的程式語言,並搭配合適的 framework,用以設計能夠支援更大規模的 concurrent user 的系統。
討論concurrency有三項重點,接下來的文章內容,會以這三個部份,討論增加系統使用者的策略。
- connection handling
chap4:web server architectures for high concurrency - application logic
chap5:concurrency concepts for applications and business logic - backend persistence
chap6: concurrent and scalable storage backends
concurrency 與 scalability
Concurrency 就是系統可同時執行多個活動的一種特性。每個活動都是獨立的,可以發生在不同的運算環境中,例如 single-core processors, multi-core processors, multi-processors 或是分散式系統的多台機器。為保證系統的 consistency,必須有 coordination 與 synchronization 的機制。
有三個方法可改善 concurrency 的效能:
- reduce latency
將工作切割可同時執行的子任務 - hide latency
因為等待 network 或 disk IO 會造成延遲,可同時執行多個外部系統的工作。 - increase throughput
藉由同時執行多個 task 可增加系統 throughput,也可增加 sequential task 的執行速度。
Concurrency vs. Parallelism
簡單地說,paralleism 是由硬體架構支援的平行處理,這是執行的狀態,可用 multi-core 或是 multiprocessor 實現,而 concurrency 是程式語言支援的模式。single core 的機器也可以支援 concurrency 但不能支援真正的 paralleism。
Models for Programming Concurrency
有四種 programming concurrency
- sequential
沒有 concurrency - declarative
implicit control flow of computation - message-passing
activities 透過傳遞 message 互動,訊息傳遞有 synchonous 與 asynchronous 兩種。 - shared-state
可競爭存取資源與狀態
Horizontal and Vertical Scalability
通常是採用 horizontal scalability,就是用很多低成本的機器進行水平擴充。然而採用 vertical scalability 的考量點,就是使用更好的機器,更快的 CPU,在於成本效益、或是專用的硬體,application 也不需要特別進行客製化。
scalability requirements
- high availability
通常用 percentiles of uptime 來計量 - reliability
以 meantime between failures 計算 - performance
short response times (low latencies)
Scalable Web Architecture
tiers architecture
通常 web architecture 可分為三個不同的 tiers
- presentation tier
html user interface - application logic tier
business logic - persistence tier
database
load balancing strategies
- round robin
- least connections
以連線數量決定 - least response time
以最小的 response time 決定 - randomized
- resource-aware
搭配 connection 數量與 response time 計算出適當的 loading 分配比率
sticky session
雖然 http 是 stateless,但 web application 常常需要讓 user 在同一個 session 中,存取同一個 web server,這時候可透過 cookie 來決定分配的機器。
在 scalable web architecture 中,我們不應該試著將 user 導向到同一台機器,而是要找到一個方法,讓後端的多個機器,可以同時取得使用者的 session data。
Web Server Architecture for High Concurrency
目標是更多的 concurrent http requests,server 的 performance 可用以下的 metrics
- request throughput (#/sec)
- raw data throughput (Mbps)
- response time (ms)
- number of concurrent connections (#)
在機器上可取得的 metrics
- CPU utilication
- memory usage
- number of open socket/file handles
- number of threads/processes
C10K
理論上, 500 MHz, 1 GB of RAM, 6 x 100Mbit/s 的硬體,同時有 10000 個客戶連線完全是可行的,目前已經有公司提出 C500K 的 concurrent model。
I/O Operation Models
blocking vs. non-blocking
application 可告訴 OS 該如何存取 device。
blocking mode 的 IO operation 會一直等待,等到該 operation 完成才會 return。non-blocking mode 中,所有 operation 都會立刻 return,並提供 call status 或是 error。synchronous vs. asynchronous
說明在 IO Operation 過程中的 control flow,synchronous call 會一直等待 operation 的結果,而 asynchronous call 會立刻 return,然後可繼續執行其他 operations。
Server Architecture
- Thread-based
multi-process architecture
傳統的 unix-based network server 就是每一個 connection 產生一個 processmulti-threaded architecture
在一個 process 裡面,多個 thread 共用相同的 memory,共用 global variables 與 state,建立 thread 比建立 process 消耗的系統資源少。系統可用一個 thread 接受 request,然後 dipatch 到 worker thread pool 中,取得一個有空閒的 worker thread 處理該 request。
- Event-driven
利用一個 thread 執行 event loop,每一次處理一個從 event queue 取得的 event。
對於大規模的 concurrent connection,目前比較流行的作法是使用 asynchronous/non-blocking I/O operations 的 event-driven server architectures。
Concurrency Concepts for Applications and Business Logic
將 application logic 區分為兩種類型
CPU-bound activities
需要 CPU 在記憶體進行大量的計算,通常在 web application 中,input validation, template rendering, on-the-fly encoding/decoding 就屬於這類型的 taskI/O-bound activities
受 network or file I/O 限制的 activities,包含了 storage backend, background services, external services
concurrency based on thread, locks, and shared state
thred 控制了 application flow,當兩個以上的 thread 同時 access ctritical 資料時,需要一個locking mechanism,來控制 threads 之間的狀態變化。
Java 語言就是使用這種機制
concurrency via software transactional memory (STM)
由 programming language 直接提供 locking 與 shared state 機制。
Clojure 使用這個機制
Actor-based Concurrency
利用 actors 進行 concurrent processing,actor 可透過以下方式取得需要進行處理的 message
- Send a finite number of messages to other actors.
- Spawn a finite number of new actors.
- Change its own internal behavior, taking effect when the next incoming message is handled.
scala 使用這個機制,actor 的實作有兩種方式
Thread-based Actors
使用 receiveEvent-driven Actors
使用 react
Event-driven Concurrency
node.js 使用這個機制
Concurrent and Scalable Storage Backends
CAP Theorem
一個分散式系統不可能同時滿足以下三點,最多只能滿足其中兩項,例如 CA: high-availability consistency, CP: enforced consistency, AP: eventual consistency
- consistency 一致性
- availability 可用性
- partition tolerance 容忍網絡分區
Consistency Models
ACID: 具有 transaction 的行為
atomicity: 交易細項,是全有或是全無
consistency: 執行交易時,保證從一個狀態過渡到另一個狀態
isolation: 保證 transaction 不受其他交易影響
durability: 一旦 transaction 成立,交易的結果一定會保存,即使系統 crash 也是一樣BASE: 簡單而快速,盡力而為
basically available
soft state: 客戶端要接受,某些狀況下會失效
eventually consistent: 盡可能地提供一致性
Replication strategies
Master-Slave
單一 Master node 提供寫入,多個nodes 以 load balancer 提供讀取的功能Multi-Master
允許多個 node 同時讀寫
Distributed DB System 的類型
Relational DBMS
Non-Relational DBMS
- Key/Value Stores
ex: Dynamo from Amazon, Redis - Document Stores
ex: CouchDB - Wide Column Stores
ex: BigTable, Cassandra - Graph Database
ex: neo4j