2 điểm bởi GN⁺ 2024-05-21 | 1 bình luận | Chia sẻ qua WhatsApp
  • Nền tảng thanh toán của Uber đã tích lũy dữ liệu sổ cái từ năm 2017, vượt hơn 1 nghìn tỷ bản ghi và đạt quy mô hàng PB, nên họ chuyển từ cấu trúc kết hợp DynamoDB·TerraBlob·LedgerStore sang lấy LedgerStore làm trung tâm
  • Do gánh nặng chi phí của DynamoDB, cấu trúc trước đây chỉ giữ 12 tuần dữ liệu gần đây, và LedgerStore — một kho lưu trữ kiểu sổ cái chỉ ghi thêm — đã được chọn làm giải pháp dài hạn
  • Việc xác minh được thực hiện song song bằng shadow validation sao chép lưu lượng production và xác minh ngoại tuyến so sánh toàn bộ bản dump, qua đó tách riêng rủi ro của dữ liệu hiện tại và dữ liệu lạnh để kiểm tra
  • Backfill có thể tạo tải lớn hơn lưu lượng bình thường, nên được triển khai dần dần với các lô nhỏ, tính idempotent, kiểm soát tốc độ, dừng khẩn cấp và tách riêng các bản ghi có vấn đề
  • Quá trình chuyển đổi được rollout thận trọng trong vài tuần, và sau fallback ban đầu cùng việc giữ dữ liệu DynamoDB thêm một tháng, họ hoàn tất backup cuối cùng và xóa bảng mà không gây gián đoạn

Đối tượng di chuyển và cấu trúc lưu trữ cũ

  • Nền tảng thanh toán Gulfstream của Uber khi ra mắt năm 2017 đã sử dụng DynamoDB làm kho lưu trữ
  • Khi chi phí DynamoDB tăng cao ở quy mô của Uber, cấu trúc lưu trữ được chia thành ba nhánh
    • Dữ liệu nóng của 12 tuần gần nhất được lưu trong DynamoDB
    • Dữ liệu lạnh cũ hơn được lưu trong TerraBlob, hệ thống blob store nội bộ của Uber
    • Dữ liệu cũng đã được ghi vào LedgerStore, và đây trở thành đích di chuyển cuối cùng
  • Phạm vi di chuyển là dữ liệu sổ cái của toàn bộ hoạt động kinh doanh Uber kể từ năm 2017
    • Bản ghi bất biến: 1.2PB theo dung lượng đã nén
    • Chỉ mục phụ: 0.5PB theo dung lượng chưa nén
  • Bản ghi sổ cái về thực chất không thể thay đổi sau khi đã ghi, còn dữ liệu chỉ mục phụ có thể được chỉnh sửa khi cần khắc phục sự cố

Lý do chọn LedgerStore

  • LedgerStore là một cơ sở dữ liệu kiểu sổ cái chỉ ghi thêm
  • Thiết kế tối ưu cho dữ liệu thanh toán phù hợp với yêu cầu của Gulfstream
    • Tính bất biến có thể kiểm chứng, xác nhận bản ghi có bị thay đổi hay không bằng chữ ký mật mã
    • Lưu trữ phân tầng, tách dữ liệu nóng và dữ liệu lạnh theo nhu cầu xử lý yêu cầu và chi phí lưu trữ
    • Đặc tính độ trễ tốt hơn cho các chỉ mục phụ có tính nhất quán cuối cùng
  • Việc giảm từ ba kho lưu trữ xuống còn một giúp đơn giản hóa mã truy cập lưu trữ và thiết kế tạo chỉ mục của Gulfstream
  • LedgerStore chạy on-premise trong trung tâm dữ liệu của Uber nên có thể cung cấp độ trễ mạng nhanh hơn
  • Việc chuyển sang LedgerStore cũng mang lại hiệu quả cắt giảm chi phí lặp lại đáng kể

