1 điểm bởi GN⁺ 2024-05-17 | 1 bình luận | Chia sẻ qua WhatsApp
  • Datomic Pro 1.0.7075 trong các thử nghiệm cho thấy mức an toàn giữa các giao dịch có vẻ mạnh hơn tuyên bố trong tài liệu, nhưng ngữ nghĩa bên trong giao dịch lại khác đáng kể so với mô hình thực thi tuần tự thông thường
  • Tất cả lịch sử thử nghiệm đều có vẻ Serializable; một phiên peer đơn lẻ gần với Strong Session Serializable, còn các thao tác ghi và đọc bằng d/sync gần với Strong Serializable
  • Trong Datomic, add, retract và transaction function không được thực thi tích lũy theo thứ tự bên trong giao dịch; mỗi hàm hoạt động theo cách chỉ nhìn thấy trạng thái DB tại thời điểm bắt đầu
  • Nếu trong cùng một giao dịch kết hợp các transaction function vốn an toàn khi đứng riêng lẻ, như approvedeny, kết quả hợp thành có thể tạo ra vi phạm bất biến
  • Khi đưa nhiều transaction function vào một giao dịch, cần kiểm tra quan hệ giữa read set và write set, đồng thời dùng kèm các ràng buộc tường minh như entity predicate, attribute predicate và entity spec

Mô hình và kiến trúc của Datomic Pro

  • Datomic là một cơ sở dữ liệu OLTP Entity-Attribute-Value mô hình hóa khái niệm thời gian một cách tường minh
    • Trạng thái DB tại một thời điểm cụ thể được biểu diễn bằng tập các datom dạng [entity, attribute, value]
    • Mỗi datom cũng lưu lại giao dịch nào đã thêm hoặc rút lại nó
    • Một datom đầy đủ là một bộ 5 phần tử dạng [entity, attribute, value, transaction, asserted-or-retracted?]
  • Vì Datomic là temporal database, có thể yêu cầu snapshot không chỉ ở hiện tại mà còn theo thời điểm logic trong quá khứ hoặc thời điểm wall-clock
    • Cũng có thể truy vấn qua view lịch sử đầy đủ để biết một sự kiện cụ thể từng tồn tại trong quá khứ hay không
    • Về phương thức truy vấn, Datomic cung cấp API kiểu Datalog, API duyệt đồ thị và kiểu Entity theo phong cách ODM
  • Datomic Pro là phiên bản người dùng có thể tự vận hành, còn Datomic Cloud chạy trên AWS và có một số khác biệt về kiến trúc
  • Datomic Pro có cấu trúc gồm nhiều thành phần phối hợp với nhau
    • Transactor chịu trách nhiệm thực thi giao dịch ghi, duy trì chỉ mục và ghi vào storage
    • Peer là client dày có nhúng thư viện JVM, thực hiện việc gửi giao dịch, truy vấn đọc vào đích storage và cache
    • Với ứng dụng viết bằng ngôn ngữ khác, Datomic cũng cung cấp mô hình client-server dựa trên thin client và peer server
  • Bên trong, Datomic append mỗi giao dịch vào một log theo thứ tự thời gian và duy trì 4 chỉ mục được sắp xếp theo tổ hợp entity·attribute·value·time
    • Log và chỉ mục được lưu dưới dạng các cây bền vững và bất biến trên storage như Cassandra hoặc DynamoDB
    • Vì các node của cây là bất biến, backing storage chỉ cần bảo đảm eventual consistency
    • Khi commit, transactor lưu các node cây bất biến mới rồi tiến con trỏ root bằng compare-and-set(CaS); CaS này cần Sequential consistency
  • Sequential CaS bảo đảm thứ tự toàn cục của giao dịch, nhưng buộc thông lượng ghi bị giới hạn bởi tốc độ của một transactor duy nhất
    • Datomic thường chỉ có một active transactor tại một thời điểm và triển khai nhiều transactor để chịu lỗi
    • Peer kết nối trực tiếp với storage và transactor, đồng thời mỗi peer duy trì bản sao con trỏ root tăng đơn điệu của riêng mình
    • Các thao tác đọc có thể cache node cây bất biến, nên khi tăng số lượng peer thì gần như có thể mở rộng đọc tuyến tính

