Bản dịch này được tạo bằng máy học và có thể không chính xác 100%. Xem phiên bản tiếng Anh

Giao Thức Garlic Farm

Proposal 150
Open
Author zzz
Created 2019-05-02
Last Updated 2019-05-20

Tổng quan

Đây là đặc tả cho giao thức truyền tải Garlic Farm, dựa trên JRaft, mã “exts” của nó để triển khai qua TCP, và ứng dụng mẫu “dmprinter” của nó JRAFT .

Chúng tôi không thể tìm thấy bất kỳ triển khai nào có giao thức truyền tải được tài liệu hóa. Tuy nhiên, triển khai JRaft đơn giản đến mức chúng tôi có thể kiểm tra mã nguồn và sau đó tài liệu hóa giao thức của nó. Đề xuất này là kết quả của nỗ lực đó.

Đây sẽ là phần nền tảng để điều phối các bộ định tuyến công bố các mục trong một Meta LeaseSet. Xem đề xuất 123.

Mục tiêu

  • Kích thước mã nhỏ
  • Dựa trên triển khai hiện có
  • Không sử dụng các đối tượng Java được tuần tự hóa hoặc bất kỳ tính năng hoặc định dạng mã hóa đặc thù nào của Java
  • Việc khởi tạo ban đầu nằm ngoài phạm vi. Giả định rằng ít nhất một máy chủ khác được ghi cứng hoặc cấu hình ngoài băng thông của giao thức này.
  • Hỗ trợ cả các trường hợp sử dụng ngoài băng thông và trong I2P.

Thiết kế

Giao thức Raft không phải là một giao thức cụ thể; nó chỉ định nghĩa một máy trạng thái. Do đó, chúng tôi tài liệu hóa giao thức cụ thể của JRaft và xây dựng giao thức của mình dựa trên đó. Không có thay đổi nào đối với giao thức JRaft ngoài việc thêm một bước bắt tay xác thực.

Raft bầu chọn một Leader có nhiệm vụ công bố một nhật ký (log). Nhật ký chứa dữ liệu Cấu hình Raft và dữ liệu Ứng dụng. Dữ liệu Ứng dụng chứa trạng thái của bộ định tuyến trên mỗi Máy chủ và Địa điểm (Destination) cho cụm Meta LS2. Các máy chủ sử dụng một thuật toán chung để xác định người công bố và nội dung của Meta LS2. Người công bố Meta LS2 KHÔNG nhất thiết phải là Raft Leader.

Đặc tả

Giao thức truyền tải được thực hiện qua cổng SSL hoặc cổng I2P không dùng SSL. Các cổng I2P được chuyển tiếp qua HTTP Proxy. Không hỗ trợ cổng rõ (clearnet) không dùng SSL.

Bắt tay và xác thực

Không được JRaft định nghĩa.

Mục tiêu:

  • Phương pháp xác thực người dùng/mật khẩu
  • Định danh phiên bản
  • Định danh cụm
  • Có thể mở rộng
  • Dễ dàng chuyển tiếp khi dùng cho cổng I2P
  • Không tiết lộ không cần thiết máy chủ như một máy chủ Garlic Farm
  • Giao thức đơn giản để không cần triển khai đầy đủ máy chủ web
  • Tương thích với các tiêu chuẩn phổ biến, để các triển khai có thể sử dụng các thư viện chuẩn nếu muốn

Chúng tôi sẽ sử dụng một giao thức bắt tay giống websocket và xác thực HTTP Digest RFC 2617 . Xác thực Cơ bản (Basic) theo RFC 2617 KHÔNG được hỗ trợ. Khi chuyển tiếp qua HTTP proxy, giao tiếp với proxy theo như được chỉ định trong RFC 2616 .

Chứng thực

Việc tên người dùng và mật khẩu được áp dụng theo cụm hay theo máy chủ là tùy thuộc vào triển khai.

Yêu cầu HTTP 1

Người khởi tạo sẽ gửi nội dung sau.