Độ ổn định của lưu lượng hiện tại được xác nhận bằng shadow validation

  • Để đánh giá backfill có chính xác hay không, họ đặt ra năm tiêu chí
    • Tính đầy đủ: mọi bản ghi đều được backfill
    • Tính chính xác: mọi bản ghi đều đúng
    • Tải: LedgerStore có thể xử lý tải hiện tại
    • Độ trễ: độ trễ P99 của LedgerStore nằm trong ngưỡng cho phép
    • Độ trễ chỉ mục: độ trễ tạo chỉ mục phụ ở nền nằm trong ngưỡng cho phép
  • Shadow validation so sánh phản hồi từ hệ thống cũ với phản hồi khi dùng LedgerStore làm nguồn dữ liệu
  • Mục tiêu là đạt ít nhất 99.99% về tính đầy đủ và chính xác của backfill theo tiêu chí shadow validation, đồng thời đặt trần ở 99.9999%
  • Cần có mức trần vì nếu điều tra đến cùng mọi trường hợp khả nghi trong xác minh dữ liệu quy mô lớn, dự án có thể bị đình trệ
    • Di chuyển dữ liệu lịch sử có thể lẫn các lỗi ghi sai từ giai đoạn phát triển ban đầu hoặc hư hỏng dữ liệu do quy mô
    • Dù S3 đảm bảo độ bền 11 nines, ở quy mô 1 nghìn tỷ bản ghi vẫn có thể kỳ vọng khoảng 10 bản ghi bị hư hỏng
    • Với chỉ mục có tính nhất quán cuối cùng, các bản ghi xuất hiện sau vài giây có thể bị xem là thiếu trong shadow validation, tạo ra false positive
    • Để xác nhận đáng tin cậy mức 6 nines cần so sánh 100 triệu bản ghi; nếu so sánh 1.000 bản ghi mỗi giây thì cần hơn một ngày để thu thập dữ liệu
    • Với 7 nines, trong cùng điều kiện phải chờ 12 ngày
  • Khi sao chép lưu lượng production sang LedgerStore, họ đồng thời xác nhận được tải, độ trễ, độ trễ chỉ mục và độ tin cậy của mã truy cập
  • Các vấn đề về độ trễ và độ trễ chỉ mục được phát hiện trong quá trình di chuyển đã dẫn đến nhiều bản sửa lỗi
    • Tối ưu partition key để cải thiện phân tán dữ liệu chỉ mục
    • Sửa lỗi chỉ mục khiến hệ thống phải scan bản ghi thay vì point lookup
  • Shadow validation trên lưu lượng thật hữu ích với dữ liệu đang được truy cập hiện tại, nhưng khó đưa ra đảm bảo mạnh cho toàn bộ dữ liệu lịch sử hầu như không còn được truy cập

Xác minh ngoại tuyến và backfill tăng dần

  • Xác minh ngoại tuyến so sánh toàn bộ dữ liệu trong LedgerStore với bản dump dữ liệu DynamoDB
  • Vì lưu lượng thực tế chủ yếu truy cập dữ liệu gần đây, các vấn đề ẩn trong dữ liệu lạnh khó được phát hiện chỉ bằng shadow validation
  • Những bản ghi có vấn đề dữ liệu cần được bỏ qua để backfill tiếp tục chạy, đồng thời cũng phải tính đến khả năng có bug trong chính tác vụ backfill
  • Tác vụ xác minh lớn nhất xử lý 70TB dữ liệu nén, ước tính 300TB chưa nén, và so sánh 760 tỷ bản ghi trong một job duy nhất
  • Job Apache Spark ở quy mô này cần data shuffle, và Uber đã dùng kết hợp Distributed Shuffle as a Service for Spark, Dynamic Resource Allocation và Speculative Execution
  • Các bản ghi thiếu được tìm thấy qua xác minh ngoại tuyến được dùng làm đầu vào cho backfill tăng dần
  • Họ lặp lại quy trình xác minh và backfill để bảo đảm mọi bản ghi đều đã được ghi