Mô hình giao dịch của Datomic

  • Datomic không cung cấp interactive transaction như các cơ sở dữ liệu OLTP thông thường
    • Đây không phải mô hình bắt đầu giao dịch, nhận kết quả phép toán, gửi phép toán tiếp theo rồi cuối cùng commit
    • Có transaction function tương tự stored procedure, nhưng không thể trả về giá trị tùy ý cho bên gọi
  • Đường đọc và đường ghi được tách biệt nghiêm ngặt
    • db trả về trạng thái DB mới nhất mà peer biết
    • d/sync đồng bộ với transactor để nhận trạng thái mới nhất theo mọi peer hoặc trạng thái sau một thời điểm cụ thể
    • d/as-of lấy trạng thái DB tại một thời điểm trong quá khứ
    • Vì trạng thái DB là bất biến, nhiều truy vấn trên cùng một trạng thái được thực thi chính xác tại cùng một thời điểm logic
  • Giao dịch ghi được biểu diễn dưới dạng ordered list các operation
    • Ví dụ bao gồm :db/add, :db/retract, db/cas và lời gọi transaction function do người dùng định nghĩa
    • Transaction function nhận trạng thái DB tại thời điểm bắt đầu giao dịch cùng các đối số, rồi trả về một tập operation mới
    • Các lời gọi hàm được mở rộng đệ quy cho đến khi chỉ còn assertion và retraction
  • Transaction function có thể thực hiện đọc bên trong để quyết định ghi có điều kiện, nhưng không trực tiếp trả về kết quả đọc hoặc thông tin tùy ý cho bên gọi transact
    • transact trả về trạng thái DB ngay trước giao dịch, trạng thái DB kết quả sau giao dịch và tập datom đã được mở rộng
    • Bên gọi có thể dùng pre-state và post-state để xác định ghi có điều kiện có xảy ra hay không
  • Datomic là mô hình được thiết kế để giải quyết vấn đề xoay quanh DB snapshot rẻ và có thể truyền được
    • Nubank là công ty hiện đang phát triển Datomic, cung cấp dịch vụ tài chính cho khoảng 94 triệu người dùng và xử lý trung bình 2,3 tỷ giao dịch người dùng mỗi ngày
    • Hầu hết mọi sản phẩm của Nubank đều dùng Datomic làm system of record

Các tuyên bố về tính nhất quán và thiết kế kiểm thử

  • Tài liệu Datomic tuyên bố các giao dịch ACID, cho rằng giao dịch được ghi vào storage bằng một atomic write duy nhất và mỗi peer quan sát tất cả giao dịch đã hoàn tất tới một thời điểm nhất định theo một tổng thứ tự
    • Trước khi client nhận acknowledgement, giao dịch được flush xuống durable storage
  • Tại thời điểm bắt đầu phân tích vào đầu tháng 1/2024, tài liệu tuyên bố không chính thức rằng các giao dịch ghi là Serializable
    • Tài liệu cũng gọi Datomic là hệ thống “single-writer”, nhưng Jepsen cho rằng mô tả này không chính xác vì hai lý do
    • Để chịu lỗi có thể vận hành nhiều transactor, và vì bộ phát hiện lỗi không thể hoàn hảo, có thể xuất hiện khoảng thời gian trong đó nhiều transactor cùng cho rằng mình đang active
    • Ngay cả khi chỉ có một transactor, độ trễ mạng có thể khiến các thông điệp storage bị interleave với thông điệp từ transactor khác
  • Độ an toàn của Datomic được đánh giá là đến từ Sequential consistency của thao tác CaS trên storage, chứ không phải từ lập luận “single-writer”
    • Ngay cả khi có nhiều transactor concurrent, CaS vẫn phải cung cấp độ an toàn
  • Kiểm thử dùng Datomic test suite được viết bằng Jepsen testing library
    • Datomic Pro 1.0.7075 được cài trên một cụm node Debian Bookworm
    • Storage dùng AWS DynamoDB table
    • Hai node chạy transactor, các node còn lại chạy peer
  • Peer là một chương trình Clojure nhỏ dùng Datomic peer library và expose HTTP API cho các thao tác kiểm thử
    • Kiểm thử chạy cả chế độ có khả năng stale read dùng d/db và chế độ bảo đảm tính mới nhất bằng d/sync
  • Fault injection được áp dụng cho cả transactor và peer
    • Chèn process pause, crash, clock error
    • Tạo network partition giữa transactor và peer, cũng như giữa node và storage
    • Cũng yêu cầu Datomic garbage collection
  • Transactor sẽ tự thoát nếu không duy trì được kết nối ổn định với storage
    • Với các node ngoài AWS dùng timeout mặc định 5 giây, chỉ biến động mạng bình thường cũng khiến nó thoát vài phút một lần
    • Ngay cả trong môi trường kiểm thử EC2, với timeout 1 giây nó cũng thoát mỗi 10–20 phút
    • Datomic khuyến nghị operator khởi động lại transactor bằng supervisor daemon, và bài kiểm thử dùng systemd service với thiết lập Restart=on-failure