Tất cả các dòng đều kết thúc bằng CRLF như yêu cầu của HTTP.


GET /GarlicFarm/CLUSTER/VERSION/websocket HTTP/1.1
  Host: (ip):(port)
  Cache-Control: no-cache
  Connection: close
  (any other headers ignored)
  (blank line)

  CLUSTER là tên của cụm (mặc định là "farm")
  VERSION là phiên bản Garlic Farm (hiện tại là "1")

Phản hồi HTTP 1

Nếu đường dẫn không đúng, người nhận sẽ gửi phản hồi chuẩn “HTTP/1.1 404 Not Found”, như trong RFC 2616 .

Nếu đường dẫn đúng, người nhận sẽ gửi phản hồi chuẩn “HTTP/1.1 401 Unauthorized”, bao gồm tiêu đề xác thực HTTP digest WWW-Authenticate, như trong RFC 2617 .

Cả hai bên sau đó sẽ đóng cổng kết nối.

Yêu cầu HTTP 2

Người khởi tạo sẽ gửi nội dung sau, như trong RFC 2617 .

Tất cả các dòng đều kết thúc bằng CRLF như yêu cầu của HTTP.


GET /GarlicFarm/CLUSTER/VERSION/websocket HTTP/1.1
  Host: (ip):(port)
  Cache-Control: no-cache
  Connection: keep-alive, Upgrade
  Upgrade: websocket
  (Sec-Websocket-* headers if proxied)
  Authorization: (HTTP digest authorization header as in RFC 2617)
  (any other headers ignored)
  (blank line)

  CLUSTER là tên của cụm (mặc định là "farm")
  VERSION là phiên bản Garlic Farm (hiện tại là "1")

Phản hồi HTTP 2

Nếu xác thực không đúng, người nhận sẽ gửi thêm một phản hồi chuẩn “HTTP/1.1 401 Unauthorized”, như trong RFC 2617 .

Nếu xác thực đúng, người nhận sẽ gửi phản hồi sau, như trong giao thức WebSocket.

Tất cả các dòng đều kết thúc bằng CRLF như yêu cầu của HTTP.


HTTP/1.1 101 Switching Protocols
  Connection: Upgrade
  Upgrade: websocket
  (Sec-Websocket-* headers)
  (any other headers ignored)
  (blank line)

Sau khi nhận được điều này, cổng kết nối vẫn mở. Giao thức Raft như được định nghĩa bên dưới bắt đầu, trên cùng một cổng kết nối.

Bộ nhớ đệm

Chứng thực phải được lưu vào bộ nhớ đệm ít nhất một giờ, để các kết nối tiếp theo có thể nhảy trực tiếp đến “Yêu cầu HTTP 2” ở trên.

Các loại tin nhắn

Có hai loại tin nhắn: yêu cầu và phản hồi. Yêu cầu có thể chứa các mục nhật ký (Log Entries), và có kích thước thay đổi; phản hồi không chứa các mục nhật ký, và có kích thước cố định.

Các loại tin nhắn 1-4 là các tin nhắn RPC tiêu chuẩn do Raft định nghĩa. Đây là phần cốt lõi của giao thức Raft.

Các loại tin nhắn 5-15 là các tin nhắn RPC mở rộng do JRaft định nghĩa, để hỗ trợ khách hàng, thay đổi máy chủ động và đồng bộ nhật ký hiệu quả.

Các loại tin nhắn 16-17 là các tin nhắn RPC nén nhật ký (Log Compaction) được định nghĩa trong phần 7 của Raft.

