Redis (REmote DIctionary Service “) là một trong những cơ sở dữ liệu “in-memory” nhanh nhất, thiết kế để truy xuất và lưu trữ dữ liệu với độ trễ cực thấp. Mặc dù chỉ hoạt động trên luồng đơn ( single- thread), Redis vẫn vượt trội hơn nhiều cơ sở dữ liệu đa luồng nhờ kiến trúc hướng sự kiện ( event-driven) và khả năng quản lý bộ nhớ hiệu quả.
Redis được sử dụng rộng rãi trong các hệ thống cache phân tán, hay quản lý các phiên làm việc (session management), trung gian truyền thông điệp ( message brokering) hay phân tích dữ liệu thời gian thực ( real-time analysis) . Nó là nền tảng cho nhiều ứng dụng lớn như Twitter, Github, Stackoverflow.
Trong bài viết này, chúng ta sẽ cùng tìm hiểu sâu hơn về nội tại của Redis, tập trung vào mô hình thực thi đơn luồng, kiến trúc phân tán, và vai trò của nó như một hệ thống cache hiệu suất cao.
Vì sao Redis lại nhanh 😒
Chạy đơn luồng (single-thread)
- Thoạt nhìn redis chỉ sử dụng một luồng (thread) có vẻ là hạn chế nhưung thực ra là điểm mạnh:
- Không tranh chấp giữa các thread ⇒ Giảm thiểu thời gian khoá bộ nhớ, đồng bộ dữ liệu
- Dễ dự đoán và tối ưu: Dữ liệu phải được xử lý tuần tự, tránh các lỗi phức tạp độ ổn định luôn được ưu tiên.
- Redis hoạt động như một mô hình event-loop: Mọi kết nối , thao tác đọc/ ghi đều được xử lý qua một vòng lặp sự kiện ( giống Node.js), cho phép hàng ngàn kết nối đồng thời và nhanh chóng.
3 sockets khác nhau represents cho 3 network connections khác nhau, với đặc trưng single thread của redis, nó sẽ làm nhiệm vụ:
- event loop sẽ monitor các socket activites trong IO multiplex
- Khi event ready, nó sẽ place vô task queue
- Event sau đó sẽ được pool ra và disatch vào processor để execute
⇒ Tum cái quần lại là bạn có thể scalable network application bằng cách allows a single thread quản lý hiệu quả các connections simultaneously mà không blocking.
Tối ưu bộ nhớ
- Sử dụng các cấu trúc dữ liệu nhỏ gọn: string, list, set, sorted set, hash, bitmap, hyperloglog
- Nén và chia nhỏ các dữ liệu tuỳ chỉnh
- Eviction policy: LRU, LFU, TTL, v.v….
Dữ liệu luôn ở trong RAM
- Redis lưu toàn bộ dữ liệu trong RAM để đạt tốc độ tối đa nhưng vẫn có cơ chế để lưu ra đĩa - RDB (Redis database backup) or AOF (Append only file).
Kiến trúc cốt lõi
Redis diễn ra là tất cả mọi thứ trong RAM, vì vậy tốc độ xử lý vô cùng nhanh, chỉ tầm vài ms, loại bỏ các tác vụ nặng nề như I/O bottlenecks.
Tuy nhiên Redis chỉ là RAM/In-memory storage. Nó là cache đứng trước các scenario cần phải query data thật như PostgresQL, MYSQL, nhờ vào việc sử dụng nó mà có thể tối ưu thời gian load memory và giảm thời gian gọi xuống central database.
Nhưng nó dễ bị giới hạn về bộ nhớ , vì vậy nó sẽ có cơ chế loại bỏ ( eviction policy) để remove khi bộ nhớ đạt được đến giới hạn.Default sẽ dùng volatile-lru - key ít được sử dụng gần đây nhất. Trừ trường hợp active-active database dùng noneviction policy.
Thêm vào đó, Redis có 2 cơ chế để tối ưu cho việc hoạt động:
- MMAP để tự động build scripts load data vào từ file vào redis.
Như hồi cũ, bạn phải sử dụng câu lệnh dưới đây để copy từ file vào socket:
int fd = open("data.rdb", O_RDONLY);
char buffer[4096];
while (read(fd, buffer, sizeof(buffer)) > 0) { write(socket_fd, buffer, sizeof(buffer)); // Copy to socket
}
giờ đây mọi thứ ngắn gọn hơn:
int fd = open("data.rdb", O_RDONLY);
struct stat st;
fstat(fd, &st); // Memory-map the file (memory-mapped I/O)
void* file_memory = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
⇒ Redis sử dụng mmap trong fork để snapshot data trong khi tiếp tuc
- Zero-copy cloning techniques optimistic
Data type redis used for storage
Nó hỗ trợ rất nhiều các loại data types khác nhau từ Bitmap với chuỗi sequences bytes tới bitfield với các chunk N bytes.
Một khía cạnh quan trọng khác là Redis làm mờ ranh giới giữa bộ nhớ đệm và lưu trữ dữ liệu. Điều quan trọng cần lưu ý là việc đọc và thao tác dữ liệu trong bộ nhớ nhanh hơn so với sử dụng SSD hoặc ổ cứng để lưu trữ dữ liệu truyền thống.
Chỉ dùng để lưu trữ ?
Ngay từ ban đầu, Redis sử dụng như 1 memCached và chỉ dùng để lưu trữ dữ liệu, nhưng rồi mọi thứ thay đổi, nó viable để thực hiện pub/sub mechanism, stream processing.
Memcached
Memcached được tạo ra bởi Brad Fitzpatrick vào năm 2003, sáu năm trước Redis. Nó bắt đầu như một dự án Perl và sau đó được viết lại trong C. Điểm yếu so với redis là support ít data types hơn và chỉ duy nhất 1 eviction policy LRU.
Một điểm khác biệt khác là Redis là một luồng đơn, trong khi Memcached là nhiều luồng. Memcached có thể hoạt động tốt trong môi trường bộ đệm nghiêm ngặt, nhưng yêu cầu một số thiết lập trong một cụm phân tán, trong khi Redis hỗ trợ điều này ngay lập tức.
Các cách triển khai redis khác nhau và sự đánh đổi của chúng
Single Redis instance
Đây là cách đơn giản nhất để triển khai Redis. Nó cho phép người dùng thiết lập và chạy các trường hợp setup đơn giản ( dưới local) để giúp họ phát triển và tăng tốc dịch vụ của họ. Tuy nhiên, phương pháp triển khai này không phải là không có nhược điểm của nó. Ví dụ: nếu redis failover hoặc restart, ,mặc định tất cả các requests đến Redis sẽ thất bại, giảm tính toàn vẹn của hệ thống.
Ability and speed:
- Với đủ bộ nhớ và tài nguyên máy chủ, trường hợp này có thể rất mạnh mẽ. Sử dụng chủ yếu để lưu trữ có thể cải thiện đáng kể hiệu suất với thiết lập tối thiểu. Cho đủ tài nguyên hệ thống, bạn có thể triển khai dịch vụ Redis này trên cùng một máy chủ nơi ứng dụng của bạn đang chạy.
- Điều quan trọng là phải hiểu một số khái niệm Redis để quản lý dữ liệu trong hệ thống. Các lệnh được gửi đến redis được xử lý trước trong bộ nhớ. Sau đó, nếu persistent được thiết lập trên các trường hợp đó, có một quy trình được chạy sau một khoảng thời gian nào đó: có thể là RDB (Redis database backup) hoặc AOF.
- Hai quy trình này cho phép Redis có lưu trữ dài hạn, hỗ trợ các chiến lược sao chép khác nhau và cho phép các cấu trúc liên kết phức tạp hơn. Nếu Redis không được thiết lập persistent, dữ liệu sẽ bị mất trong trường hợp khởi động lại. Ngược lại, nó sẽ tải tất cả dữ liệu từ RDB hoặc AOF vào bộ nhớ.
Đi tiếp vào các trường hợp distributed setup mà bạn muốn sử dụng.
Redis high availability
Một thiết lập phổ biến khác cho Redis là sự kết hợp giữa primary và secondary instance.
- one primary : handle all writes
- multiple secondaries: replicate data from primary ( read-only default).
- Về mặt tổng quát, setup này:
- Tăng khả năng scale read
- Cải thiện fault tolenrance (secondary fail) - nhưng phải manually promote secondary to primary
- Bắt buộc cho automatic failover ( redis sentinel hoặc redis cluster) .
High availability
Tính khả dụng cao (HA) là một tính năng của một hệ thống được thiết kế để đảm bảo hiệu suất hoạt động ổn định trong một khoảng thời gian trung bình kéo dài.
Trong các hệ thống này, không nên có điểm thất bại duy nhất để hệ thống có thể phục hồi nhanh chóng ⇒ không có dữ liệu nào bị mất trong quá trình chuyển đổi từ primary sang secondary và khả năng tự động phát hiện và phục hồi từ lỗi.
Redis replication
Mỗi instance trong Redis đều gồm2 thành phần: replicationID và offset dùng để track tiến trình synchronize với primary
Redis sentinel
Sentinel là một hệ thống phân tán. Giống như tất cả các hệ thống phân tán, Sentinel có một số ưu điểm và nhược điểm. Sentinel được thiết kế theo cách mà nhiều quy trình Sentinel hoạt động cùng nhau để phối hợp trạng thái để cung cấp Redis HA. Rốt cuộc, bạn không thể có 1 hệ thống bảo vệ bạn khỏi thất bại nếu nó có single point of failure.
Sentinel chịu trách nhiệm cho một số khía cạnh. Đầu tiên, nó đảm bảo rằng các instance node đều đang hoạt động và đáp ứng nhu cầu. Điều này là cần thiết vì Sentinel (cùng với các quy trình Sentinel khác) có thể cảnh báo và hành động trong trường hợp primary hay secondary node bị down. Thứ hai, nó đóng một vai trò tương tự như ZooKeeper và Consul trong các hệ thống khác. Vì vậy, khi 1 yêu cầu gửi đến redis, nó sẽ cho bạn biết node chính đang là gì. Ngoài ra, Sentinel liên tục theo dõi tính khả dụng và gửi thông tin này cho khách hàng để nếu họ thất bại, khách hàng có thể phản ứng với nó.
Tổng kết lại thì các đặc điểm chính của sentinel bao gồm:
-
Giám sát - Đảm bảo các primary và secondary node hoạt động đúng như mong đợi.
-
Thông báo - Thông báo cho quản trị viên hệ thống về một cái gì đó xảy ra trong trường hợp Redis.
-
Quản lý chuyển đổi dự phòng - Các nút Sentinel có thể bắt đầu quá trình promote secondary lên primary.
.4. Quản lý cấu hình - Nút Sentinel cũng đóng vai trò là trung tâm cấu hình cho phiên bản Redis chính hiện tại.
Fault detection có thể đạt được bằng cách sử dụng Redis Sentinel. Phát hiện này liên quan đến các Sentinel process đồng ý rằng phiên bản primary hiện tại không còn nữa. Quá trình đồng thuận này được gọi là quorum.
Số người hợp pháp
Quorum là số lượng phiếu bầu tối thiểu mà hệ thống phân tán phải có được để được phép thực hiện một hoạt động, chẳng hạn như chuyển đổi dự phòng. Số này có thể định cấu hình nhưng sẽ phản ánh số lượng nút trong hệ thống phân tán. Hầu hết các hệ thống phân tán có kích thước ba hoặc năm sentinel process, với các quorum tương ứng hai hoặc ba. Rõ ràng, số lẻ luôn được yêu thích đã có majority.
Có thể triển khai Redis Sentinel theo nhiều cách khác nhau. Thành thật mà nói, để đưa ra bất kỳ khuyến nghị hợp lý nào thì nhiều bối cảnh hệ thống hơn tôi có ngay bây giờ. Theo hướng dẫn thì nên chạy một nút Sentinel bên cạnh mỗi máy chủ ứng dụng (nếu có thể) để không cần tính đến sự khác biệt về khả năng tiếp cận mạng giữa nút Sentinel và máy khách thực sự sử dụng Redis.
Có thể chạy Sentinel với một phiên bản Redis hoặc thậm chí trên một nút độc lập ( standalone node) , nhưng điều này làm phức tạp mọi thứ theo những cách khác nhau. Tôi khuyên bạn nên chạy ít nhất ba nút với một đại biểu ít nhất hai nút.
IMPORTANT: đừng nhầm lẫn giữa sentinel count và replica count
The number of Sentinels is purely about voting/failover reliability. The number of Redis replicas (secondaries) is about read‑scaling and data redundancy.
Redis cluster
Nhiều người đang tự hỏi điều gì xảy ra khi bạn có thể lưu trữ tất cả dữ liệu của mình trên một máy. Hiện tại, RAM tối đa có sẵn trên một máy chủ được liệt kê trực tuyến trên AWS là 24TB, và trong khi đó rất nhiều, đối với một số hệ thống, nó không đủ, ngay cả đối với tầng bộ nhớ đệm.
Redis cluster cho phép Redis mở rộng theo chiều ngang.
Thuật ngữ gossip protocol - Trao đổi trạng thái cụm: Mỗi nút (chính hoặc bản sao) trao đổi định kỳ thông tin nhịp tim & cấu trúc liên kết với một vài nút khác để fault tolenrance và consensus
Vertical and horizontal expansion
Khi hệ thống của bạn phát triển, bạn có ba tùy chọn:
-
Làm ít hơn (không ai hoàn toàn làm điều này bởi vì chúng ta là những con quái vật tham lam) .
-
Tăng quy mô.
-
Mở rộng ra.
Coi trọng hai trường hợp sau, mở rộng dọc và mở rộng theo chiều ngang được gọi tương ứng .
Mở rộng dọc (nhiều máy hơn) không phải là một chiến lược luôn hoạt động vì ngay cả các máy lớn cũng có RAM giới hạn.
Để hệ thống mở rộng theo chiều ngang, hệ thống cần có khả năng mở rộng thành nhiều nút để tải được phân phối đều giữa các nút khác nhau. Redis Cluster cho phép người dùng kết hợp nhiều nút để đạt được loại tỷ lệ này. Mặc dù Redis Cluster cung cấp một cách để đạt được điều này, các hệ thống phân tán rất khó khăn và không nên được sử dụng nếu không có sự hiểu biết đầy đủ về lợi thế và nhược điểm của chúng.
Đầu tiên, hãy xem xét các câu hỏi sau:
• Tính nhất quán của dữ liệu : Khi bạn ghi vào một nút, làm thế nào để đảm bảo rằng cùng một dữ liệu có sẵn trên tất cả các nút khác?
• Dữ liệu được phân vùng như thế nào - dữ liệu được xử lý như thế nào khi nó được phân vùng trên nhiều nút? Redis Cluster là giải pháp phân tán chính thức được cung cấp bởi Redis. Nó cung cấp một cách để dữ liệu phân vùng theo chiều ngang trên nhiều nút, với các tính năng tích hợp như phân phối lại tự động và sao chép dữ liệu để xử lý các lỗi nút.
Đối với các lệnh như + GET user: 123 + set cart: ABC,
Băm key và tìm kiếm node nào sở hữu khe cắm đó (nó lưu trữ bản đồ khe cắm cụm). Lệnh được gửi thẳng đến node đó. Trả lời trở lại ngay lập tức, không cần sự phối hợp liên tục.
Tuy nhiên, điều quan trọng cần lưu ý là cụm Redis cũng đòi hỏi nhiều cấu hình và công việc bảo trì hơn vì nó giới thiệu sự phức tạp hơn.
Tổng kết
Redis là một cơ sở dữ liệu trong bộ nhớ mạnh mẽ có thể được sử dụng cho nhiều trường hợp sử dụng, bao gồm bộ nhớ đệm, lưu trữ dữ liệu và các ứng dụng thời gian thực. Bạn có thể chọn các cấu hình Redis khác nhau dựa trên các yêu cầu ứng dụng, bao gồm triển khai độc lập, cấu hình khả dụng cao của Redis Sentinel (HA) và triển khai phân tán của Redis Cluster (distributed).
Hiểu mô hình dữ liệu của Redis, và các loại dữ liệu được hỗ trợ rất quan trọng để sử dụng Redis một cách hiệu quả. Redis cung cấp nhiều loại dữ liệu như chuỗi, băm, danh sách, bộ và bộ được sắp xếp, làm cho nó phù hợp cho nhiều trường hợp sử dụng.
Cuối cùng, việc sử dụng thành công REDIS phụ thuộc vào cấu hình và quản lý thích hợp, và cần được thu nhỏ và điều chỉnh dựa trên nhu cầu tải và sẵn có. Các ứng dụng khác nhau đòi hỏi các chiến lược triển khai Redis khác nhau, vì vậy, điều quan trọng là phải có sự hiểu biết sâu sắc về khả năng của Redis và các thực tiễn tốt nhất. Tôi hy vọng thông tin này hữu ích và giúp bạn hiểu rõ hơn về Redis và vai trò của nó trong các hệ thống phân tán.
Ref:
https://redis.io/technology/redis-enterprise-cluster-architecture/
https://www.geeksforgeeks.org/redis-and-its-role-in-system-design/
https://medium.com/@hubian/redis-parsing-infographic-14ec1f4b3202
https://medium.com/hepsiburadatech/redis-solutions-standalone-vs-sentinel-vs-cluster-f46e703307a9