Bốn workload

  • List Append

    • Workload List Append được dùng cùng Elle transaction checker
    • Về mặt logic, workload xử lý các danh sách phần tử số nguyên, mỗi danh sách được nhận diện bằng một primary key kiểu số nguyên
    • Client thực hiện các giao dịch ngẫu nhiên gồm đọc danh sách hoặc append phần tử duy nhất
    • Elle kiểm tra aborted read, intermediate read, vi phạm internal consistency, sai khác thứ tự phần tử, và tìm cycle trong dependency graph để phán định vi phạm mô hình nhất quán
    • Trong Datomic, danh sách được mã hóa bằng một entity và hai thuộc tính
    • append/key đóng vai trò primary key
    • append/elements là thuộc tính đa trị lưu các phần tử số nguyên của danh sách
    • Vì thuộc tính đa trị là set không có thứ tự, Jepsen sắp xếp các phần tử theo transaction timestamp của từng datom để lấy thứ tự mà Elle cần
    • Ràng buộc không có mixed read-write transaction được vượt qua bằng transaction function và tính toán pre-state
    • Các thao tác ghi được thực hiện bằng transaction function
    • Dùng pre-state mà transact trả về để tính các lần đọc bên trong giao dịch đã thấy gì
    • Cùng một hàm được chạy một lần trong transact, và một lần ở peer để bổ sung phần đọc dựa trên pre-state
  • List Append with CaS

    • Workload List Append with CaS dùng pattern db/cas
    • Người dùng có thể đọc trạng thái hiện tại bằng d/db rồi gửi, ví dụ, [:db/cas 123 :counter/value 4 5] để chỉ đổi giá trị thành 5 khi giá trị đang là 4
    • Nếu dùng db/cas cho mọi thao tác ghi, có thể tạo một Snapshot Isolation ad hoc trên “user transaction” logic
    • Workload này lưu danh sách không phải dưới dạng đa trị, mà dưới dạng chuỗi single-valued phân tách bằng dấu phẩy
    • Khi bắt đầu giao dịch, nó đọc, áp dụng các thao tác đọc/ghi cục bộ, rồi dựng giao dịch CaS bảo đảm giá trị không đổi kể từ sau lần đọc
  • Internal

    • Workload Internal đo trực tiếp tính nhất quán bên trong giao dịch
    • Trường hợp assert 1 rồi assert 2 trên cùng entity attribute
    • Trường hợp assert rồi retract một fact trong cùng giao dịch
    • Trường hợp assert một giá trị rồi cố đổi bằng CaS
    • Trường hợp thực hiện nhiều CaS như 1→2, 2→3
    • Trường hợp tạo entity rồi sửa bằng lookup ref
    • Bao gồm cả trường hợp cố increment giá trị hai lần bằng transaction function
  • Grant

    • Workload Grant kiểm tra liệu transaction function có bảo toàn bất biến của hàm hay không
    • grant được mã hóa thành một entity duy nhất có ba thuộc tính created-at, approved-at, denied-at
    • grant không được đồng thời ở trạng thái approved và denied
    • Các hàm approvedeny trước hết kiểm tra grant đã approved hoặc denied chưa, và abort nếu cần
    • Kiểm tra xem grant có trở thành đồng thời approved và denied trong nhiều tổ hợp transaction boundary hay không

Kết quả kiểm thử: độ an toàn giữa các giao dịch có vẻ mạnh

  • Jepsen không tìm thấy hành vi trái với các tuyên bố cốt lõi về độ an toàn của Datomic
    • Các giao dịch dường như được áp dụng theo total order
    • Thứ tự đó khớp với local operation order ở mỗi peer
  • Các lịch sử chỉ giới hạn ở giao dịch ghi, và các lịch sử dùng (d/sync conn) khi đọc, khớp với real-time order
    • Jepsen cho rằng điều này có vẻ là Strict Serializable
  • Nếu diễn giải bằng cách gắn session với một peer duy nhất, Datomic có vẻ bảo đảm Strong Session Serializability
    • Lịch sử giao dịch không thể phân biệt với lịch sử được thực thi theo một total order nào đó
    • Order đó khớp với thứ tự được quan sát ở từng peer
  • d/db trả về bản sao DB được cập nhật bất đồng bộ, nên có thể xảy ra stale read
    • Tài liệu Datomic cũng nêu rõ peer read có thể không quan sát được một phần các giao dịch vừa commit gần đây
    • d/sync đồng bộ với transactor để tránh stale read
  • Việc kiểm chứng thực nghiệm vẫn có giới hạn
    • Có thể chứng minh sự tồn tại của bug, nhưng không thể chứng minh bug không tồn tại
    • Correctness error trong hệ thống storage mà Datomic phụ thuộc có thể dẫn đến vi phạm bảo đảm của Datomic
    • Datomic chạy trên DynamoDB an toàn ở mức thao tác compare-and-set của DynamoDB