Tin nhắnSốGửi bởiGửi đếnGhi chú
RequestVoteRequest1Ứng cử viên (Candidate)Người theo dõi (Follower)RPC chuẩn của Raft; không được chứa mục nhật ký
RequestVoteResponse2FollowerCandidateRPC chuẩn của Raft
AppendEntriesRequest3LeaderFollowerRPC chuẩn của Raft
AppendEntriesResponse4FollowerLeader / ClientRPC chuẩn của Raft
ClientRequest5ClientLeader / FollowerPhản hồi là AppendEntriesResponse; chỉ được chứa các mục nhật ký Ứng dụng
AddServerRequest6ClientLeaderChỉ được chứa một mục nhật ký ClusterServer duy nhất
AddServerResponse7LeaderClientLeader cũng sẽ gửi một JoinClusterRequest
RemoveServerRequest8FollowerLeaderChỉ được chứa một mục nhật ký ClusterServer duy nhất
RemoveServerResponse9LeaderFollower
SyncLogRequest10LeaderFollowerChỉ được chứa một mục nhật ký LogPack duy nhất
SyncLogResponse11FollowerLeader
JoinClusterRequest12LeaderMáy chủ mớiLời mời tham gia; chỉ được chứa một mục nhật ký Cấu hình duy nhất
JoinClusterResponse13Máy chủ mớiLeader
LeaveClusterRequest14LeaderFollowerLệnh rời khỏi
LeaveClusterResponse15FollowerLeader
InstallSnapshotRequest16LeaderFollowerRaft Mục 7; Chỉ được chứa một mục nhật ký SnapshotSyncRequest duy nhất
InstallSnapshotResponse17FollowerLeaderRaft Mục 7

Thiết lập

Sau khi bắt tay HTTP, chuỗi thiết lập như sau:


Máy chủ mới Alice              Người theo dõi ngẫu nhiên Bob

  ClientRequest   ------->
          <---------   AppendEntriesResponse

  Nếu Bob nói rằng nó là leader, tiếp tục như bên dưới.
  Nếu không, Alice phải ngắt kết nối với Bob và kết nối với leader.


  Máy chủ mới Alice              Leader Charlie

  ClientRequest   ------->
          <---------   AppendEntriesResponse
  AddServerRequest   ------->
          <---------   AddServerResponse
          <---------   JoinClusterRequest
  JoinClusterResponse  ------->
          <---------   SyncLogRequest
                       HOẶC InstallSnapshotRequest
  SyncLogResponse  ------->
  HOẶC InstallSnapshotResponse

Chuỗi ngắt kết nối:


Follower Alice              Leader Charlie

  RemoveServerRequest   ------->
          <---------   RemoveServerResponse
          <---------   LeaveClusterRequest
  LeaveClusterResponse  ------->

Chuỗi bầu cử:


Ứng cử viên Alice               Follower Bob

  RequestVoteRequest   ------->
          <---------   RequestVoteResponse

  nếu Alice thắng bầu cử:

  Leader Alice                Follower Bob

  AppendEntriesRequest   ------->
  (heartbeat)
          <---------   AppendEntriesResponse

Định nghĩa

  • Nguồn (Source): Xác định người khởi tạo tin nhắn
  • Đích (Destination): Xác định người nhận tin nhắn
  • Các kỳ hạn (Terms): Xem Raft. Được khởi tạo bằng 0, tăng đơn điệu
  • Chỉ mục (Indexes): Xem Raft. Được khởi tạo bằng 0, tăng đơn điệu

Yêu cầu

Yêu cầu chứa một tiêu đề và không hoặc nhiều mục nhật ký. Yêu cầu chứa một tiêu đề kích thước cố định và các Mục nhật ký tùy chọn có kích thước thay đổi.

Tiêu đề yêu cầu

Tiêu đề yêu cầu dài 45 byte, như sau. Tất cả các giá trị đều là số nguyên big-endian không dấu.


Loại tin nhắn:      1 byte
  Nguồn:            ID, số nguyên 4 byte
  Đích:             ID, số nguyên 4 byte
  Kỳ hạn:           Kỳ hạn hiện tại (xem ghi chú), số nguyên 8 byte
  Kỳ hạn nhật ký cuối:     số nguyên 8 byte
  Chỉ mục nhật ký cuối:    số nguyên 8 byte
  Chỉ mục cam kết:      số nguyên 8 byte
  Kích thước mục nhật ký:  Tổng kích thước tính bằng byte, số nguyên 4 byte
  Mục nhật ký:       xem bên dưới, tổng độ dài như đã chỉ định

