300 triệu bản ghi với Redis và giải pháp của Instagram
Đây là câu chuyện về 1 lần chuyển đổi hệ thống của Instagram. Lúc đó họ cần một giải pháp map 300 triệu bức ảnh với user id tương ứng, các yêu cầu đặt ra là: Trả về giá trị tương ứng theo khóa với tốc độ cực nhanh Tiết kiệm bộ nhớ, sử dụng 1 server với RAM 17GB hoặc 34GB chứ ko phải cỡ 68GB ...
Đây là câu chuyện về 1 lần chuyển đổi hệ thống của Instagram.
Lúc đó họ cần một giải pháp map 300 triệu bức ảnh với user id tương ứng, các yêu cầu đặt ra là:
- Trả về giá trị tương ứng theo khóa với tốc độ cực nhanh
- Tiết kiệm bộ nhớ, sử dụng 1 server với RAM 17GB hoặc 34GB chứ ko phải cỡ 68GB
- Phù hợp với hạ tầng hiện tại đã có
- Bền vững, an toàn, ko để mất dữ liệu
Giải pháp đơn giản nhất là lưu vào các hàng trong database, với các cột "Media ID" và "User ID". Tuy nhiên một cơ sở dữ liệu SQL có vẻ quá mức cần thiết cũng như không đem lại hiệu suất cao, các bản ghi này ko bao giờ update, chỉ insert, chẳng cần transaction và cũng chẳng có quan hệ nào giữa các bảng.
Thay vào đó các kỹ sư của Instagram đã quyết định chuyển sang Redis, một key-value store nâng cao mà họ đã mở rộng và đem lại sức mạnh cho phần main feed của họ. Redis không chỉ là 1 cơ chế key-value thông thường dạng lưu vào rồi lấy ra như Memcached mà nó thực sự là 1 công cụ lợi hại trong lĩnh vực key-value.
Redis cung cấp những kiểu dữ liệu tính toán mạnh mẽ như sorted sets và lists. Ngoài ra còn cung cấp một cơ chế bảo toàn dữ liệu có thể cấu hình, dữ liệu được lưu trữ ngầm theo khoảng thời gian và có thể cài đặt để chạy master-slave. Tất cả server Redis của Instagram được deploy với master-slave với các slave lưu vào ổ cứng hàng phút.
Ban đầu, họ quyết định dùng Redis theo cách đơn giản nhất có thể. Với mỗi ID, key sẽ là media ID và value sẽ là user ID:
SET media:1155315 939 GET media:1155315 > 939
Khi thử nghiệm giải pháp này họ tìm ra rằng Redis cần khoảng 70MB để lưu trữ 1,000,000 key theo cách này. Mở rộng ra với 300,000,000, con số thực tế mà họ cần, nó sẽ tốn vào khoảng 21GB bộ nhớ, như vậy đã là lớn hơn server 17GB của Amazon EC2
Họ tìm đến sự trợ giúp từ: Pieter Noordhuis, một trong những dev chính của Redis, và anh ta đã khuyên họ rằng, hãy sử dụng Redis Hash. Hash trong Redis là một dạng từ điểm mà có thể mã hóa, đóng gói(encode) trong bộ nhớ rất hiệu quả. Trong phần setting của Redis có một cấu hình là 'hash-zipmap-max-entries' dùng để tùy chỉnh số lượng thực thể tối đa một hash có thể chứa mà vẫn đảm bảo việc encode hiệu quả. Họ đã nghiên cứu và tìm ra rằng con số 1000 là tốt nhất, bất kỳ con số nào cao hơn khi chạy lệnh HSET sẽ gây ra cảnh báo với hoạt động của CPU.
Để tận dụng lợi thế của kiểu dữ liệu Hash, họ đóng gói tất cả Media ID thành từng gói 1000 (Lấy tất cả ID ra chia cho 1000 và bỏ phần dư). Ví dụ với Media ID là 1155315 sẽ nằm ở gói 1155 (1155315 / 1000 = 1155).
HSET "mediabucket:1155" "1155315" "939" HGET "mediabucket:1155" "1155315" > "939"
Kích thước đã thay đổi một cách bất ngờ, với 1,000,000 key (đóng gói thành 1000 hash, mỗi hash chứa 1000 key), Redis chỉ cần 16MB để lưu trữ. Nhân lên với 300 triệu key, con số tổng sẽ là 5GB, trong thực tế chi phí rẻ hơn rất nhiều, chỉ vào khoảng 1/3 so với trước đây. Và hơn cả là việc truy xuất hash có độ phức tạp là O(1) nên tốc độ xử lý là vô cùng nhanh.
Nếu bạn hứng thú với những điều trên, đây là đoạn mã các kỹ sư của Instagram đã dùng để test (họ có test cả Memcached trong đoạn mã để so sánh và nó tốn khoảng 52MB cho 1 triệu key): https://gist.github.com/mikeyk/1329319
Bài viết tham khảo từ: http://instagram-engineering.tumblr.com/post/12202313862/storing-hundreds-of-millions-of-simple-key-value. Chúc các bạn sử dụng Redis hiệu quả