Mở rộng nhanh hệ thống lưu trữ trực tuyến cho hơn 1 tỷ người dùng ChatGPT (Phần II)
Cách chúng tôi tối ưu Azure Cosmos DB trong nền tảng lưu trữ ứng dụng Habitat để đáp ứng mức tăng trưởng chưa từng có.
Mọi sản phẩm OpenAI đều cần truy cập dữ liệu nhanh chóng, đáng tin cậy, do nền tảng lưu trữ Habitat của chúng tôi cung cấp. Nền tảng này phải phản hồi trong vài mili giây cho hơn 1 tỷ người dùng ở 40 khu vực địa lý. Hạ tầng của chúng tôi đối mặt với một thách thức đặc biệt lớn: đáp ứng tăng trưởng bùng nổ và các trường hợp sử dụng mới, đồng thời tiếp tục cải thiện độ tin cậy, hiệu năng và tốc độ phát triển sản phẩm. Để giải quyết thách thức đó, chúng tôi phải xem xét lại cách thiết kế và vận hành nền tảng lưu trữ trực tuyến. Chúng tôi liên tục cân nhắc các đánh đổi theo trình tự: trước hết đủ tin cậy cho lưu lượng sản phẩm thiết yếu, sau đó đủ nhanh cho người dùng toàn cầu, và cuối cùng là vận hành linh hoạt ở quy mô khổng lồ.
Loạt bài hai phần này giải thích cách chúng tôi phát triển Habitat từ một thư viện máy khách và cơ sở dữ liệu đơn giản thành nền tảng lưu trữ phân tán toàn cầu, phục vụ hơn 500 petabyte dữ liệu. Phần I tập trung vào quá trình Habitat chuyển từ một thư viện máy khách Python thành một dịch vụ. Phần đó cũng trình bày các kỹ thuật giúp chúng tôi đưa một dịch vụ dựa trên Python vượt xa giới hạn mà nhiều người cho là khả thi.
Trong bài viết này, Phần II, chúng tôi trình bày cách mở rộng thành phần lưu trữ nền tảng: Azure Cosmos DB. Nhờ hợp tác chặt chẽ với đội ngũ Azure, chúng tôi đã tìm ra cách triển khai đa bên thuê khả thi bằng các container đồng quản lý, mang lại hiệu năng đọc xuất sắc trên quy mô toàn cầu khổng lồ.
Hình 01 · Habitat là gì?
Nền tảng lưu trữ trực tuyến
Habitat là nền tảng lưu trữ trực tuyến do chúng tôi xây dựng để các sản phẩm OpenAI truy cập thông tin cần thiết một cách nhanh chóng và đáng tin cậy.
- Yêu cầu
- Phản hồi
- Thay đổi (CDC)
Khi công ty mở rộng, các nhóm hạ tầng thường chuyển từ vận hành hệ thống đơn bên thuê sang đa bên thuê. Trong mô hình đơn bên thuê, mỗi nhóm phụ trách một mảng sản phẩm duy trì hệ thống riêng. Cách này giảm phạm vi ảnh hưởng của sự cố, dễ phân định trách nhiệm và cô lập tải công việc. Khi số nhóm và số mảng sản phẩm tăng lên, chi phí vận hành cách này trở nên tốn kém. Mô hình đơn bên thuê buộc mọi nhóm sản phẩm phải tự hoạch định tài nguyên và thường dẫn tới cấp phát dư thừa đáng kể.
Ngược lại, mô hình đa bên thuê giao quyền quản lý cho một nhóm cơ sở dữ liệu tập trung, có kiến thức và kinh nghiệm tốt hơn về cấp phát tài nguyên. Nhưng mô hình đa bên thuê cũng tạo ra vấn đề riêng, chẳng hạn tải lân cận gây nhiễu: một bên thuê tiêu thụ tỷ lệ tài nguyên lớn bất thường, làm ảnh hưởng tới các bên thuê khác.
Với Habitat, chúng tôi phải cân nhắc tất cả những đánh đổi này để thiết kế hệ thống lưu trữ đáng tin cậy, hiệu quả ở quy mô lớn. Ngày nay, Habitat là lớp cơ sở dữ liệu đa bên thuê cho nhiều sản phẩm OpenAI. Nhưng chúng tôi đã đi một vòng: từ một container Azure Cosmos DB đa bên thuê, sang cấp phát các container lưu trữ đơn bên thuê, rồi quay lại mặc định dùng container đa bên thuê. Hành trình đa bên thuê của Habitat vẫn ở giai đoạn đầu: dù hỗ trợ rất nhiều trường hợp sử dụng, chúng tôi vẫn có thể hoãn đầu tư vào mảng này bằng cách tận dụng các cơ chế nền tảng tích hợp sẵn của Azure Cosmos DB ở mọi nơi có thể.
Trước khi đi vào hành trình với Azure Cosmos DB, dưới đây là một số kiến thức cơ bản:
Một tài khoản Azure Cosmos DB xác định một tập hợp container và một chính sách sao chép
Mỗi container được cấp một mức thông lượng nhất định, tính bằng đơn vị yêu cầu mỗi giây (RU/s)
Dữ liệu trong mỗi container được phân mảnh theo khóa phân vùng logic chỉ định, với giới hạn lưu trữ và thông lượng cho từng khóa được nêu trong tài liệu
Azure Cosmos DB phân bổ các khóa phân vùng logic vào số lượng phân vùng vật lý ít hơn ở lớp dưới, rồi tách chúng thành nhiều phân vùng vật lý khi dung lượng lưu trữ vượt ngưỡng hoặc container cần thêm phân vùng vật lý để duy trì thông lượng cấp sẵn
Ban đầu, chúng tôi cho phép mọi tải từ máy khách đi qua, dựa vào giới hạn công bố 10 nghìn RU/s trên mỗi khóa phân vùng logic để tạo áp lực ngược, điều tiết tải đầu vào. Lúc mới bắt đầu, chúng tôi cũng chỉ dùng một container Azure Cosmos DB mặc định trong mỗi tài khoản. Cách này hoạt động tương đối tốt, nhưng bộc lộ vấn đề vì một số lý do:
Do các lựa chọn API ban đầu, chúng tôi cho phép máy khách trực tiếp chọn khóa phân vùng logic. Vì vậy, các trường hợp sử dụng sản phẩm khác nhau thường xuyên trùng khóa phân vùng phổ biến, như user_id hoặc workspace_id. Vì các trường hợp sử dụng này cùng chịu giới hạn Azure Cosmos DB trên những khóa phân vùng logic giống nhau, thiết kế đó giới hạn tổng thông lượng cho mỗi người dùng.
Trước khi chuyển sang Habitat và Azure Cosmos DB, một vấn đề phổ biến khi mở rộng Postgres là nhiều yêu cầu từ một tổ chức hoặc khóa có tải cực cao — tức một bên thuê tạo tải lớn bất tương xứng — có thể làm sập toàn bộ cơ sở dữ liệu. Chúng tôi đã dành nhiều công sức chung để lưu đệm các khóa đó và bổ sung cơ chế lease khi không tìm thấy dữ liệu trong bộ nhớ đệm, nhằm tránh để tải phát sinh từ các lần trượt bộ nhớ đệm làm quá tải cơ sở dữ liệu bên dưới.
Figure 02a · Logical partition key limits
Different clients, the same partition key
Dù các giới hạn về kích thước dữ liệu và thông lượng trong tài liệu áp dụng cho khóa phân vùng logic, giới hạn thực tế lại được thực thi ở phân vùng vật lý. Trong thực tế, điều này có nghĩa là các phân vùng logic không thể đạt 10.000 RU/s. Thay vào đó, chúng phải chia sẻ giới hạn của phân vùng vật lý với mọi khóa phân vùng logic khác cùng nằm trên phân vùng vật lý đó.
Điều này khiến tải lân cận gây nhiễu ảnh hưởng tới nhiều khóa phân vùng logic không liên quan: các tải xử lý dữ liệu cho tính năng ít dùng có thể làm gián đoạn luồng đăng nhập và đăng ký cốt lõi.
Figure 02b · Noisy neighbors
Different users, the same physical partition
Giới hạn thông lượng của một phân vùng vật lý cũng thay đổi, tùy theo tổng thông lượng được cấp cho container Azure Cosmos DB. Thông lượng cấp sẵn của container được phân bổ gần như đồng đều cho các phân vùng vật lý trong container đó.
Khi dữ liệu tăng lên, các phân vùng vật lý tách ra, làm tăng tổng số phân vùng trong khi tổng thông lượng cấp sẵn không đổi. Kết quả là giới hạn thông lượng thực tế trên mỗi phân vùng giảm khi kích thước dữ liệu tăng.
Với các trường hợp sử dụng tốn dung lượng nhất, lưu dữ liệu dạng blob, điều này tạo ra một kiểu sự cố: chỉ riêng việc dữ liệu lưu trữ tăng lên cũng làm giảm công suất thông lượng cho các tải đang hoạt động, ngay cả khi tốc độ yêu cầu và mức sử dụng vẫn ổn định.
Figure 02C · Weak partitions
The limit falls below demand
A partition splits when it reaches its storage limit. Each child receives half the throughput capacity.
Các container riêng giúp giải quyết một phần giới hạn khóa phân vùng và tình trạng tải lân cận gây nhiễu. Khi dùng container riêng, mỗi container có thể được cấp các phân vùng vật lý độc lập. Chỉ các tải công việc trong chính container đó mới có thể gây nhiễu lẫn nhau hoặc trùng lặp trong không gian khóa phân vùng. Đổi lại, việc cấp phát container mới phát sinh chi phí vận hành: mỗi container cần được hoạch định tài nguyên riêng. Vì vậy, chúng tôi chỉ muốn tách container theo dịch vụ hoặc trường hợp sử dụng khi hợp lý.
Chúng tôi bắt đầu dùng các container Azure Cosmos DB riêng cho những trường hợp sử dụng mới quan trọng nhất, cần mức cô lập cao. Kết hợp với một tập lệnh xử lý phân vùng yếu bằng cách điều chỉnh tổng thông lượng cấp sẵn của mỗi container theo số phân vùng vật lý, chúng tôi đã tránh được hầu hết các vấn đề đang gặp phải.
Tuy nhiên, vì khởi đầu với một container mặc định, nhiều trường hợp sử dụng quan trọng từ trước vẫn bị kẹt ở đó nếu không di chuyển dữ liệu. Để bảo vệ các dịch vụ thiết yếu vẫn dựa vào dữ liệu trong container mặc định dùng chung, chúng tôi thường khuyên các nhóm tạo container riêng cho dịch vụ mới hoặc tính năng sản phẩm lớn. Khi quy mô tăng, áp lực lên container mặc định tăng theo, kéo theo nhiều sự cố hơn trên môi trường vận hành thực tế. Chúng tôi bắt đầu cấp phát container cho mọi dịch vụ mới hoặc tính năng sản phẩm lớn, chỉ để container mặc định không phải chịu thêm tải.
Cách này giúp tránh nhiều sự cố ngừng hoạt động trên toàn hệ thống, giới hạn phạm vi ảnh hưởng ở mức suy giảm hoặc gián đoạn từng tính năng hay dịch vụ. Tuy nhiên, gánh nặng cấp phát container mới cuối cùng cũng trở thành vấn đề:
Trong container mặc định dùng chung trước đây, một trường hợp sử dụng mới tăng từ 0 lên 1 triệu QPS khó có thể làm tổng mức sử dụng thay đổi đáng kể. Nhưng trong container riêng, một trường hợp sử dụng mới tăng từ 0 lên 1 triệu QPS có thể tạo ra tải gấp 1.000 lần mức cơ sở vốn chỉ đến từ việc dùng thử nội bộ.
Với container chuyên dụng, các nhóm giờ phải nhớ cấp sẵn thông lượng theo mức dự kiến cho đợt ra mắt. Các nhóm sản phẩm thường đưa tính năng vào vận hành mà quên tăng tài nguyên trước. Đến ngày ra mắt, chúng tôi lại phải vào phòng xử lý sự cố nghiêm trọng (SEV), cố tăng quy mô container vào phút chót.
Việc gộp nhiều tải công việc là lợi ích cốt lõi của hệ thống đa bên thuê mà chúng tôi phải đánh đổi để có mức cô lập tốt hơn với chiến lược container này.
Figure 03 · Lack of stable aggregate growth
The same workload, different headroom
1K RU/s during load testing → 1M RU/s at launch
Theo thời gian, việc theo dõi mức sử dụng container chuyên dụng cũng đòi hỏi hiểu biết sâu về sản phẩm để biết khi nào lưu lượng sẽ chuyển dịch hoặc tăng lên.
Chúng tôi có thể cung cấp một tập lệnh cơ bản ở lớp điều khiển để tăng thông lượng cấp sẵn cho mỗi container theo xu hướng tăng trưởng. Nhưng khi thiếu tăng trưởng tổng hợp ổn định, việc điều chỉnh đúng mức khiến gần như mọi nhóm sản phẩm tại OpenAI đều phải tham gia hoạch định tài nguyên.
Cách này không thể mở rộng theo tổ chức, vì mức độ cẩn trọng trong cấp phát Azure Cosmos DB khác nhau rất nhiều giữa các nhóm phụ trách dịch vụ.
Khi tổ chức lớn mạnh, những vấn đề vận hành đó ngày càng cản trở việc mở rộng. Không có một nhóm trung tâm duy nhất phụ trách hoạch định, nhiều nhóm đã lên kế hoạch kém hiệu quả. Vì vậy, chúng tôi chuyển dần trở lại giải pháp đa bên thuê và hợp tác chặt chẽ với đội ngũ Azure để khắc phục các vấn đề ban đầu bằng thiết kế dùng chung:
Ưu tiên hạn chế tốc độ yêu cầu với các khóa có tải cao nhất giúp ngăn tải lân cận gây nhiễu chiếm hết thông lượng sẵn có của một phân vùng vật lý. Cách này giảm tình trạng một khóa có tải cao gây ảnh hưởng tới toàn hệ thống.
Tương tự, QoS phân tầng yêu cầu ngăn các tải công việc ngoại tuyến, như chèn hàng loạt hoặc trích xuất dữ liệu, sử dụng hết thông lượng của một phân vùng vật lý. Khi được gán mức ưu tiên thấp hơn, yêu cầu của các tải này sẽ bị hạn chế tốc độ trước, tránh ảnh hưởng tới yêu cầu tương tác có mức ưu tiên cao hơn phục vụ người dùng cuối.
Azure Cosmos DB vốn đã có chế độ không máy chủ có thể giải quyết vấn đề phân vùng yếu mà chúng tôi gặp trong chế độ cấp phát sẵn. Tuy nhiên, chế độ này có nhược điểm lớn: chỉ mở rộng theo dung lượng lưu trữ đã dùng và giới hạn mức sử dụng RU ở 5 nghìn RU/s trên mỗi phân vùng vật lý. Cách này giải quyết được vấn đề phân vùng yếu, nhưng ngăn chúng tôi mở rộng các trường hợp sử dụng tiêu tốn nhiều RU.
Đội ngũ Azure Cosmos DB đã xây dựng cho chúng tôi một chế độ không máy chủ cải tiến, cho phép mỗi phân vùng vật lý đạt tới 10 nghìn RU/s và bổ sung cơ chế tách phân vùng theo mức sử dụng RU bên cạnh dung lượng lưu trữ. Nhờ đó, chúng tôi không còn phải theo dõi và tăng quy mô container thủ công.
Nhờ các thay đổi này, chúng tôi đã quay lại dùng một container chung, giúp đơn giản hóa đáng kể việc hoạch định tài nguyên ban đầu lẫn liên tục cho các nhóm sản phẩm, mà vẫn duy trì sự cô lập giữa các tải công việc. Trong những tháng kể từ đó, chúng tôi không gặp sự cố nào về cấp phát tài nguyên hay tải lân cận gây nhiễu, dù tốc độ phát triển sản phẩm tăng lên.
Khi công ty đạt quy mô như OpenAI, dịch vụ được quản lý không còn được nhà cung cấp “lo trọn gói” như trước. Nhiều tải công việc trở thành trường hợp khác biệt trong hạ tầng của nhà cung cấp đám mây. Khi OpenAI trở thành một trong những đơn vị sử dụng Azure Cosmos DB lớn nhất, vận hành thành công đòi hỏi một cách làm khác: kiểm thử chung, bảng theo dõi chung, kênh kỹ thuật trực tiếp và cùng chịu trách nhiệm xử lý các kiểu sự cố chỉ xuất hiện ở quy mô của chúng tôi. Hiện nay, tài khoản Azure Cosmos DB lớn nhất của chúng tôi lưu trữ hàng chục petabyte dữ liệu và phục vụ hơn 20 triệu QPS. Theo hiểu biết của chúng tôi, OpenAI là công ty duy nhất đã triển khai Azure Cosmos DB ở quy mô này.
Cuối năm 2024, một sự cố cấp khu vực cho thấy rõ vì sao sự hợp tác này là cần thiết. Khi đó, khu vực Azure chính của một trong những tài khoản Azure Cosmos DB lớn nhất của chúng tôi bị mất điện. Trong quá trình chuyển đổi dự phòng sau đó, chúng tôi nhận ra các tài khoản lớn nhất cần vài giờ để chuyển sang khu vực thứ cấp — điều mà cả đội ngũ chúng tôi lẫn Azure Cosmos DB đều chưa kiểm thử ở quy mô này.
Khoảng một tháng sau, khi chuyển các tài khoản đó trở lại khu vực ban đầu, chúng tôi lại gây ra một sự cố nghiêm trọng khác. Một làn sóng kết nối ồ ạt tới khu vực ban đầu đã làm quá tải cổng kết nối Azure Cosmos DB tại đó. Một điểm bất thường trong cách máy khách Azure Cosmos DB ở chế độ cổng kết nối xử lý chuyển đổi dự phòng khiến mọi máy khách lập tức thiết lập kết nối và gửi yêu cầu tới khu vực ban đầu, dù mới chỉ có một phần các phân vùng vật lý được chuyển về.
Trong mỗi sự cố, cả OpenAI và Azure đều thực hiện quy trình quản lý sự cố, xác định nhiều nguyên nhân gốc rễ và triển khai các bản sửa lỗi. Nhưng những sự cố này là biểu hiện của một vấn đề mang tính hệ thống lớn hơn trong cách hai đội ngũ vận hành và kiểm thử. Ban đầu, tận dụng dịch vụ được quản lý giúp chúng tôi tiến nhanh và tập trung vào mục tiêu kinh doanh. Ở quy mô lớn, dịch vụ được quản lý không còn được lo trọn gói như trước, mà đòi hỏi phối hợp sâu với nhà cung cấp ở mọi cấp độ, từ thiết kế tới vận hành.
Hiện nay, các đội ngũ kỹ thuật Habitat và Azure cùng giám sát mọi lớp của Habitat, từ lớp dịch vụ của chúng tôi tới các lớp lưu trữ vật lý của Azure Cosmos DB. Chúng tôi vận hành và kiểm thử các thay đổi trên một tài khoản Azure Cosmos DB ngoài môi trường sản xuất nhưng có quy mô tương đương. Chúng tôi cùng kiểm thử, cải tiến SDK và xác định các phương pháp tối ưu để mở rộng, định cỡ tài khoản Azure Cosmos DB. Hai đội ngũ kỹ thuật có thể liên hệ trực tiếp qua Teams, thậm chí gửi cảnh báo gọi trực cho nhau mà không cần đi qua các tầng hỗ trợ.
Trong năm qua, hai bên đã phối hợp thực hiện nhiều cải tiến nhằm mở rộng khả năng xử lý của lớp điều khiển và cổng kết nối Azure Cosmos DB: bổ sung cơ chế chống quá tải và lưu đệm nhiều loại siêu dữ liệu Azure Cosmos DB tại cổng kết nối để bảo vệ phân vùng siêu dữ liệu; giảm áp lực từ các tiến trình habitat-service Python bằng cơ chế dùng chung và tăng tái sử dụng kết nối; đặt các tải công việc cùng vị trí khi có thể; và dùng các VPC khác nhau để tách tải công việc thiết yếu khỏi tải công việc ngoại tuyến.
Sự hợp tác kỹ thuật sâu sát này đóng vai trò then chốt trong việc duy trì sự ổn định của Azure Cosmos DB cho chúng tôi trong năm qua. Bất kỳ hệ thống nào đủ lớn hoặc đủ quan trọng đều cần cách làm việc nhóm này: phá bỏ rào cản về phạm vi phụ trách và phối hợp vượt qua ranh giới tổ chức.
Như đã đề cập ở Phần I, triết lý cốt lõi của chúng tôi là: làm cho hệ thống chạy được, chạy nhanh, rồi chạy tiết kiệm. Ưu tiên độ tin cậy, rồi đến hiệu năng, sau cùng là hiệu quả sử dụng tài nguyên. Habitat đã trở thành hạ tầng thiết yếu của OpenAI, nên ưu tiên hàng đầu là bảo đảm độ tin cậy. Khi hệ thống dần ổn định trong năm 2025 và OpenAI mở rộng toàn cầu, độ trễ trở thành điểm nghẽn tiếp theo đối với người dùng và các nhóm sản phẩm.
Tài nguyên tính toán và lưu trữ thường nằm ở các khu vực khác nhau, khiến các yêu cầu liên khu vực trở nên không thể tránh khỏi.
Figure 04 · Improving performance at a global scale
Global traffic
Compute and storage capacity were often located in different regions, making cross-region requests unavoidable.
Vị trí địa lý của hạ tầng tính toán và lưu trữ chỉ mang tính minh họa.
Độ trễ chênh lệch lớn tùy theo nơi lưu trữ dữ liệu và nơi xử lý yêu cầu. Để các yêu cầu tới Habitat đạt hiệu năng tốt, nhà phát triển sản phẩm phải bổ sung bộ nhớ đệm phía máy khách, gom lô yêu cầu, giảm thiểu thao tác đọc ghi cơ sở dữ liệu và đưa công việc ra khỏi luồng xử lý quyết định thời gian phản hồi khi có thể. Dù cách này tạo ra một số thiết kế sản phẩm thú vị, có khả năng chống chịu tốt hơn trước sự cố cơ sở dữ liệu, nó cũng làm sản phẩm phức tạp hơn và chậm cải tiến hơn. Điều này đi ngược mục tiêu của Habitat: thúc đẩy phát triển sản phẩm nhanh mà không cần hiểu rõ cơ sở dữ liệu.
Đây là trọng tâm lớn của chúng tôi trong năm 2026. Chúng tôi đã xây dựng chiến lược nhiều lớp để tối ưu hiệu năng đọc, loại thao tác chiếm hơn 90% yêu cầu tới Habitat:
Chúng tôi có nhiều tài khoản Azure Cosmos DB tại các khu vực Azure trên khắp thế giới để phục vụ người dùng có yêu cầu về nơi lưu trú dữ liệu. Ngay cả với người dùng không có yêu cầu bắt buộc về nơi lưu trú dữ liệu, việc đặt dữ liệu gần họ cũng cải thiện trải nghiệm nhờ giảm độ trễ.
Trên thực tế, ngoài các trường hợp có yêu cầu về nơi lưu trú dữ liệu, chúng tôi chưa thể áp dụng rộng rãi cách này vì vị trí đặt dữ liệu bị giới hạn bởi tài nguyên đám mây vật lý. Do các tập dữ liệu quá lớn, nhiều khu vực không thể đáp ứng dung lượng lưu trữ khổng lồ cần thiết cho tỷ lệ lưu lượng người dùng tương ứng.
Ở những khu vực hạn chế về tài nguyên trung tâm dữ liệu, điện hoặc khả năng làm mát, đôi khi chúng tôi phải lựa chọn trực tiếp: dành tài nguyên cho lưu trữ cùng vị trí để giảm độ trễ Habitat, hoặc dùng tài nguyên đó để tăng năng lực tính toán phục vụ yêu cầu và chuyển yêu cầu lưu trữ tới nơi xa hơn.
Vì vậy, quyết định đặt dữ liệu thường là sự đánh đổi ở cấp sản phẩm giữa: A) tối ưu độ trễ cho từng sản phẩm và nhóm người dùng, và B) tổng tài nguyên lưu trữ và tính toán sẵn có.
Với các tải công việc đòi hỏi độ trễ thấp nhất, chẳng hạn siêu dữ liệu xác thực cần cho mọi yêu cầu, chúng tôi giảm thời gian khứ hồi (RTT) giữa hạ tầng tính toán và Habitat bằng các tài khoản Azure Cosmos DB có nhiều bản sao tại nhiều khu vực thứ cấp. Một số tài khoản được sao chép tới cả 40 khu vực Azure nơi chúng tôi phục vụ lưu lượng; số khác được sao chép tới ít nhất một khu vực trên mỗi châu lục.
Chúng tôi đã phải xây dựng sớm hơn dự kiến một lớp di chuyển và định tuyến dữ liệu trong Habitat, hoạt động mà ứng dụng không cần biết, để chuyển các tập dữ liệu giữa những tài khoản có cấu trúc sao chép khác nhau.
Tuy nhiên, cách này rốt cuộc vẫn bị giới hạn bởi tài nguyên, nên chỉ áp dụng cho một vài tập dữ liệu được chọn kỹ.
Tải công việc của Habitat chủ yếu là đọc: ứng dụng liên tục lấy cài đặt, trạng thái và các thuộc tính khác. Một tập dữ liệu hoạt động tương đối nhỏ, thuộc các kiểu được truy cập thường xuyên, tạo ra phần lớn lưu lượng. Điều này khiến hệ thống đặc biệt phù hợp với bộ nhớ đệm phân tán. Bộ nhớ đệm cải thiện hiệu năng trong hạ tầng đơn khu vực, nhưng lợi ích còn lớn hơn khi hoạt động liên khu vực, vì nó có thể “che giấu” độ trễ giữa các khu vực.
Chúng tôi đã tích hợp một lớp bộ nhớ đệm phân tán kiểu lookaside vào Habitat. Lớp này lưu bản sao các đối tượng và cạnh được truy cập gần đây trên các máy chủ Valkey trong hạ tầng của chúng tôi, gần nơi xử lý yêu cầu người dùng. Thông thường, các bộ nhớ đệm này dùng thời gian sống (TTL) để cân bằng tỷ lệ trúng bộ nhớ đệm và độ lỗi thời của dữ liệu. TTL ngắn giảm độ lỗi thời nhưng làm giảm lợi ích của bộ nhớ đệm, vì các mục nhanh hết hạn và phải được lấy lại thường xuyên hơn. TTL dài tăng tỷ lệ trúng nhưng cung cấp dữ liệu lỗi thời lâu hơn, làm giảm trải nghiệm người dùng và khiến hành vi sản phẩm khó đoán.
Một cách khác là chủ động vô hiệu hóa bộ nhớ đệm khi ứng dụng ghi vào cùng dữ liệu nền bên dưới. Cách này cải thiện đáng kể tính cập nhật của dữ liệu đệm, nhưng khó triển khai đúng. Nó vẫn chịu ảnh hưởng của một số tình huống đặc biệt, như lỗi cục bộ khiến dữ liệu đệm không được cập nhật. Triển khai đa khu vực làm các vấn đề này trầm trọng hơn: mạng liên khu vực kém tin cậy hơn, còn bộ nhớ đệm có thể gặp tranh chấp thời điểm với quá trình sao chép dữ liệu lưu trữ bên dưới. Kết hợp thêm TTL giúp giới hạn thời gian lỗi thời tối đa, nhưng vẫn chịu cùng sự đánh đổi vốn có của TTL nêu trên.
Chúng tôi chọn cách vô hiệu hóa tiên tiến hơn, học hỏi từ các hệ thống như TAO của Meta. Bộ nhớ đệm tích hợp của Habitat dùng cơ chế thu thập thay đổi dữ liệu (CDC) qua luồng thay đổi của Azure Cosmos DB để truyền lệnh vô hiệu hóa trên toàn cầu trong vài giây, đạt tỷ lệ trúng cao mà vẫn giữ độ lỗi thời thấp. Một dịch vụ trong hạ tầng của chúng tôi đọc luồng thay đổi này và vô hiệu hóa dữ liệu đệm cục bộ khi dữ liệu nền được cập nhật. Lần đọc tiếp theo sẽ trượt bộ nhớ đệm, rồi bộ nhớ đệm được nạp phiên bản dữ liệu mới nhất.
Chúng tôi cũng giảm đáng kể độ trễ bằng cách loại bỏ chi phí xử lý dư thừa trong chính dịch vụ Habitat, viết lại mã bằng Rust để đạt hiệu năng tốt hơn Python ban đầu.
Kết hợp lại, các thay đổi này đã giảm độ trễ đọc p50 tổng thể trên toàn cầu từ khoảng 120 ms xuống khoảng 10 ms, cải thiện gấp 12 lần kể từ khi chúng tôi bắt đầu tập trung vào hiệu năng hồi đầu năm nay.
Figure 05 · Improving performance at a global scale
p50 latency for reads
Three major design changes improved read latency
Dù bộ nhớ đệm giảm mạnh độ trễ trung vị, các yêu cầu chậm nhất vẫn phải lấy dữ liệu chưa được lưu đệm từ lớp lưu trữ bên dưới, thường ở những khu vực xa. Khi bổ sung tài nguyên và cải thiện hiệu quả lưu trữ, chúng tôi dự định giải quyết thách thức căn bản hơn: đặt dữ liệu gần nơi truy cập ngay từ đầu.
CDC đáng tin cậy và có khả năng mở rộng — truyền thay đổi của cơ sở dữ liệu tới các hệ thống phía sau — là thành phần thiết yếu không chỉ trong chiến lược bộ nhớ đệm của Habitat. Hàng triệu thay đổi mỗi giây trên hàng nghìn container và hàng triệu phân vùng container được truyền qua hơn một trăm chủ đề Kafka. Chúng còn phục vụ các chỉ mục phụ nhất quán cuối cùng, quy trình di chuyển dữ liệu, phân tích ngoại tuyến và các tính năng sản phẩm thời gian thực khác. Khi hạ tầng nền mở rộng toàn cầu, việc theo dõi thay đổi ở các hàng dữ liệu ngày càng phức tạp. Để đăng ký hàm gọi lại mỗi khi hàng thuộc kiểu dữ liệu của mình thay đổi, máy khách trước hết phải xác định tài khoản và container Cosmos chứa dữ liệu, bản triển khai CDC nào đang theo dõi các container đó ở từng khu vực, đồng thời điều chỉnh quy mô đội tiến trình xử lý CDC, Kafka và trình tiêu thụ của mình cho phù hợp. Nền tảng CDC của chúng tôi che giấu toàn bộ sự phức tạp đó khỏi nhà phát triển sản phẩm, thay bằng giao diện đơn giản: máy khách đăng ký hàm cần gọi khi hàng dữ liệu thay đổi, còn chúng tôi lo kết nối hạ tầng và mở rộng quy mô.
Lớp điều khiển nội bộ liên tục bảo đảm mọi container cần thiết đều được thu thập thay đổi, chọn khu vực Cosmos để đọc và phân bổ hiệu quả công việc cho hàng nghìn tiến trình xử lý ở nhiều khu vực địa lý. Dùng các khu vực bản sao và hạ mức ưu tiên khi đọc luồng thay đổi giúp bảo vệ lưu lượng Habitat nhạy cảm với độ trễ khỏi tải thu thập chạy nền. Ở quy mô này, tiến trình xử lý bị sập, sự cố container, lỗi kho lease, cấu hình không hợp lệ và lỗi đích nhận xảy ra liên tục. Chúng tôi đã củng cố việc quản lý vòng đời tiến trình CDC và xử lý lease, cô lập lỗi giữa các luồng, đồng thời xây dựng cơ chế bảo vệ khi đổi cấu hình và triển khai. Chúng tôi dùng hàng đợi thông điệp lỗi để tránh lỗi gửi vĩnh viễn gây tắc nghẽn đầu hàng đợi. Chúng tôi chịu được sự cố cấp khu vực bằng cách chuyển các trình đọc sang khu vực Cosmos khác. Ở quy mô này, chúng tôi còn phải sửa SDK CDC của Azure để việc ghi điểm kiểm tra hiệu quả hơn: gom các điểm kiểm tra trong bộ nhớ và chỉ ghi xuống định kỳ.
Dù cách Habitat dùng Azure Cosmos DB bên trong rất phức tạp, giá trị cốt lõi vẫn luôn là che giấu chi tiết hạ tầng để nhà phát triển đẩy nhanh tiến độ sản phẩm. Nền tảng CDC của chúng tôi cũng vậy.
Một nhóm nhỏ đã hỗ trợ được nền tảng lưu trữ tăng trưởng nhanh nhờ chủ động giữ API lưu trữ gọn, tiếp tục mở rộng dịch vụ Python và ưu tiên các thách thức kỹ thuật cấp bách nhất. Chúng tôi ưu tiên độ tin cậy cho lưu lượng sản phẩm thiết yếu, rồi đến hiệu năng đọc cho người dùng toàn cầu, cuối cùng là hiệu quả vận hành ở quy mô lớn. Cách tiếp cận này hỗ trợ tăng trưởng nhanh và các trường hợp sử dụng mới, đồng thời cải thiện độ tin cậy, hiệu năng và tốc độ phát triển sản phẩm.
Để mở rộng Habitat và hệ thống lưu trữ hội thoại cho một tỷ người dùng tiếp theo, chúng tôi cần giải quyết bài toán sao chép dữ liệu trên toàn hạ tầng ở quy mô còn lớn hơn. Để đón đầu nhu cầu này, chúng tôi đang tự xây dựng hệ thống lưu trữ trực tuyến quy mô exabyte, tối ưu cho các kiểu dữ liệu dung lượng lớn của Habitat. Hệ thống đang phát triển này kết hợp lõi RocksDB Cloud của Rockset với cơ chế sao chép dựa trên Raft. Hệ thống dùng cùng mô hình tài liệu như Azure Cosmos DB, nhưng tách riêng lớp lưu trữ và dùng sao chép vật lý để giảm dung lượng flash cần thiết, đổi lại là QPS tối đa thấp hơn.
Nếu bạn muốn tham gia các dự án hạ tầng dữ liệu như thế này ở quy mô tiên phong, hãy xem các vị trí đang tuyển.