Ghi chú

Trong RequestVoteRequest, Term là kỳ hạn của ứng cử viên. Trong các trường hợp khác, đó là kỳ hạn hiện tại của leader.

Trong AppendEntriesRequest, khi kích thước mục nhật ký bằng 0, tin nhắn này là tin nhắn heartbeat (giữ kết nối).

Mục nhật ký

Nhật ký chứa không hoặc nhiều mục nhật ký. Mỗi mục nhật ký như sau. Tất cả các giá trị đều là số nguyên big-endian không dấu.


Kỳ hạn:           số nguyên 8 byte
  Loại giá trị:     1 byte
  Kích thước mục:     Tính bằng byte, số nguyên 4 byte
  Mục:          độ dài như đã chỉ định

Nội dung nhật ký

Tất cả các giá trị đều là số nguyên big-endian không dấu.

Loại giá trị nhật kýSố
Ứng dụng1
Cấu hình2
ClusterServer3
LogPack4
SnapshotSyncRequest5

Ứng dụng

Nội dung Ứng dụng được mã hóa UTF-8 theo định dạng JSON . Xem phần Lớp Ứng dụng bên dưới.

Cấu hình

Được dùng để leader tuần tự hóa một cấu hình cụm mới và sao chép tới các máy ngang hàng. Chứa không hoặc nhiều cấu hình ClusterServer.


Chỉ mục nhật ký:  số nguyên 8 byte
  Chỉ mục nhật ký cuối:  số nguyên 8 byte
  Dữ liệu ClusterServer cho mỗi máy chủ:
    ID:                số nguyên 4 byte
    Độ dài dữ liệu Endpoint: Tính bằng byte, số nguyên 4 byte
    Dữ liệu Endpoint:     chuỗi ASCII dạng "tcp://localhost:9001", độ dài như đã chỉ định

ClusterServer

Thông tin cấu hình cho một máy chủ trong cụm. Chỉ được bao gồm trong tin nhắn AddServerRequest hoặc RemoveServerRequest.

Khi dùng trong tin nhắn AddServerRequest:


ID:                số nguyên 4 byte
  Độ dài dữ liệu Endpoint: Tính bằng byte, số nguyên 4 byte
  Dữ liệu Endpoint:     chuỗi ASCII dạng "tcp://localhost:9001", độ dài như đã chỉ định

Khi dùng trong tin nhắn RemoveServerRequest:


ID:                số nguyên 4 byte

LogPack

Chỉ được bao gồm trong tin nhắn SyncLogRequest.

Nội dung sau được nén bằng gz trước khi truyền:


Độ dài dữ liệu chỉ mục: Tính bằng byte, số nguyên 4 byte
  Độ dài dữ liệu nhật ký:   Tính bằng byte, số nguyên 4 byte
  Dữ liệu chỉ mục:     8 byte cho mỗi chỉ mục, độ dài như đã chỉ định
  Dữ liệu nhật ký:       độ dài như đã chỉ định

SnapshotSyncRequest

Chỉ được bao gồm trong tin nhắn InstallSnapshotRequest.


Chỉ mục nhật ký cuối:  số nguyên 8 byte
  Kỳ hạn nhật ký cuối:   số nguyên 8 byte
  Độ dài dữ liệu cấu hình: Tính bằng byte, số nguyên 4 byte
  Dữ liệu cấu hình:     độ dài như đã chỉ định
  Offset:          Vị trí dữ liệu trong cơ sở dữ liệu, tính bằng byte, số nguyên 8 byte
  Độ dài dữ liệu:        Tính bằng byte, số nguyên 4 byte
  Dữ liệu:            độ dài như đã chỉ định
  Hoàn tất:         1 nếu xong, 0 nếu chưa xong (1 byte)

