So sánh nhỏ: Redis vs Memcached

So sánh nhỏ: Redis vs Memcached
Photo by Brett Jordan from Unsplash

Khi nói đến cache ở phía server, có hai giải pháp phổ biến nhất: Redis và Memcached. Cả hai công cụ này chia sẻ nhiều điểm chung cũng như mỗi công cụ lại có những điểm riêng biệt. Trong bài viết này, tôi sẽ trình bày một số so sánh nho nhỏ những điểm giống và khác nhau của hai công cụ này.

Khái quát

Cả Redis và Memcached đều có chung những đặc điểm như:

  • Lưu dữ liệu dạng key-value dạng in-memory, tốc độ đọc/ghi cao
  • Mã nguồn mở
  • Dùng để tăng hiệu suất ứng dụng
  • Hầu hết các dịch vụ cloud đều hỗ trợ hai công cụ này

Redis là gì?

Redis là viết tắt của Remote Dictionary Server, một công cụ được tạo ra năm 2009 bởi Salvatore Sanfilippo (nickname antirez). Mục đích ban đầu của Redis là để tăng khả năng mở rộng của công cụ phân tích log mà startup của anh ta đang xây dựng. Bản prototype của Redis được viết bằng Tcl và sau đó bản chính thức dùng ngôn ngữ lập trình C. Khi Sanfilippo quyết định mở mã nguồn của Redis, nó đã gây được tiếng vang lớn. GitHub và Instagram là những tên tuổi lớn đầu tiên sử dụng Redis.

Memcached là gì?

Memcached được tạo ra sớm hơn, từ năm 2003 bởi Brad Fitzpatrick để sử dụng cho mạng xã hội LiVEJOURNAL. Ban đầu Memcached được viết bằng Perl, sau đó cũng được chuyển sang ngôn ngữ lập trình C. Memcached được sử dụng bởi một số tên tuổi lớn như Facebook, Youtube.

Lưu trữ dữ liệu

Redis lưu dữ liệu như nào?

Redis hỗ trợ rất nhiều kiểu dữ liệu khác nhau: Strings, Lists, Sets, Hashes, Sorted sets, Streams, Geospatial indexes, Bitmaps, Bitfields, HyperLogLog. Redis còn cho phép sử dụng extension để sử dụng các kiểu dữ liệu phức tạp khác. Nhờ đó, Redis hỗ trợ nhiều thao tác xử lý khác nhau tương ứng với từng kiểu dữ liệu. Redis cho phép truy cập hoặc thay đổi một phần dữ liệu mà không cần phải tải toàn bộ object lên ứng dụng, thay đổi rồi lưu trữ trở lại.

Redis sử dụng cơ chế cấp phát bộ nhớ của malloc/free. Đây là cách tiếp cận đơn giản hơn cơ chế Memcached Slab. Redis hỗ trợ key có kích thước lên tới 512MB và value cũng có kích thước tối đa tương tự.

Memcached lưu dữ liệu như nào?

Khác với Redis, Memcached không có kiểu dữ liệu, mọi dữ liệu sẽ được lưu dưới dạng string. Cách làm này khiến Memcached ít có dữ liệu overhead hơn so với Redis. Ngoài ra, cơ chế lưu trữ của Memcached phụ thuộc vào bộ nhớ của máy chủ. Khi bộ nhớ đã đầy, Memcached sẽ tìm cách giải phóng bộ nhớ bằng cách xóa bớt dữ liệu cũ.

Cơ chế cấp phát bộ nhớ của Memcached được gọi là Slab. Cơ chế này chia nhỏ bộ nhớ thành từng khối có kích thước khác nhau và lưu trữ dữ liệu vào các khối đó. Cách làm của Memcached giúp dữ liệu không bị phân mảnh. Memcached hỗ trợ key có kích thước đối đa 250B và value kích thước tối đa 1MB.

Lợi ích của kiểu dữ liệu

Lấy một ví dụ đơn giản về việc dùng cache để lưu trữ session của người dùng. Nếu sử dụng Memcached, khi phải thay đổi một trường trong object, toàn bộ object (lưu dưới dạng string) phải được tải lên ứng dụng, chuyển đổi dữ liệu, cập nhật rồi lưu lại.

