Tldr
Ordering service trong Fabric đóng vai trò thu thập các transaction đã được chứng thực và sắp xếp chúng vào một block rồi phân phối cho các peer node trong channel để commit xuống ledger.
Ordering service được cung cấp bởi các orderer, là một loại node ở trong blockchain network của Fabric.
What is Ordering?
Các public blockchain chẳng hạn như Bitcoin hoặc Ethereum sử dụng các cơ chế đồng thuận xác suất (probabilistic) để sắp xếp và đóng gói các transaction vào các block. Các cơ chế đồng thuận này dễ xảy ra tình trạng forking1.
Hyperledger hoạt động theo một cách khác: nó có các node đóng vai trò là orderer chịu trách nhiệm sắp xếp các transaction. Các orderer này kết hợp với nhau tạo thành ordering service. Ordering service sử dụng các cơ chế đồng thuận tất định (deterministic) nhằm đảm bảo các block đã được xác thực là final. Điều này giúp giảm thiểu vấn đề forking xảy ra ở trong các public blockchain.
Ngoài việc đảm bảo tính finality, Fabric còn tách biệt giữa việc thực thi smart contract với việc sắp xếp giao dịch nhằm tăng hiệu năng, khả năng mở rộng của network cũng như là giảm thiểu bottleneck xảy ra khi một node phải thực hiện quá nhiều công việc.
Orderer Nodes and Channel Configuration
Orderer còn làm nhiệm vụ ép thỏa các chính sách truy cập cho các channel. Cụ thể hơn, nó giúp giới hạn lại những tác nhân có quyền đọc, ghi dữ liệu cũng như là cấu hình orderer. Chính sách về các quyền hạn của các tác nhân nằm ở trong channel configuration và sẽ được các orderer xử lý khi tạo ra genesis block2. Nếu có một tác nhân cập nhật các chính sách, orderer sẽ đối chiếu với chính sách cũ để đảm bảo rằng tác nhân đó có đủ quyền hạn để thực hiện thao tác. Nếu thỏa mãn, một configuration transaction (giao dịch cập nhật cấu hình) sẽ được tạo ra và sẽ được phân phối đến cho các peer dưới dạng một configuration block.
Orderers and the Transaction Flow
Thứ tự của các transaction ở trong block không nhất thiết phải là thứ tự mà các orderer nhận được từ các gateway. Lý do là vì các orderer trong cùng một ordering service có thể nhận được các transaction có thứ tự khác nhau. Tuy nhiên, thứ tự của các transaction sẽ được quy định lại một cách chặt chẽ bởi ordering service và các peer cần phải tuân thủ theo thứ tự này.
Đối với các blockchain khác, một transaction có thể tồn tại ở nhiều block khác nhau và các block này cạnh tranh với nhau để tạo thành một chain. Trong Fabric, một khi transaction được đặt vào block thì vị trí của nó ở trong ledger là hoàn toàn được đảm bảo. Chính điều này giúp Fabric ngăn chặn được các ledger fork.
Có thể thấy, các orderer chỉ có trách nhiệm đóng gói các transaction vào các block chứ chúng không quan tâm đến nội dung của transaction (ngoại trừ các configuration transaction như đã đề cập ở trên).
Ordering Service Implementations
Có một số cách thức cài đặt của ordering service còn khả dụng (không tính những implementation đã bị bỏ) như sau:
- Raft: là một crash fault tolerant (CFT) ordering service dựa trên giao thức Raft của
etcd
(một distributed key-value store). Raft sử dụng mô hình leader và follower. Cụ thể, sẽ có một leader được bầu cử động ở trong channel và tất cả các các quyết định của leader sẽ được nhân bản ra cho các follower. - BFT: là một Byzantine Fault Tolerance (BFT) ordering service hoạt động với điều kiện không quá 1/3 tổng số node bị hư hỏng.
Raft
Raft ordering service có thể chịu được việc một số node bị crash (không ngoại trừ leader) nếu như có đa số các node vẫn còn hoạt động. Ta gọi tập các node còn hoạt động là quorum. Cụ thể hơn, nếu có 3 node trong một channel thì Raft ordering service vẫn có thể hoạt động nếu chỉ có 1 node bị crash. Một ví dụ khác, nếu như có 5 node trong channel thì có thể có 2 node bị crash.
Attention
Raft ordering service có thể làm mất transaction trong trường hợp leader bị crash ngay tại thời điểm các follower gửi lại acknowledgement. Để giải quyết vấn đề này, client application có thể đặt ra một timeout nhất định. Sau timeout, nếu không có commit event nào xảy ra3 thì client application cần phải gửi lại transaction hoặc thu thập lại các endoresement.
Raft Concepts
Một số concept quan trọng trong Raft:
- Log entry: unit of work cơ bản nhất của Raft ordering service là các log entry. Ta xem log là nhất quán (consistent) nếu như có một quorum các node đồng thuận về nội dung và thứ tự của các log entry.
- Consenter set: là các orderer tham gia vào việc ordering và nhận về các bản sao của log entry của channel.
- Finite-state machine (FSM): mỗi orderer trong Raft ordering service đều có một FSM nhằm đảm bảo chuỗi các log entry trong các orderer khác nhau là tất định (có cùng nội dung và thứ tự).
- Quorum: một lượng tối thiểu các node cần xác nhận một proposal từ leader để các transaction có thể được sắp xếp vào block. Với mỗi consenter set thì quorum là một tập đa số các node. Nếu như không tồn tại quorum thì ordering service không thể đọc hay ghi dữ liệu cũng như là sẽ không có log entry nào được commit.
- Ledger: tại bất kỳ thời điểm nào, consenter set của channel sẽ bầu cử ra một node để làm leader. Leader có nhiệm vụ nhận vào các log entry mới từ client application và gửi chúng cho các follower.
- Follower: nhận các log entry từ leader và nhân bản chúng một cách tất định nhằm đảm bảo tính nhất quán của tập các log entry. Khi một leader ngừng gửi thông điệp đến các follower, sau một thời gian nhất định, các follower sẽ tiến hành bầu chọn để chọn ra leader mới.
Raft in a Transaction Flow
Mỗi channel sẽ có một instance của Raft ordering service. Chỉ có thể có một orderer có thể được thêm vào hay xóa bỏ khỏi channel tại một thời điểm.
Trong Raft, các transaction (bao gồm các proposal và các configuration update) được định tuyến tự động giữa các orderer để đến leader. Nói cách khác, các peer và các client application không cần phải biết ai là leader để gửi transaction.
Architectural Notes
How Leader Election Works in Raft
Các node trong Raft có ba trạng thái là follower, candidate và leader.
- Các node sẽ khởi đầu với trạng thái follower. Khi ở trạng thái này, các node sẽ nhận các log entry từ một leader hoặc gửi các phiếu bầu. Nếu không có log entry nào gửi đến node sau một khoảng thời gian nhất định (chẳng hạn như 5 giây), các node sẽ tiến hành tự đề cử chúng để trở thành leader và chuyển sang trạng thái candidate.
- Khi ở trạng thái candidate, các node sẽ yêu cầu các phiếu bầu từ các node khác. Nếu một node nhận được một quorum số phiếu bầu thì nó sẽ được chọn làm leader.
- Leader bắt buộc phải chấp nhận các log entry và gửi chúng cho các follower.
Seealso
Visualization của Raft protocol.
Snapshots
Khi một node bị crash, làm cách nào để nó nhận được các log entry khi nó khôi phục?
Raft sử dụng một cơ chế gọi là snapshotting cho phép người dùng định nghĩa số lượng các byte dữ liệu được lưu lại sau một khoảng thời gian nhất định. Các byte dữ liệu này sẽ tương ứng với số lượng các block.
Ví dụ, giả sử có một replica R1
vừa khôi phục với block mới nhất của nó là 100
. Trong khi đó, block hiện tại của leader L
là 196
và leader được cấu hình sẽ thực hiện snapshot mỗi 20 block. R1
sau đó sẽ nhận block 180 và nó sẽ gửi một Deliver
request cho các block từ 101 đến 180. Các block còn lại từ 180 đến 196 sẽ được ghi nhận thông qua giao thức Raft thông thường.
Giải thích tại sao
L
gửi block 180 choR1
thay vì block 176Bởi vì leader được cấu hình snapshot một lần 20 block nên số block gửi cho replica cần phải là bội của 20 và có khoảng cách đến block hiện tại nhỏ hơn hoặc bằng 20. Bội của 20 gần 196 nhất có thể là 160, 180. Tuy nhiên, khoảng cách từ 160 đến 196 lại là 36 lớn hơn 20. Do đó, 180 là con số được chọn.
BFT
Giao thức được sử dụng bởi BFT ordering service là SmartBFT, là một giao thức dựa trên giao thức BFT-SMART. Thực chất, BFT-SMART là phiên bản non-pipeline4 của giao thức PBFT.
Tương tự với Raft, sẽ có một orderer được chọn làm leader để phân phối block đến cho các follower. Tuy nhiên, leader ở trong BFT không được bầu cử động mà được chọn theo thuật toán round-robin5 bất cứ khi nào leader trước đó có lỗi. Dấu hiệu để bầu cử leader mới trong BFT cũng tương tự với Raft: sau một khoảng timeout mà leader không gửi log entry thì các follower sẽ tiến hành bầu cử leader mới.
Giao thức BFT có thể hoạt động nếu có ít hơn 1/3 tổng số orderer bị lỗi (hoặc bị kiểm soát bởi kẻ xấu). Trong khi đó, giao thức Raft có thể hoạt động khi hệ thống có ít hơn 1/2 tổng số orderer bị lỗi. Ví dụ, nếu hệ thống có 9 orderer thì BFT cho phép tối đa 3 orderer bị lỗi và Raft cho phép tối đa 4 orderer bị lỗi.
Điểm khác biệt to lớn giữa BFT và Raft là khi client gửi transaction cho BFT ordering service thì nó sẽ gửi cho toàn bộ các orderer vận hành ordering service. Điều này đảm bảo rằng nếu leader bị lỗi hoặc bị kiểm soát bởi kẻ xấu thì nó cũng không thể chi phối quá trình sắp xếp transaction vào block và phân phối đến cho các peer.
Trong Raft, việc gửi transaction cho một orderer không đảm bảo rằng transaction đó sẽ nằm trong một block. Kể cả nếu gửi transaction cho tất cả các orderer thì leader cũng có thể bị crash và dẫn đến transaction bị mất. Đối với BFT, nếu leader bị crash thì transaction vẫn còn nằm trong bộ nhớ của các follower và transaction đó sẽ được gửi lại cho leader hoặc sẽ có một leader khác được chọn nhằm đảm bảo transaction luôn được thêm vào trong block.
Related
Resources
- https://hyperledger-fabric.readthedocs.io/en/latest/network/network.html
- https://hyperledger-fabric.readthedocs.io/en/latest/orderer/ordering_service.html
Footnotes
-
xem thêm Creating the Network và Blockchain ↩
-
một giao thức đồng thuận mà không có pipeline sẽ đồng thuận một block chỉ khi nào block trước đó đã được đồng thuận. ↩
-
xem thêm Fair Queuing - Round Robin ↩