Phản hồi

Tất cả phản hồi đều dài 26 byte, như sau. Tất cả các giá trị đều là số nguyên big-endian không dấu.


Loại tin nhắn:   1 byte
  Nguồn:         ID, số nguyên 4 byte
  Đích:          Thường là ID đích thực (xem ghi chú), số nguyên 4 byte
  Kỳ hạn:           Kỳ hạn hiện tại, số nguyên 8 byte
  Chỉ mục tiếp theo:     Được khởi tạo bằng chỉ mục nhật ký cuối của leader + 1, số nguyên 8 byte
  Được chấp nhận:    1 nếu được chấp nhận, 0 nếu không (xem ghi chú), 1 byte

Ghi chú

ID Đích thường là ID đích thực cho tin nhắn này. Tuy nhiên, đối với AppendEntriesResponse, AddServerResponse và RemoveServerResponse, đó là ID của leader hiện tại.

Trong RequestVoteResponse, Is Accepted là 1 nếu bỏ phiếu cho ứng cử viên (người yêu cầu), và 0 nếu không bỏ phiếu.

Lớp Ứng dụng

Mỗi Máy chủ định kỳ đăng dữ liệu Ứng dụng vào nhật ký trong một ClientRequest. Dữ liệu Ứng dụng chứa trạng thái của bộ định tuyến trên mỗi Máy chủ và Địa điểm (Destination) cho cụm Meta LS2. Các máy chủ sử dụng một thuật toán chung để xác định người công bố và nội dung của Meta LS2. Máy chủ có trạng thái “tốt nhất” gần đây nhất trong nhật ký là người công bố Meta LS2. Người công bố Meta LS2 KHÔNG nhất thiết phải là Raft Leader.

Nội dung dữ liệu Ứng dụng

Nội dung Ứng dụng được mã hóa UTF-8 theo định dạng JSON , để đơn giản và có thể mở rộng. Đặc tả đầy đủ sẽ được xác định sau. Mục tiêu là cung cấp đủ dữ liệu để viết một thuật toán xác định bộ định tuyến “tốt nhất” để công bố Meta LS2, và để người công bố có đủ thông tin để đánh trọng số các Địa điểm trong Meta LS2. Dữ liệu sẽ chứa cả thống kê bộ định tuyến và Địa điểm.

Dữ liệu có thể tùy chọn chứa dữ liệu cảm biến từ xa về tình trạng sức khỏe của các máy chủ khác, và khả năng truy xuất Meta LS. Những dữ liệu này sẽ không được hỗ trợ trong phiên bản đầu tiên.

Dữ liệu có thể tùy chọn chứa thông tin cấu hình do một khách hàng quản trị đăng. Những dữ liệu này sẽ không được hỗ trợ trong phiên bản đầu tiên.

Nếu “name: value” được liệt kê, điều đó chỉ định khóa và giá trị bản đồ JSON. Nếu không, đặc tả sẽ được xác định sau.

Dữ liệu cụm (cấp cao nhất):

  • cluster: Tên cụm
  • date: Ngày của dữ liệu này (dài, ms kể từ thời điểm gốc)
  • id: ID Raft (số nguyên)

Dữ liệu cấu hình (config):

  • Bất kỳ tham số cấu hình nào

Trạng thái công bố MetaLS (meta):

  • destination: địa điểm metals, mã hóa base64
  • lastPublishedLS: nếu có, mã hóa base64 của metals đã công bố gần nhất
  • lastPublishedTime: tính bằng ms, hoặc 0 nếu chưa từng
  • publishConfig: trạng thái cấu hình người công bố tắt/bật/tự động
  • publishing: trạng thái boolean người công bố metals đúng/sai

Dữ liệu bộ định tuyến (router):

  • lastPublishedRI: nếu có, mã hóa base64 của thông tin bộ định tuyến đã công bố gần nhất
  • uptime: Thời gian hoạt động tính bằng ms
  • Độ trễ công việc (Job lag)
  • Các đường hầm thăm dò (Exploratory tunnels)
  • Các đường hầm tham gia (Participating tunnels)
  • Băng thông đã cấu hình
  • Băng thông hiện tại