Ngữ nghĩa bên trong giao dịch: không phải thứ tự, mà là tính đồng thời

  • Hầu hết cơ sở dữ liệu và các hình thức hóa chính về cô lập giao dịch cung cấp ngữ nghĩa thực thi tuần tự bên trong giao dịch
    • Nếu là set x = 1; read x; thì read thường thấy 1
    • Các hình thức hóa của Adya, Cerone·Bernardi·Gotsman, Crooks·Alvisi·Pu·Clement, v.v. nêu rõ thứ tự operation bên trong giao dịch và tính chất “write trước đó được read sau đó quan sát thấy”
  • Transaction request của Datomic là ordered list, nhưng khi thực thi không bảo toàn thứ tự đó
    • add, retract, transaction function hoạt động như thể được thực thi đồng thời với nhau
    • transaction function luôn quan sát trạng thái DB tại thời điểm bắt đầu giao dịch
    • Không thấy hiệu ứng của assertion, retraction, transaction function trước đó
  • Nếu đưa cùng một CaS hai lần vào một entity có giá trị hiện tại là 0, trong Datomic cả hai đều thấy trạng thái ban đầu 0 và thành công
[[:db/cas 123 :internal/value 0 1]
 [:db/cas 123 :internal/value 0 1]]
  • Theo mô hình tuần tự, CaS đầu tiên phải đổi giá trị thành 1 và CaS thứ hai phải thất bại
    • Trong Datomic, hai CaS tạo ra assertion trùng lặp và giá trị cuối cùng là 1
  • Hai increment transaction function cũng cho kết quả khác với mô hình tuần tự