Trong khi đó, nếu sử dụng Redis thì có thể dùng dữ liệu kiểu hash. Kiểu dữ liệu này cho phép truy cập tới từng trường của object và việc cập nhật diễn ra rất dễ dàng. Tầng ứng dụng hầu như không phải có những logic để tải dữ liệu, chuyển đổi, v.v… và nhờ đó, hiệu suất của ứng dụng cũng cao hơn.

Các ứng dụng cũng có thể sử dụng các cấu trúc dữ liệu thích hợp để hỗ trợ nhiều trường hợp sử dụng. Ví dụ, khi phát triển và vận hành server game, có thể sử dụng Redis Sorted Sets để dễ dàng triển khai tính năng bảng xếp hạng người chơi sắp xếp theo điểm số.

Khả năng mở rộng (scale)

Redis mở rộng như thế nào?

Redis chủ yếu chạy single-thread và hỗ trợ clustering, nên nó có thể dễ dàng mở rộng theo chiều ngang. Redis clustering hoạt động với kiến ​​trúc master/slave. Đối với mỗi node master, sẽ có 2 node slave để dự phòng. Nếu master bị lỗi, Redis sẽ đưa một node slave thành master.

Việc này giúp Redis hoạt động ổn định, dễ dàng mở rộng theo chiều ngang nhưng nhược điểm là sự phức tạp trong quản lý hoạt động. Điểm khó nhất là đồng bộ dữ liệu giữa nhiều node chạy song song. Tất nhiên, những điểm khó này do Redis đảm nhiệm, người dùng không cần phải quá lo lắng.

Memcached mở rộng như thế nào?

Memcached chạy multi-thread và nó có thể dễ dàng mở rộng theo chiều dọc. Chỉ cần có đủ thêm CPU và bộ nhớ là Memcached sẽ mở rộng đến hết khả năng của server. Việc mở rộng theo chiều ngang không được hỗ trợ sẵn. Nếu muốn, vẫn có thể chạy nhiều server Memcached song song, nhưng ở phía client phải tự quản lý logic để phân phối dữ liệu. So sánh với Redis thì việc mở rộng theo chiều ngang của Memcached khó khăn hơn rất nhiều.

Sao lưu/phục hồi, duy trì dữ liệu

Dù cả hai đều là những công cụ lưu dữ liệu in-memory cho phép đọc/ghi nhanh, nhưng Redis được gọi là data store còn Memcached là data cache. Đây cũng điểm rất quan trọng để xác định Redis may Memcached sẽ phù hợp với từng bài toán

Ngay từ cái tên đã cho thấy sự khác biệt. Đầu tiên, việc quản lý dữ liệu trong bộ nhớ của Memcached dựa trên cơ chế LRU (least recently used) trong khi Redis hỗ trợ nhiều cơ chế khác nhau:

  • No eviction: trả về lỗi nếu không đủ bộ nhớ
  • All keys LRU: xóa các key lâu được sử dụng nhất
  • Volatile LRU: xóa các key có thiết lập thời gian hết hạn, từ key lâu được sử dụng nhất
  • All keys random: xóa các key ngẫu nhiên
  • Volatile random: xóa các key thiết lập thời gian hết hạn một cách ngẫu nhiên
  • Volatile TTL: xóa các key thiết lập thời gian hết hạn, kể từ key có thời gian sống (TTL – Time To Live) ngắn nhất.

Ngoài ra, Redis có cơ chế sao lưu/phục hồi dữ liệu trong khi Memcached thì không. Khi Redis server gặp lỗi và phải khởi động lại, Redis có thể lấy lại dữ liệu cũ còn Memcached thì bắt buộc phải tạo lại từ đầu. Vì vậy Redis mới được gọi là data store. Thực ra, Memcached cũng có thể sao lưu và phục hồi dữ liệu nhưng phải sử dụng thêm công cụ của bên thứ ba, sẽ có nhiều khó khăn hơn so với tính năng có sẵn của Redis.

Cơ chế sao lưu/phục hồi của Redis có hai kiểu:

  • RDB snapshot: Snapshot là bản sao lưu của toàn bộ dữ liệu, sẽ được lưu trữ trên bộ nhớ ngoài. Việc sao lưu sẽ được thực hiện định kỳ sau khoảng thời gian nhất định. Vì vậy, dữ liệu của Redis có thể lấy lại được khi cần khởi động lại.
  • AOF log (Append Only File log): Đây là file log ghi lại toàn bộ các lệnh được thực hiện bởi Redis server. File log này cũng được lưu trữ trên bộ nhớ ngoài. Và khi khởi động lại, các lệnh trong log sẽ được thực hiện lại một lần nữa, nhớ đó dữ liệu sẽ được khôi phục.