Những vấn đề vận hành gặp phải trong backfill

  • Backfill phải bắt đầu ở quy mô nhỏ rồi tăng dần đến giới hạn của hệ thống
    • Nếu cứ ép tải vượt ngưỡng, sẽ thành tình huống tự DDoS chính hệ thống của mình
    • Cần tìm ra điểm nghẽn, xử lý xong rồi mới mở rộng tiếp
    • Sau mỗi lần mở rộng đều cần giám sát chặt chẽ
  • Khi backfill dữ liệu của nhiều năm chỉ trong vài tháng, tải phát sinh sẽ lớn hơn nhiều so với lưu lượng bình thường
    • Nếu production xử lý 1.000 yêu cầu mỗi giây, thì backfill 100 tỷ bản ghi ở 10.000 yêu cầu mỗi giây vẫn cần 120 ngày
    • Nếu tác vụ backfill có khả năng gây sự cố trong lúc chạy, phải dừng ngay lập tức
  • Backfill không nên là một tác vụ chạy một mạch đến cuối mà phải chia thành các lô tăng dần
    • Mỗi lô cần đủ nhỏ để hoàn thành trong vài phút
    • Vì tác vụ có thể kết thúc giữa chừng nên phải có tính idempotent
    • Khi hoàn thành một lô, cần ghi ra file các thống kê như số bản ghi đã đọc, số bản ghi đã backfill rồi tổng hợp lại để theo dõi tiến độ
  • Backfill an toàn cần kiểm soát tốc độ có thể điều chỉnh
    • Trong Java/Scala có thể dùng RateLimiter của Guava
    • Nếu có thể chạy nhanh hơn khi lưu lượng production thấp, thì theo dõi trạng thái hệ thống để điều chỉnh RPS
    • Uber điều chỉnh RPS theo cơ chế additive increase/multiplicative decrease, nhưng vẫn giữ giới hạn trên để bảo đảm an toàn
  • Nếu nghi ngờ có sự cố hoặc quá tải, cần có khả năng dừng backfill nhanh chóng
    • Trong thời gian xảy ra sự cố, backfill nên được dừng để phòng ngừa và giảm nhiễu
    • Ngay cả sau sự cố, hệ thống vẫn có thể chịu thêm tải trong quá trình phục hồi
    • Chức năng dừng khẩn cấp cũng giúp ích cho việc debug các vấn đề liên quan đến quy mô

Tệp dung lượng lớn, chịu lỗi và logging

  • Kích thước tệp dump dữ liệu nên được giữ ở khoảng 1GB, với độ linh hoạt khoảng 10 lần theo cả hai hướng là phù hợp
    • Nếu tệp quá lớn có thể chạm giới hạn MultiPart của nhiều công cụ
    • Nếu tệp quá nhỏ thì số lượng tệp sẽ quá nhiều, khiến chỉ riêng việc liệt kê danh sách cũng tốn rất nhiều thời gian
    • Khi chạy lệnh shell có thể đụng giới hạn ARGMAX
  • Trong quá trình chuyển đổi dữ liệu của backfill, các vấn đề chất lượng dữ liệu hoặc bản ghi hư hỏng là điều không thể tránh khỏi
    • Các bản ghi lỗi phân tán ngẫu nhiên nên không thể mỗi lần gặp lỗi lại dừng toàn bộ job
    • Đồng thời cũng không thể bỏ qua vì đó có thể là bug trong code
    • Các bản ghi có vấn đề được dump riêng ra và giám sát bằng thống kê
    • Nếu tỷ lệ lỗi cao, họ sẽ dừng backfill thủ công, sửa vấn đề rồi tiếp tục
  • Việc ghi bản ghi có thể thất bại do RPC timeout
    • Có thể retry, nhưng đến một thời điểm nào đó vẫn phải bỏ qua bất kể nguyên nhân là gì để toàn bộ công việc có thể tiếp tục tiến lên
  • Dù muốn ghi nhiều log để debug và theo dõi tiến độ, điều này có thể tạo áp lực lớn lên hạ tầng logging
    • Ngay cả khi có thể ghi log, lượng dữ liệu cần lưu giữ cũng có thể trở nên quá lớn
    • Với những phần phát sinh nhiều log, cần áp dụng rate limiting
    • Nếu lỗi xảy ra hiếm, có thể ghi lại toàn bộ log lỗi