[['internal/increment "x"]
 ['internal/increment "x"]]
  • Nếu giá trị ban đầu là 0, kết quả của mô hình tuần tự là 2
  • Trong Datomic, cả hai hàm đều thấy trạng thái ban đầu 0 và giá trị cuối cùng là 1
  • transaction function cũng không thấy assertion phía trước
[[:db/add id-of-x :internal/value 1]
 ['internal/increment "x"]]
  • Trong Datomic, giá trị cuối cùng trở thành 1, không phải 2
  • lookup ref cũng dùng trạng thái DB tại thời điểm bắt đầu giao dịch
    • Không thể thêm entity trong cùng một giao dịch rồi tham chiếu entity đó bằng lookup ref
    • Trường hợp này bị abort với lỗi Unable to resolve entity

Phát hiện xung đột và pseudo write skew

  • Datomic abort với :db.error/datoms-conflict nếu trong cùng một giao dịch assert các giá trị khác nhau cho một thuộc tính cardinality đơn
    • Với giá trị ban đầu 0, nếu assert giá trị 2 đồng thời increment function tạo assertion giá trị 1, sẽ xảy ra xung đột
    • Phát hiện xung đột này có khả năng ngăn nhiều kết quả bất ngờ phát sinh từ việc tổng hợp sai transaction function
  • Nếu write set là các cặp [entity, attribute] khác nhau, rất khó giữ bất biến chỉ bằng phát hiện xung đột
    • Workload grant cho thấy tình huống này
    • approvedeny lần lượt kiểm tra rằng grant chưa được approved cũng chưa bị denied, rồi thêm các thuộc tính khác nhau
  • Nếu gọi approvedeny trong các giao dịch khác nhau, các giao dịch Serializable của Datomic bảo đảm bất biến
    • Nhưng nếu gọi cả hai cùng trong một giao dịch, cả hai đều thấy trạng thái ban đầu và thành công
[['grant/approve id]
 ['grant/deny id]]
  • Kết quả là grant có cả approved-at lẫn denied-at
    • Bất biến “grant không được đồng thời approved và denied” bị phá vỡ
    • Trình kiểm tra xung đột in-transaction của Datomic không ngăn điều này vì hai hàm tạo assertion trên các thuộc tính khác nhau
  • Hiện tượng này tương tự Write Skew của Berenson và cộng sự
    • Hai hàm không thấy hiệu ứng của nhau, tạo ra read-write anti-dependency cycle
    • Nếu xem transaction function như giao dịch, nó tương tự anomaly G2-item mà Repeatable Read và Serializability cấm
  • Datomic và Nubank xem hành vi này là hành vi kỳ vọng của Datomic, không phải lỗi
    • Nubank dự định duy trì concurrent intra-transaction semantics của Datomic

Củng cố bất biến bằng entity predicate

  • Datomic cung cấp các cơ chế ràng buộc như type, uniqueness, attribute predicate cụ thể, entity predicate
    • entity predicate nhận trạng thái DB candidate sau khi đã áp dụng mọi hiệu ứng giao dịch cùng entity ID, rồi trả về true hoặc false để quyết định có cho phép commit hay không
    • Dù tên là entity predicate, nó có thể truy cập toàn bộ trạng thái DB nên cũng biểu diễn được các ràng buộc toàn cục vượt ra ngoài một entity cụ thể
  • Trong ví dụ grant, có thể dùng predicate valid-grant? để bảo đảm approved-atdenied-at không tồn tại đồng thời
(defn valid-grant?
  [db eid]
  (let [{:grant/keys [approved-at denied-at]}
        (d/pull db '[:grant/approved-at
                     :grant/denied-at]
                   eid)]
   (not (and approved-at denied-at))))
  • Trong schema, thêm entity spec để tham chiếu predicate này
    • entity predicate được liên kết với entity spec không tự động áp dụng cho mọi giao dịch
    • Datomic xem việc có áp dụng entity spec hay không là domain decision, và cho rằng mỗi giao dịch phải yêu cầu rõ ràng
  • Các hàm approvedeny có thể thêm thuộc tính rồi yêu cầu áp dụng entity spec bằng virtual datom :db/ensure
(defn approve
  [db id]
  [[:db/add id :grant/approved-at (Date.)]
   [:db/add id :db/ensure :grant/valid?]])
  • Khi dùng entity spec này, nếu thử approve và deny cùng trong một giao dịch, lỗi entity predicate sẽ xảy ra và bất biến được bảo toàn
    • Lỗi bao gồm :db.error/entity-pred, :db.error/pred-return false

Thay đổi tài liệu và khuyến nghị cho người dùng

  • Datomic đã chỉnh sửa đáng kể tài liệu sau khi hợp tác với Jepsen
    • transaction safety documentation phản ánh mức an toàn mạnh hơn mà Datomic được cho là thực sự cung cấp
    • Nêu rõ Serializability toàn cục, monotonicity theo từng peer, và Strict Serializability đối với các thao tác đọc sử dụng ghi hoặc sync
    • Lập luận “single-writer” đã được loại bỏ khỏi tài liệu về an toàn
  • Tài liệu transaction syntax and semantics trình bày toàn diện về cấu trúc transaction request, quy tắc mở rộng map form và transaction function, cũng như quá trình áp dụng transaction
  • Tài liệu transaction functions cũng đã được sửa đổi
    • Giải thích nhiều cơ chế bảo đảm consistency, việc tạo và gọi hàm, cũng như hành vi của các hàm tích hợp sẵn
    • Các cách diễn đạt rằng transaction function có thể “atomically analyze and transform database values” hoặc bảo đảm “atomic read-modify-write processing” đã được loại bỏ
  • Datomic dự định từ nay gọi cấu trúc dữ liệu được truyền vào d/transacttransaction request thay vì “transaction”
    • Các phần tử của nó sẽ được gọi là “data” thay vì “statements” hay “operations”
    • [:db/add ...][:db/retract ...] lần lượt là assertion request và retraction request
    • Điều này giúp phân biệt datom assertion thực tế với assertion request chưa hoàn chỉnh bên trong transaction request
  • Những điểm người dùng cần lưu ý là rõ ràng
    • Có thể tin cậy Serializability giữa các transaction của Datomic
    • Concurrent execution semantics bên trong transaction là một lựa chọn hiếm gặp, nên cần thận trọng khi gọi nhiều transaction function trong cùng một transaction
    • Đặc biệt cần chú ý trường hợp read set chồng lấn còn write set tách biệt
    • Nhiều phép increment có thể âm thầm bị collapse thành một update duy nhất
    • Có thể sử dụng attribute predicate và entity spec, nhưng entity spec phải được yêu cầu rõ ràng trong mọi transaction cần đến nó
  • Về mặt vận hành, cũng cần tính đến việc transactor khởi động lại và biến động mạng
    • Datomic transactor sẽ tự thoát nếu không thể giao tiếp với storage trong vài phút
    • Jepsen khuyến nghị bổ sung retry loop cho transactor để chịu được biến động mạng tốt hơn

Giới hạn và câu hỏi nghiên cứu trong tương lai

  • Trong thử nghiệm lần này vẫn còn các hạng mục nằm ngoài phạm vi đánh giá
    • Không đánh giá excision và historical query
    • Cũng không khảo sát Datomic client library, nhưng Jepsen cho rằng hành vi của nó có khả năng tương tự peer dùng cho thử nghiệm
    • Chỉ sử dụng một storage engine là DynamoDB
    • Datomic Cloud cũng không được đánh giá, và Datomic Cloud sử dụng kiến trúc hơi khác
  • Jepsen cho biết họ hầu như không biết hệ thống hay hình thức hóa nào cung cấp đồng thời Serializability giữa các transaction và concurrent semantics bên trong transaction
  • Mô hình của Datomic đặt ra nhiều câu hỏi nghiên cứu
    • Liệu transaction của Datomic có thể được xem là dual của transaction truyền thống hay mô hình “co-transaction” hay không
    • Liệu ưu và nhược điểm của mô hình này có thể được giảm nhẹ bằng static analysis, runtime check, hoặc API extension hay không
    • Khả năng người dùng thực tế viết transaction phá vỡ invariant là cao đến mức nào
  • Các đối tượng so sánh được nhắc đến gồm dự án nghiên cứu temporal Datalog Alvaro’s DedalusFauna
    • Dedalus cũng có transaction diễn ra “all at once” như Datomic
    • Fauna là temporal database, đồng thời hỗ trợ đến Strong Serializability, và khác với Datomic, có vẻ cung cấp serial execution cùng incremental side effect bên trong transaction
  • Sự tương đồng giữa end-of-transaction conflict checker của Datomic và quy tắc first-committer-wins của Snapshot Isolation cũng vẫn là một cơ hội nghiên cứu
    • Phần nào trong tài liệu về Snapshot Isolation có thể áp dụng cho Datomic
    • Cycle bên trong transaction của Datomic được biểu diễn bằng loại anti-dependency edge nào
    • Liệu có analogue trong ngữ nghĩa nội bộ tương ứng với các hiện tượng như lost update, Fractured Read, read-only transaction anomaly, Long Fork hay không vẫn là câu hỏi bỏ ngỏ
  • Cũng có thể xem xét thêm mối liên hệ với CALM theorem
    • Liệu transaction function monotonic về mặt logic có thể được kết hợp an toàn trong cùng một Datomic transaction hay không
    • Có thể nghiên cứu liệu chương trình Datalog không có negation có an toàn trong mô hình thực thi này hay không

1 bình luận

 
GN⁺ 2024-05-17
Ý kiến trên Hacker News
  • Tôi đã đứng bên cạnh theo dõi công việc này diễn ra, và việc chứng kiến quá trình thảo luận thực sự rất thú vị
    Việc Jepsen không tìm thấy lỗi nghiêm trọng nào cũng đáng ngạc nhiên, và chỉ riêng việc làm rõ tài liệu cùng các hành vi đặc thù có chủ đích đã là một kết quả rất hữu ích
    Nghĩ đến việc đang vận hành một ngân hàng trên Datomic, đây hoàn toàn là một bài tập đáng giá để xây dựng niềm tin

    • Nếu xét rằng đây là cơ sở dữ liệu do Rich Hickey thiết kế thì kết quả cũng không quá bất ngờ
      Bài viết thật sự xuất sắc, và mỗi khi cảm thấy mình khá thông minh, đọc một phân tích Jepsen là cách rất tốt để trở nên khiêm tốn hơn
    • Cho tôi hỏi đó là ngân hàng nào được không?
    • Về đoạn “việc Jepsen không tìm thấy lỗi nghiêm trọng nào cũng đáng ngạc nhiên”, báo cáo có nói rằng “có thể chứng minh sự tồn tại của lỗi, nhưng không thể chứng minh sự vắng mặt của lỗi
    • Trước khi vận hành ngân hàng trên đó, các bạn không tự mình thực hiện kiểu kiểm chứng này sao?
  • Đây là lần đầu tiên tôi đọc kỹ một báo cáo Jepsen, và tôi thích phần giải thích rõ ràng về cơ chế hoạt động bên trong của transaction trong Datomic
    Tôi cũng nhận ra mình đã không hiểu sự khác biệt giữa transaction của Datomic và transaction của cơ sở dữ liệu SQL đến mức nào
    Đặc biệt, đoạn này rất đáng chú ý: “Trước đây Datomic gọi cấu trúc dữ liệu được truyền vào d/transact là ‘transaction’, và gọi các phần tử của nó là ‘statements’ hoặc ‘operations’. Từ nay, chúng tôi muốn gọi cấu trúc này là ‘transaction request’, và các phần tử của nó là ‘data’”
    Tôi tò mò điều này có ý nghĩa gì đối với d/transact-async trong namespace datomic.api và các chức năng liên quan
    Tôi đã không dùng Datomic gần một năm rồi, và có vẻ như rất nhiều thứ đã thay đổi

    • Kết quả kiểm thử Jepsen không đòi hỏi phải thay đổi gì trong phần mềm Datomic
      Mọi chức năng của datomic.api vẫn giữ nguyên
  • Đây là một báo cáo tuyệt vời và chi tiết về một cơ sở dữ liệu thật sự tốt
    Việc tài liệu được làm rõ và cập nhật cũng rất đáng mừng
    Nhân tiện, sẽ thật tuyệt nếu Apple chi trả cho một phân tích Jepsen về FoundationDB
    Tôi biết Aphyr từng nói rằng “các bài kiểm thử của họ có lẽ tốt hơn”, nhưng nếu Jepsen thực sự không tìm thấy vấn đề nào trong FoundationDB, đó sẽ là một bằng chứng mạnh mẽ nữa cho thấy đây là một cơ sở dữ liệu xuất sắc

    • Tôi hoàn toàn không có ý muốn lấy đi kế sinh nhai của Aphyr, nhưng tôi thắc mắc liệu có lý do cụ thể nào khiến một contributor đủ động lực không thể tự tạo các bài kiểm thử Jepsen, hay chi phí của nó đắt đến mức ngay cả kiểu “giống GoFundMe” cũng khó kham nổi
      Tôi không rành lĩnh vực này, nhưng mỗi khi nghe câu “giá như $foo chịu chi trả” thì tôi lại thấy hứng thú
      Vốn thì có thừa, nhưng theo kinh nghiệm của tôi, chờ Apple làm điều gì đó thường sẽ mất rất lâu
  • Jepsen đã tìm ra một tình huống rõ ràng dẫn đến vi phạm bất biến, và điều gây ấn tượng là phản hồi từ phía Datomic dường như chỉ là làm rõ tài liệu
    Rốt cuộc có phải đội Datomic chấp nhận rằng những vi phạm như vậy xảy ra nhưng không bận tâm không?
    Bài viết nói rằng “theo góc nhìn của Datomic, vi phạm bất biến trong workload grant là lỗi người dùng. Các hàm giao dịch không được thực thi tuần tự một cách nguyên tử. Nếu các thao tác khác trong giao dịch có thể làm mất hiệu lực tiền điều kiện đó, thì việc kiểm tra tiền điều kiện trong hàm giao dịch là không an toàn”

    • Như Jepsen đã xác nhận, cơ chế cưỡng chế bất biến của Datomic hoạt động đúng như thiết kế
      Để xem điều này có ý nghĩa gì từ góc nhìn người dùng, có thể nghĩ tới dữ liệu giả lập giao dịch như sau
      [ [Stu favorite-number 41] ;; maybe more stuff [Stu favorite-number 42] ]
      Nếu đọc theo nghĩa vận hành, trông như ở đầu giao dịch tôi thích 41, rồi về sau lại thích 42
      Sau khi giao dịch kết thúc, người quan sát sẽ kỳ vọng thấy tôi chỉ thích 42, và phải lo trong điều kiện nào thì có thể thấy 41
      Cách diễn giải vận hành này về ngữ nghĩa bên trong giao dịch khá phổ biến ở nhiều cơ sở dữ liệu, nhưng nó giả định rằng trong một giao dịch có nhiều thời điểm
      Datomic không có những thời điểm như vậy, cũng không muốn có, và ưu tiên việc không phải lo “giữa chừng trong giao dịch” đã xảy ra chuyện gì
      Trong Datomic, mọi fact của một giao dịch đều xảy ra tại cùng một thời điểm, nên giao dịch này nói rằng tôi bắt đầu thích đồng thời cả hai con số
      Nếu đọc sai giao dịch Datomic như một tổ hợp của nhiều thao tác, tất nhiên có thể tìm ra đủ loại “bất thường về bất biến”
      Ngược lại, nếu áp nhầm mô hình Datomic lên giao dịch SQL, cũng có thể tìm ra “bất thường về bất biến”
      Vì khả năng hiểu nhầm như vậy, tài liệu tốt là cần thiết; chúng tôi đã cải thiện tài liệu cùng Jepsen [1], chỉnh lại các cách diễn đạt dễ gây bất cẩn và cố giảm hiểu nhầm
      Chúng tôi cũng thêm một ghi chú kỹ thuật trực tiếp xử lý hiểu nhầm cụ thể này [2]
      [1] https://docs.datomic.com/transactions/transactions.html#tran...
      [2] https://docs.datomic.com/tech-notes/comparison-with-updating...
    • Tóm lại, gần với “đây là một cái bẫy tiềm tàng, nhưng nhất quán với tài liệu và hoạt động đúng như thiết kế”
      Việc nó có thực sự quan trọng hay không phụ thuộc vào việc người dùng viết hàm giao dịch để cố bảo toàn bất biến nào, và hàm đó có chỉ giữ được bất biến khi được thực thi tuần tự chứ không phải đồng thời hay không
      Lập trường của Datomic, hoặc điều tôi mong phía Datomic vào nói rõ, là người dùng không thường xuyên viết các hàm giao dịch như vậy
      Lập trường này có thể bảo vệ được. Bởi tài liệu đã nêu rõ rằng các hàm giao dịch không quan sát lẫn nhau, mà quan sát trạng thái lúc bắt đầu giao dịch
      Mặt khác, tài liệu cũng có cách diễn đạt ngụ ý rằng hàm giao dịch có thể được dùng để bảo toàn bất biến: “[txn fns] can atomically analyze and transform database values. You can use them to ensure atomic read-modify-update processing, and integrity constraints...”
      Vì cách diễn đạt này, cùng thực tế là gần như mọi cơ sở dữ liệu khả tuần tự khác đều dùng ngữ nghĩa tuần tự bên trong giao dịch, báo cáo đã dành nhiều dung lượng cho vấn đề này
      Đây là câu hỏi phức tạp, không có câu trả lời rõ ràng, và tôi muốn nghe cộng đồng cơ sở dữ liệu nói chung, đặc biệt là người dùng Datomic, tiếp nhận ngữ nghĩa này như thế nào
    • Tôi nghĩ cuối mục 3.1 của bài đã đưa ra câu trả lời rồi: “Hành vi này có thể gây ngạc nhiên, nhưng nhìn chung nhất quán với tài liệu Datomic. Nubank không có kế hoạch thay đổi hành vi này, và chúng tôi không xem đây là lỗi”
      Nói “tình huống dẫn đến vi phạm bất biến” nghe như lỗi của Datomic, nhưng không phải vậy
      Cần hiểu cách Datomic xử lý giao dịch và viết mã cho phù hợp
      Không liên quan đến Nubank, nhưng khi dùng Datomic như cơ sở dữ liệu đa dụng, tôi chưa từng gặp tình huống nào mà điều này trở thành vấn đề
    • Nghe giống tình huống ở một số cơ sở dữ liệu quan hệ, khi muốn cập nhật dựa trên giá trị vừa chọn thì cần biết rằng phải dùng SELECT ... FOR UPDATE
  • Bổ sung cho những ai chưa biết: tên Jepsen là một lối chơi chữ lấy từ Carly Rae Jepsen, người hát “call me maybe”
    Tôi nghĩ đó là cái tên hoàn hảo cho một dự án nghiên cứu hệ thống phân tán

  • Tôi chưa dùng Datomic lâu trong thực tế, nhưng nó vốn quá đặc thù nên tôi tự hỏi trong này có gì đáng ngạc nhiên không
    Giao dịch Datomic về cơ bản gần với xử lý theo lô, và tôi luôn nghĩ chúng là đơn luồng, nên việc không có nhiều race condition có vẻ là điều đương nhiên
    Về thiết kế thì nó nghiêng về chậm và an toàn

    • Ví dụ “nếu tăng x hai lần trong cùng một giao dịch thì kết quả là x+1 chứ không phải x+2” có vẻ khá quan trọng
      Có lẽ phải hết sức cẩn thận
    • Datomic có nén transaction log vào lúc nào đó không?
  • Cảm ơn Kyle
    Rõ ràng tài liệu của chúng tôi còn chưa đầy đủ
    Cùng với Rich, chúng tôi đã cố viết tài liệu rõ ràng và toàn diện hơn về mô hình giao dịch của Datomic
    Hy vọng có thể ngăn trước các hiểu nhầm phổ biến, và chúng tôi hoan nghênh mọi phản hồi
    https://docs.datomic.com/transactions/model.html

  • Mô hình dữ liệu của Datomic khá trực quan nếu bạn quen với kho lưu trữ triple hoặc RDF
    Tuy nhiên, trong tài liệu hay các thảo luận trực tuyến, những điểm tương đồng này thường không được nhắc đến
    Tôi tự hỏi liệu có phải vì mọi người không quen với các khái niệm đó, hay vì các liên tưởng liên quan đến Semantic Web bị xem là yếu tố gây nhiễu, hoặc có khác biệt căn bản nào đó mà tôi đã bỏ sót

  • Tôi đã thật sự chờ đợi bài phân tích này
    Gần đây tôi đang tự xây một kho dữ liệu giống Datomic, nên có vẻ sẽ hữu ích; hiện tôi đang đọc
    Bài phân tích MongoDB cũng thú vị, và các phân tích khác như Redis, RethinkDB cũng rất đáng xem
    Hy vọng một ngày nào đó cũng sẽ có phân tích về rqlite/dqlite hoặc turso/libsql