Việc sử dụng cơ chế nào tùy thuộc vào yêu cầu cụ thể. Cơ chế RDB snapshot yêu cầu thời gian nhất định để sao lưu dữ liệu. Và nếu dữ liệu của Redis quá lớn, quá trình này sẽ mất nhiều thời gian, ảnh hưởng đến hiệu suất hoạt động của Redis server. Nhưng ngược lại, việc khôi phục dữ liệu từ bản sao lưu lại rất nhanh.

Nếu yêu cầu phải khôi phục được toàn bộ dữ liệu từ AOF log là giải pháp duy nhất. Bởi vì mọi lệnh sẽ được ghi vào log, mọi thao tác sẽ đều được ghi lại. Trong khi đó, RDB snapshot sao lưu định kỳ sẽ có rủi ro mất dữ liệu. Nhược điểm của AOF log là file log sẽ có kích thước rất lớn và việc khôi phục dữ liệu tốn nhiều thời gian.

Nên chọn công cụ nào?

Redis mạnh mẽ và có nhiều tính năng hơn Memcached. Redis hỗ trợ các dữ liệu phức tạp với nhiều kiểu dữ liệu khác nhau. Nhờ đó, các thao tác truy vấn, cập nhật dữ liệu đơn giản hơn, hiệu suất hoạt động của nó cũng tốt hơn. Đây là một trong những ưu điểm cực lớn của Redis. Khả năng sao lưu/phục hồi dữ liệu của Redis cũng là một điểm đáng chú ý.

Redis một sản phẩm hiện đại, nhiều tính năng và vẫn đang được phát triển tích cực. Ngoài dùng để cache, Redis có thể được dùng làm database (dạng NoSQL), streaming engine, message broker. Trong khi đó, Memcached là một công cụ cache đơn thuần.

Trong hầu hết các dự án mà tôi đã trải qua, Redis luôn được chọn. Sự lựa chọn đến tương đối nhanh mà không phải suy nghĩ quá nhiều. Redis có nhiều lệnh phức tạp để thao tác với dữ liệu hơn. Rất nhiều thao tác nếu dùng trên Memcached sẽ phải kết hợp nhiều logic phức tạp. Tôi nhớ chỉ có duy nhất một dự án từ rất lâu rồi sử dụng Memcached. Thời điểm đó, Redis còn quá mới và người ta chưa làm quen được với nó.

Thế nhưng, giờ đây mọi chuyện đã thay đổi. Redis đã xuất hiện đủ lâu và không ai còn lạ lẫm gì những thao tác làm việc với nó nữa. Thậm chí các thư viện hỗ trợ lập trình viên làm việc với Redis cũng rất nhiều. Vì vậy, ý kiến cá nhân của tôi, chọn Redis sẽ không sai.

Memcached sẽ là lựa chọn tốt hơn trong một vài trường hợp đặc thù. Memcached là một trong những giải pháp bộ nhớ đệm mã nguồn mở phổ biến đầu tiên, hoạt động tốt cho các khối lượng công việc có key-value cơ bản. Nhờ khả năng chạy multi-thread, Memcached có vẻ sẽ hoạt động tốt hơn với lượng dữ liệu lớn.

Một trường hợp nữa là khi cần cache dữ liệu từ cơ sở dữ liệu MySQL (nếu dùng engine InnoDB). Nghe nói InnoDB đã hỗ trợ sẵn Memcached, nên dùng kết hợp với Memcached sẽ không cần phải làm gì nhiều. Thế nhưng, tôi chưa thấy ai dùng Memcached chỉ để cache cơ sở dữ liệu cả, còn rất nhiều dữ liệu khác cũng cần cache.

Quan trọng hơn, ngay cả trong những trường hợp như vậy, Redis cũng có thể đáp ứng được yêu cầu. Dù hiệu suất không bằng nhưng sự chênh lệch không đáng kể so với những tính năng mạnh mẽ mà nó mang lại.

Tôi xin lỗi nếu bài viết có bất kỳ typo nào. Nếu bạn nhận thấy điều gì bất thường, xin hãy cho tôi biết.

Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.