Là nền tảng thực hiện hàng đầu cho thương mại kỹ thuật số ở Ấn Độ, Delhivery thực hiện một triệu gói hàng mỗi ngày, 365 ngày một năm. 24 trung tâm phân loại tự động, 101 trung tâm, hơn 3.100 trung tâm giao hàng trực tiếp, hơn 1000 trung tâm đối tác, hơn 11.000 đội xe và hơn 60.000 thành viên trong nhóm hoạt động trơn tru nhờ mạng lưới thiết bị IoT rộng lớn. Hàng nghìn sự kiện và tin nhắn dữ liệu đến và đi khỏi hệ thống của chúng tôi mỗi giây. Con số này tương đương với khối lượng dữ liệu khổng lồ hàng ngày tính bằng terabyte, khiến khả năng hiển thị hoạt động trở nên quan trọng đối với chúng tôi và các bên liên quan của chúng tôi.
Nhận thấy các yêu cầu này, chúng tôi quyết định xây dựng siêu thị dữ liệu—cơ sở dữ liệu tập trung, nhất quán, dần dần cung cấp cho người dùng quyền truy cập nhanh vào dữ liệu kinh doanh được tổng hợp trước. Điều này cho phép các bên liên quan của chúng tôi nhanh chóng truy cập thông tin chi tiết về doanh nghiệp mà không cần tìm kiếm trong toàn bộ kho dữ liệu.
Tuy nhiên, với quy mô khó khăn này, một trong những thách thức lớn là duy trì tính toàn vẹn dữ liệu và độ trễ thấp trong khi vẫn cung cấp khả năng cho khối lượng công việc phân tích.
Trong blog này, tôi sẽ giải thích tất cả những quan điểm của mình trong khi di chuyển kho dữ liệu của chúng tôi từ Amazon Aurora sang TiDB, một cơ sở dữ liệu SQL phân tán/Giao dịch kết hợp (HTAP). Hy vọng rằng bài đăng này có thể cung cấp thông tin chi tiết cho các nhà lãnh đạo kỹ thuật dữ liệu, quản trị viên cơ sở dữ liệu hoặc kiến trúc sư dữ liệu đang xem xét việc di chuyển tương tự sang TiDB hoặc bất kỳ cơ sở dữ liệu HTAP nào khác.
Để hiểu rõ hơn về trường hợp dữ liệu thời gian thực tại Delhivery, trước tiên chúng ta hãy làm quen với ba khái niệm cốt lõi trong trường hợp sử dụng của chúng tôi: OLTP, OLAP & HTAP:
Siêu thị dữ liệu thời gian thực khác với siêu thị dữ liệu truyền thống ở chỗ chúng nhập dữ liệu theo thời gian thực chứ không phải theo khoảng thời gian cụ thể. Các trung tâm dữ liệu này rất quan trọng trong việc ra quyết định vận hành mặt đất tại Delhivery vì chúng tôi không thể chấp nhận bất kỳ sự chậm trễ nào trong việc đồng bộ hóa các sự kiện này.
Hành trình siêu thị dữ liệu thời gian thực của chúng tôi bắt đầu vào năm 2020 khi chúng tôi xác định được nhu cầu về bảng thông tin tập trung—cụ thể là bảng thông tin EYE. Mục đích của bảng thông tin này là cung cấp khả năng hiển thị hoạt động theo thời gian thực cho các hoạt động trên mặt đất, cho phép đưa ra quyết định dựa trên dữ liệu cập nhật từng phút. Ví dụ về cách sử dụng bao gồm:
Chúng tôi đã nghĩ đến việc giải quyết các trường hợp sử dụng của mình bằng cách sử dụng các công cụ kho dữ liệu như Redshift và Snowflake nhưng không có giải pháp nào trong số này hiệu quả với chúng tôi khi xem xét mẫu thiết kế và yêu cầu nhập dữ liệu theo thời gian thực cùng với việc hợp nhất.
Vì vậy, ban đầu chúng tôi đã chọn Aurora (PostgreSQL) để phục vụ trường hợp sử dụng kho dữ liệu của mình.
Chúng tôi đã thiết kế các siêu thị dữ liệu thời gian thực của mình bằng cách sử dụng Spark Streaming và Aurora. Quy trình hấp dẫn của chúng tôi rất đơn giản--đọc dữ liệu từ Kafka, xử lý dữ liệu theo lô vi mô Spark và thực hiện các hoạt động nâng cấp trong Aurora.
Cơ sở dữ liệu của chúng tôi được mô hình hóa bằng kiến trúc nhiều lớp, bao gồm một lớp thô, một lớp được phân vùng và một lớp dữ liệu. Người dùng không có quyền truy cập để xem hoặc sửa đổi dữ liệu ở lớp thô. Lớp được phân vùng được giữ để duy trì tất cả các bảng được phân vùng (nói chung là bảng thứ nguyên). Dưới đây là một thiết kế lược đồ đơn giản của cơ sở dữ liệu của chúng tôi:
Hệ thống ban đầu hoạt động tốt cho đến khi nó phải xử lý thông lượng vượt quá 3K tin nhắn mỗi giây. Điều này đánh dấu sự khởi đầu của một số thách thức:
Giới hạn về khả năng mở rộng: Vì chúng tôi đã vượt quá thông lượng 3K tin nhắn mỗi giây nên các giới hạn Hoạt động đầu vào/đầu ra mỗi giây (IOPS) của Aurora đã trở thành một nút thắt cổ chai. Hạn chế về khả năng mở rộng đã bắt đầu ảnh hưởng đến hoạt động của chúng tôi.
Sự cố cồng kềnh: Mỗi lần cập nhật bản ghi đều dẫn đến việc tạo ra một bản ghi mới và một bộ dữ liệu chết (phiên bản trước của bản ghi). Khi tốc độ sản xuất của những bộ dữ liệu chết này vượt xa quá trình dọn dẹp, tình trạng đầy hơi sẽ xảy ra. Vì VACUUM FULL không thể yêu cầu dung lượng lưu trữ nên mức sử dụng đĩa liên tục tăng lên. Đối với khoảng 5 TB dữ liệu, Aurora đã sử dụng hơn 30 TB dung lượng lưu trữ.
Gánh nặng bảo trì: Vấn đề đầy hơi liên quan trực tiếp đến những thách thức trong việc bảo trì của chúng tôi. Với hơn 70 đường dẫn và tổng số QPS ghi vượt quá 5k tin nhắn/giây, chúng tôi nhận thấy quy trình dọn dẹp tự động của PostgreSQL, Auto Vacuum, không theo kịp tốc độ tạo ra bộ dữ liệu chết. Do đó, cần phải chạy VACUUM hoặc VACUUM FULL theo cách thủ công để khôi phục cơ sở dữ liệu. Những nỗ lực của chúng tôi với các công cụ PostgreSQL như pg_repack và pgcompacttable cũng tỏ ra không thành công. Do đó, việc bảo trì ngày càng trở nên phức tạp và tốn thời gian.
Để giải quyết các hạn chế của Aurora, chúng tôi bắt đầu tìm giải pháp thay thế tốt hơn đáp ứng các yêu cầu sau:
Xem xét tất cả các yêu cầu trên, ban đầu chúng tôi đã khám phá nhiều lựa chọn thay thế PostgreSQL bao gồm Spanner và Yugabyte vì chúng tôi muốn duy trì việc quản lý thay đổi ở mức tối thiểu.
Spanner là dịch vụ lưu trữ và quản lý cơ sở dữ liệu SQL phân tán do Google cung cấp. Nó được quản lý hoàn toàn trên Google Cloud Platform (GCP). Tuy nhiên, chúng tôi nhận thấy rằng Spanner có thể không phải là trường hợp sử dụng tốt cho kiến trúc của chúng tôi vì những lý do sau:
YugabyteDB là cơ sở dữ liệu SQL phân tán giao dịch hiệu suất cao dành cho các ứng dụng gốc trên nền tảng đám mây, được phát triển bởi Yugabyte. Cơ sở dữ liệu này rất gần với trường hợp sử dụng của chúng tôi vì nó hoàn toàn tuân thủ PostgreSQL, có thể mở rộng theo chiều ngang và được phân phối đầy đủ. Thật không may, nó không hoạt động tốt do hạn chế về khả năng mở rộng. Tiêu chí thành công của chúng tôi yêu cầu hơn 7 nghìn giao dịch mỗi giây nhưng Yugabyte chỉ có thể mở rộng quy mô lên tới 5 nghìn.
Chúng tôi cũng đã xem xét các ứng cử viên tiềm năng khác như BigQuery, nhưng không có ứng viên nào trong số đó đáp ứng tốt yêu cầu của chúng tôi.
Sau các lựa chọn thay thế PostgreSQL ở trên, chúng tôi quyết định thêm HTAP vào các yêu cầu của mình, điều này dẫn chúng tôi đến TiDB. Nó hỗ trợ khả năng mở rộng ngay lập tức, tính nhất quán, tính khả dụng, cấu trúc liên kết triển khai nhiều trang web và nhiều tính năng khác. Là một cơ sở dữ liệu phân tán, TiDB có nhiều thành phần giao tiếp với nhau và tạo thành một hệ thống TiDB hoàn chỉnh.
Các tính năng sau của TiDB đã giải quyết những thách thức chính và đáp ứng các yêu cầu hoạt động của chúng tôi:
Dễ dàng mở rộng quy mô
Thiết kế kiến trúc TiDB tách biệt điện toán khỏi lưu trữ, cho phép bạn mở rộng quy mô hoặc mở rộng dung lượng điện toán hoặc lưu trữ trực tuyến khi cần. Quá trình mở rộng quy mô là minh bạch đối với nhân viên vận hành và bảo trì ứng dụng.
Tuân thủ ACID
TiDB tương thích với MySQL và hỗ trợ các giao dịch ngay lập tức. Nó hỗ trợ cả hai loại giao dịch lạc quan và bi quan. Điều này làm cho nó trở nên độc đáo so với các cơ sở dữ liệu khác.
Tính sẵn sàng cao
TiKV lưu trữ dữ liệu thành nhiều bản sao và sử dụng giao thức Multi-Raft để lấy nhật ký giao dịch. Một giao dịch chỉ có thể được thực hiện khi dữ liệu đã được ghi thành công vào phần lớn các bản sao. Điều này đảm bảo tính nhất quán mạnh mẽ và tính sẵn sàng cao khi một số ít bản sao bị hỏng.
HTAP thời gian thực
TiDB kết hợp cả lưu trữ hàng (TiKV) và lưu trữ cột (TiFlash) trong cùng một kiến trúc, tạo thành một ngăn xếp công nghệ hợp lý giúp tạo ra các phân tích thời gian thực trên dữ liệu vận hành dễ dàng hơn.
Cơ sở hạ tầng TiDB của chúng tôi được triển khai trên máy ảo của các nhà cung cấp dịch vụ đám mây hàng đầu. Chúng tôi sử dụng TiUP, trình quản lý gói của TiDB, để quản lý cụm và tất cả các hoạt động quản trị. Cụm của chúng tôi được triển khai trên 3 vùng có sẵn (AZ).
Cấu hình cụm của chúng tôi như sau:
Bằng cách triển khai cụm TiDB trên nhiều AZ và lựa chọn cẩn thận các loại nút để đáp ứng nhu cầu xử lý và bộ nhớ, chúng tôi đã tạo ra một cơ sở hạ tầng mạnh mẽ, có tính sẵn sàng cao, có khả năng xử lý các yêu cầu thông lượng dữ liệu cao của chúng tôi.
Để làm cho nó hoạt động phù hợp với trường hợp sử dụng của chúng tôi, chúng tôi đã hợp tác chặt chẽ với nhóm PingCAP để điều chỉnh cơ sở dữ liệu. Dưới đây là một số điều chỉnh quan trọng mà chúng tôi đã thực hiện:
Đặt các tham số sau trước khi bắt đầu lập chỉ mục.
SET @@global.tidb_ddl_reorg_worker_cnt = 16; SET @@global.tidb_ddl_reorg_batch_size = 4096;
Đặt lại về giá trị mặc định sau khi tạo chỉ mục.
SET @@global.tidb_ddl_reorg_worker_cnt = 4; SET @@global.tidb_ddl_reorg_batch_size = 256;
Điều này chủ yếu quan trọng đối với các bảng được phân vùng. Nó phân tích các điều kiện lọc trong câu lệnh truy vấn và loại bỏ (cắt bỏ) các phân vùng khi chúng không chứa bất kỳ dữ liệu cần thiết nào.
SET @@session.tidb_partition_prune_mode = 'dynamic';
Đôi khi, bộ phân tích tự động trong TiDB bị lỗi nếu nhập một lượng lớn dữ liệu. Trong trường hợp đó, tất cả các truy vấn có thể sử dụng kế hoạch thực hiện sai và cuối cùng phải quét toàn bộ bảng. Để tránh tình huống như vậy, chúng tôi đã thực hiện những thay đổi sau trong cấu hình TiDB:
set global tidb_max_auto_analyze_time = 86400; set global tidb_enable_pseudo_for_outdated_stats = off; set global tidb_sysproc_scan_concurrency = 15;
Nếu bạn đang làm việc với các bảng được phân vùng, chúng tôi khuyên bạn nên chạy các thao tác phân tích bảng theo cách thủ công cho từng phân vùng để tránh lỗi phân tích.
Thông qua những điều chỉnh như thế này, chúng tôi có thể hợp lý hóa việc sử dụng TiDB một cách hiệu quả để có thể đạt được hiệu suất tối ưu cho kho dữ liệu thời gian thực của mình.
Cải thiện hiệu suất truy vấn
Chúng tôi có hơn 400 truy vấn được đánh dấu chuẩn và nhận thấy rằng tất cả các truy vấn đều đang chạy trong SLA. Chúng tôi thậm chí còn nhận thấy hiệu suất của các truy vấn P95 tăng 15-20%.
Di chuyển dễ dàng
Chúng tôi đã sử dụng công cụ TiDB Lighting để di chuyển tất cả dữ liệu lịch sử của bảng từ Postgres sang TiDB. Công cụ này rất dễ sử dụng và rất nhanh. Chúng tôi có thể tải hàng terabyte dữ liệu trong vòng khoảng 2-3 giờ. Tuy nhiên, cần lưu ý rằng cần phải điều chỉnh rất nhiều trước khi tải dữ liệu khổng lồ như vậy.
Hỗ trợ mạnh mẽ
Chúng tôi đã trải qua một số trục trặc trong quá trình thiết lập cơ sở hạ tầng sản xuất nhưng nhóm hỗ trợ PingCAP đã đóng một vai trò rất quan trọng và giúp chúng tôi điều chỉnh cụm cho phù hợp với tính chất của khối lượng công việc.
Trong bài đăng này, chúng tôi đã khám phá những thách thức khi sử dụng Aurora với trường hợp sử dụng siêu dữ liệu thời gian thực và hành trình di chuyển sang TiDB. Chúng tôi cũng đã thảo luận về cách Delhivery sử dụng TiDB trên quy mô lớn.
Bất chấp thành công của chúng tôi với TiDB, chúng tôi thừa nhận rằng không có giải pháp nào là hoàn hảo và hiệu quả có thể khác nhau tùy theo trường hợp sử dụng. Trong TiDB, chúng tôi đã lưu ý một số lĩnh vực cần cải thiện, bao gồm cả việc thiếu hỗ trợ ngay lập tức cho các chế độ xem cụ thể hóa và quản lý hạn ngạch gốc. Tuy nhiên, bằng các giải pháp và điều chỉnh phù hợp, chúng tôi đã giải quyết được những hạn chế này một cách hiệu quả.
Cho đến nay, chúng tôi đã triển khai TiDB trong môi trường sản xuất của mình. Dựa trên điểm chuẩn của chúng tôi, TiDB cho phép chúng tôi xử lý hơn hàng nghìn yêu cầu mỗi giây với độ trễ dưới 100 mili giây. Trong tương lai, chúng tôi sẽ tiếp tục khám phá thêm các trường hợp sử dụng yêu cầu cơ sở dữ liệu được phân phối nhất quán và mạnh mẽ.
https://docs.pingcap.com/tidb/stable/tidb-lightning-overview
https://reorg.github.io/pg_repack/
https://github.com/dataegret/pgcompacttable
https://cloud.google.com/spanner
https://www.yugabyte.com/yugabytedb/
https://cloud.google.com/bigquery/
https://docs.pingcap.com/tidb/dev/transaction-overview
https://proxysql.com/
Hari Kishan (Giám đốc kỹ thuật cấp cao @ Delhivery)
Akash Deep Verma (Giám đốc Công nghệ @ Delhivery)