Rollout dần dần và loại bỏ fallback

  • Việc chuyển sang LedgerStore được giảm rủi ro không chỉ bằng xác minh và phân tích thống kê backfill mà còn bằng rollout thận trọng
  • Rollout diễn ra trong vài tuần và có sự phê duyệt của các kỹ sư on-call từ các dịch vụ gọi chính
  • Ban đầu, nếu không tìm thấy dữ liệu trong LedgerStore thì hệ thống dùng fallback để lấy từ DynamoDB
  • Mỗi bản ghi bị đánh dấu là thiếu trong log fallback đều được kiểm tra lại để xác nhận liệu nó có thực sự bị thiếu trong LedgerStore hay không
  • Ngay cả sau khi loại bỏ fallback, dữ liệu DynamoDB vẫn được giữ lại trong một tháng
  • Sau đó họ dừng ghi vào DynamoDB, tạo bản backup cuối cùng rồi xóa bảng
  • Toàn bộ quá trình di chuyển kéo dài 2 năm và được hoàn tất mà không có downtime hay sự cố nào trong hoặc sau quá trình di chuyển

1 bình luận

 
GN⁺ 2024-05-21
Ý kiến trên Hacker News
  • Tò mò không biết liệu có thể nhét 1,7 petabyte dữ liệu (1 nghìn tỷ bản ghi đã được lập chỉ mục) vào một máy chủ bare-metal cực mạnh với chi phí dưới vài nghìn đô mỗi tháng và phục vụ bằng SQLite hay không
    Ví dụ theo cách này: https://use.expensify.com/blog/scaling-sqlite-to-4m-qps-on-a...

    • Nhét 1,7 petabyte vào SQLite ư? Khuyến nghị của chính SQLite là thế này: nếu dữ liệu có vẻ sẽ lớn đến mức khó hoặc không thể đưa vào một tệp đĩa đơn, hãy chọn giải pháp khác thay vì SQLite
      SQLite hỗ trợ cơ sở dữ liệu tối đa 281 terabyte, với giả định rằng bạn có thể tìm được ổ đĩa và hệ thống tệp hỗ trợ tệp 281 terabyte. Dù vậy, tài liệu vẫn nói rằng nếu kích thước nội dung có dấu hiệu tăng lên mức terabyte thì nên cân nhắc cơ sở dữ liệu client/server tập trung thay vì SQLite
    • SSD 30,7TB có giá khoảng 5.500 đô mỗi chiếc, và để đạt 1,7PB thì cần 56 chiếc ngay cả khi không có dự phòng. Hơn nữa, kích thước DB tối đa của SQLite là 140TB
      Có vẻ khó nhét lượng lưu trữ cỡ này vào một máy chủ, và mức vài nghìn đô mỗi tháng thì càng khó hơn. SQLite cũng không phù hợp cho mục đích này
    • Giá trị mà cloud thương mại đem lại không phải là tiết kiệm chi phí, trừ khi bạn định lượng tất cả các yếu tố phụ trợ/bên ngoài như rủi ro bảo mật, làm mát/sưởi, nhân sự trung tâm dữ liệu, vòng đời phần cứng
      Một công ty có đủ vốn và năng lực tổ chức có thể tự xây cloud rẻ hơn nhiều, nhưng một phần đáng kể của phép tính nằm ở việc thuê ngoài các yếu tố rủi ro
    • Dù bạn có cây búa tốt đến đâu, có những thứ ngay từ đầu đã không phải là đinh
    • Không được. SQLite “chỉ” hoạt động đến 281TB thôi [0] [1]
      [0] https://www.sqlite.org/releaselog/3_33_0.html
      [1] https://www.sqlite.org/limits.html (#12)
  • LedgerStore có vẻ không phải mã nguồn mở [1], và để tìm thông tin liên quan thì phải lần theo các bài blog Uber liên kết ngược lẫn nhau
    Trong các bài viết năm 2021, bài có nhiều thông tin nhất về LedgerStore có vẻ là bài này:
    https://www.uber.com/en-US/blog/dynamodb-to-docstore-migrati...
    [1]:https://github.com/uber

    • Đúng vậy. Trông như một giải pháp nội bộ
      Nhìn chung Uber có vẻ khá thiên về tự xây. Họ thường kết luận rằng các giải pháp mã nguồn mở hiện có là chưa đủ rồi tự làm. Khác với cách tiếp cận của Facebook, chẳng hạn, khi họ cải thiện MySQL bằng MyRocks/RocksDB và duy trì nó dưới dạng mã nguồn mở
  • Đọc bài thì thấy Uber khá rõ là đã dùng DynamoDB sai cách
    Có vẻ một số hành trình người dùng cốt lõi cần tính nhất quán mạnh, còn các giao dịch lịch sử thì cần data warehousing quy mô lớn
    Thật lạ là họ đã không chuyển cấu trúc DynamoDB 2 bảng ban đầu sang kiểu DynamoDB + Redshift trước. Đây là một pattern khá phổ biến

    • Có thể đăng tài liệu tham khảo về pattern này không?
    • Không hiểu tại sao lại phải đưa 2 tuần giao dịch bất biến vào Dynamo. Có ai gợi ý được không?
  • Khoảng năm 2015 từng có một giai đoạn các công ty công nghệ “ngầu” như Netflix, Spotify, SoundCloud, Uber tạo ra rất nhiều công cụ hạ tầng và cơ sở dữ liệu
    Ngày nay kỹ sư thường nói bằng thuật ngữ AWS/cloud
    Thấy vẫn còn tổ chức tự xây những công cụ kiểu này thì khá mới mẻ

  • Tôi không biết tính kinh tế của dự án cụ thể này, nhưng DynamoDB thật sự đắt
    Có thời tôi nghĩ tất cả những người khác đang dùng DynamoDB sai, quét và truy vấn thay vì point lookup trên các bảng đã tính sẵn
    Nhưng ngay cả khi dùng như một bảng băm phân tán, bạn vẫn phải trả premium lớn

    • Không hiểu vì sao lại nói là đắt. 120 đô/năm cho 100 WCU, 30 đô/năm cho 100 RCU nghe không đắt
      1 RCU đọc tối đa 4KB, nên để đọc 100MB cần 100.000 RCU, tức 30.000 đô/năm hoặc 2.500 đô/tháng. Nếu phép tính không sai thì tôi thấy gần như không có gì tương đương về giá
  • Tò mò không biết họ có xem xét https://tigerbeetle.com không

    • Hẳn là sẽ thú vị. TigerBeetle được viết bằng Zig
      Và Uber có lẽ là một trong số ít doanh nghiệp lớn có hợp đồng hỗ trợ với Zig Foundation
  • Chúc mừng những người tham gia công việc này. Tuy vậy, chỉ riêng chi phí vận hành đội này chắc cũng khá lớn và có lẽ không khác nhiều so với khoản tiết kiệm 6 triệu đô, chưa kể thêm gánh nặng bảo trì
    Hệ thống thanh toán cũng có vẻ không phải là một canh bạc dài hạn, nên thật thú vị khi các đội nhận những dự án như thế này. Có phải đây là một dạng chi phí chìm do đội ngũ kỹ thuật sẵn có không?

    • Ở một đầu của phổ có những người tuyên bố có thể viết phần mềm kiểu này trong một cuối tuần. Ở đầu kia có những người nói cần lương 600.000 đô/năm và thêm 9 đồng nghiệp nữa mới làm được
      Ở đâu đó giữa hai cực đó còn rất nhiều chỗ cho một ước tính chi phí thực tế hơn
    • Ước tính đó giống một cách đáng ngờ với việc chỉ tính chi phí lưu trữ dữ liệu của DynamoDB
      Nếu dữ liệu và chỉ mục là 1,7PB, thì theo giá niêm yết lưu trữ DynamoDB, chi phí khoảng 5,1 triệu đô mỗi năm
    • Nếu 5 triệu đô/năm để phát triển và duy trì một hệ thống DB tùy chỉnh hoàn toàn ở quy mô đó, thì đại khái có thể thuê 25 kỹ sư cấp cao mà vẫn còn 1 triệu đô cho chi phí thiết bị
      Nghe khá thực tế để có một hệ thống chuyên dụng được điều chỉnh tốt cho phần cốt lõi của doanh nghiệp
    • Có lẽ nên giả định rằng họ biết về chi phí của họ nhiều hơn rất nhiều, còn bạn thì biết rất ít. Không có nhiều giá trị trong việc hạ thấp các thành viên trong đội như vậy
    • Đọc bài thì thấy hệ thống này là một lớp nằm trên DynamoDB, và họ đã cập nhật nó để dùng sản phẩm nội bộ Docstore, đồng thời phải bổ sung một tính năng vào Docstore trong quá trình đó
      Không phải là công việc lớn như mọi người nói. Hơn nữa, các bản ghi là bất biến nên nhiều phần trở nên dễ hơn rất nhiều
  • Tò mò không biết đây có phải là một ngoại lệ nữa, khi đạt đến một quy mô nhất định thì tự xây sẽ có lợi hơn. Quy mô mà Uber phải xử lý khá đáng kinh ngạc
    Chỉ từ bài gốc thì không rõ tổng chi phí sở hữu của dịch vụ đã refactor mới là bao nhiêu. Giờ họ phải tự quản lý cơ sở dữ liệu riêng và lớp lưu trữ phía sau nó, đúng không? Tôi có bỏ sót gì không?

    • Tôi từng làm ở một công ty giai đoạn prototype dùng Redis, rồi để tăng hiệu năng và khả năng phục hồi thì họ tự viết cơ sở dữ liệu
      Công ty đó không bán sản phẩm cho người dùng cuối, mà có sản phẩm là một hệ thống tệp phân tán
      Theo tôi, đa số công ty không có chuyên môn để xây các hệ thống như cơ sở dữ liệu, và dù về mặt chi phí việc phát triển trông có vẻ hợp lý, trên thực tế họ vẫn sợ làm những việc như vậy
  • Tôi xem đây là một ví dụ rất hay cho thấy kho dữ liệu dựa trên cloud độc quyền có thể đắt đến mức nào, và việc di chuyển từ đó sang thứ khác là khả thi trong thực tế

  • Giả sử mọi người hành động hợp lý, tôi nghĩ giờ tính sổ với các nhà cung cấp dịch vụ cloud sắp đến
    Tôi từng làm hợp đồng cho một công ty nhỏ; họ dùng GCP Bigtable để chạy báo cáo trên dữ liệu từ một DB MySQL 375MB và tốn hơn 11.000 đô mỗi tháng
    Họ thuê một data scientist mới ra trường để làm báo cáo, và người đó đang làm những việc phi lý kém hiệu quả trên một tập dữ liệu cực nhỏ. Họ muốn tôi sửa ngay ngày mai với vài đồng lẻ nên tôi từ chối

    • Tôi đồng ý với ý chính, nhưng không nghĩ ví dụ này là một trường hợp hay
      Nó chỉ là một hệ thống được thiết kế sai. Nếu dùng cơ sở dữ liệu on-premise được provision thừa khủng khiếp để chạy cùng việc đó thì vấn đề tương tự cũng sẽ xảy ra