Các Địa điểm (destinations): Danh sách

Dữ liệu Địa điểm:

  • destination: địa điểm, mã hóa base64
  • uptime: Thời gian hoạt động tính bằng ms
  • Số lượng đường hầm đã cấu hình
  • Số lượng đường hầm hiện tại
  • Băng thông đã cấu hình
  • Băng thông hiện tại
  • Số lượng kết nối đã cấu hình
  • Số lượng kết nối hiện tại
  • Dữ liệu danh sách đen (Blacklist data)

Dữ liệu cảm biến bộ định tuyến từ xa:

  • Phiên bản RI gần nhất đã thấy
  • Thời gian truy xuất LS
  • Dữ liệu kiểm tra kết nối
  • Dữ liệu hồ sơ floodfill gần nhất cho các khoảng thời gian hôm qua, hôm nay và ngày mai

Dữ liệu cảm biến Địa điểm từ xa:

  • Phiên bản LS gần nhất đã thấy
  • Thời gian truy xuất LS
  • Dữ liệu kiểm tra kết nối
  • Dữ liệu hồ sơ floodfill gần nhất cho các khoảng thời gian hôm qua, hôm nay và ngày mai

Dữ liệu cảm biến Meta LS:

  • Phiên bản gần nhất đã thấy
  • Thời gian truy xuất
  • Dữ liệu hồ sơ floodfill gần nhất cho các khoảng thời gian hôm qua, hôm nay và ngày mai

Giao diện Quản trị

Sẽ được xác định sau, có thể là một đề xuất riêng. Không yêu cầu cho phiên bản đầu tiên.

Yêu cầu của một giao diện quản trị:

  • Hỗ trợ nhiều địa điểm chính, tức là nhiều cụm ảo (nông trại)
  • Cung cấp cái nhìn toàn diện về trạng thái cụm chia sẻ - tất cả các thống kê do các thành viên công bố, ai là leader hiện tại, v.v.
  • Khả năng buộc loại bỏ một thành viên hoặc leader khỏi cụm
  • Khả năng buộc công bố metaLS (nếu nút hiện tại là người công bố)
  • Khả năng loại trừ các băm khỏi metaLS (nếu nút hiện tại là người công bố)
  • Chức năng nhập/xuất cấu hình cho triển khai hàng loạt

Giao diện Bộ định tuyến

Sẽ được xác định sau, có thể là một đề xuất riêng. i2pcontrol không bắt buộc cho phiên bản đầu tiên và các thay đổi chi tiết sẽ được đưa vào một đề xuất riêng.

Yêu cầu cho API Garlic Farm tới bộ định tuyến (trong-JVM java hoặc i2pcontrol)

  • getLocalRouterStatus()
  • getLocalLeafHash(Hash masterHash)
  • getLocalLeafStatus(Hash leaf)
  • getRemoteMeasuredStatus(Hash masterOrLeaf) // có thể không có trong MVP
  • publishMetaLS(Hash masterHash, List contents) // hoặc MetaLeaseSet đã ký? Ai ký?
  • stopPublishingMetaLS(Hash masterHash)
  • xác thực TBD?

Cơ sở

Atomix quá lớn và sẽ không cho phép tùy chỉnh để chúng tôi định tuyến giao thức qua I2P. Ngoài ra, định dạng truyền tải của nó chưa được tài liệu hóa và phụ thuộc vào việc tuần tự hóa Java.

Ghi chú

Vấn đề

  • Không có cách nào để một khách hàng biết và kết nối tới một leader chưa biết. Chỉ cần thay đổi nhỏ để một Follower gửi Cấu hình như một Mục nhật ký trong AppendEntriesResponse.

Di chuyển

Không có vấn đề tương thích ngược.

Tài liệu tham khảo