1. Không sử dụng mật khẩu
Phần lớn mọi người đều không đặt mật khẩu cho Redis instance của họ, điều này rất tệ với phiên bản hiện tại của Redis bởi vì chúng ta có thể sử dụng CONFIG SET / CONFIG GET để thay đổi các cấu hình (config) bằng các câu lệnh (command) từ client mà không cần phải thay đổi từ file config redis.config cũng như phải restart Redis. Điều này sẽ dẫn tới các hệ lụy nếu như Redis server chúng ta có thể bị tìm thấy, ai đó hoàn toàn có thể flushing toàn bộ Redis bằng cách sử dụng Config Set/Get để chạy câu lệnh phức tạp nào đó.
Lời khuyên / Best practices: Hãy đặt mật khẩu Redis của bạn bằng cách sử dụng dịch vụ AUTH password
2. KEYS
Redis lưu trữ dữ liệu dưới dạng key-value, và keys là thứ đầu tiên ta phải học khi tiếp cận với Redis, thường mọi người cũng không thực sự hiểu rõ về KEYS của Redis và sử dụng nó một cách tuỳ tiện, điều đó rất có thể gây ra những lỗi tiềm ẩn trên Prod mà một ngày đẹp trời nào đó bạn sẽ gặp phải. Và sau đây là một vài “sự thật” về Redis Keys.
- Redis chạy “single thread”.
- Redis chỉ có thể chứa được 2³² key tức là khoảng 4 tỷ key.
- Dung lượng của mỗi key tối đa là 512Mb
- Độ phức tạp thuật toán của KEYS (dùng để tìm kiếm keys khi thỏa mãn một pattern) là O(n), với n là tổng số key trong Redis.
Khi ta tạo một ứng dụng phụ thuộc vào KEYS ví dụ như dùng Redis làm bản sao của DB, mọi thứ sẽ rất ổn nếu số lượng KEYS không quá lớn. Nhưng theo thời gian số lượng KEYS sẽ tăng lên rất lớn dẫn đến việc Redis sẽ mất nhiều thời gian hơn để tìm kiếm dữ liệu key, lý do là độ phức tạp của nó là O(n). Một lý do nữa làm ảnh hưởng tới performance của Redis đó là Redis chạy “single thread”, do đó trong khi Redis thực thi một truy vấn thì mọi truy vấn khác sẽ “dừng lại” (blocking) cho tới khi truy vấn kia hoàn thành. Vì đó sẽ không quá khó hiểu khi với số lượng KEYS càng lớn thì Redis chạy càng chậm.
Lời khuyên / Best practices: Hãy sử dụng SCAN để giới hạn số lượng KEYS trước mỗi truy vấn, tránh trường hợp cả server bị blocking trong một khoảng thời gian dài với trường hợp có số lượng lớn KEYS trong hệ thống. Nó giống như bạn sử dụng LIMIT/OFFSET trong Relational database vậy.
3. HOT KEYS
Với một hệ thống lớn chạy Redis Cluster ta sẽ phải phân chia (sharding) dữ liệu cache trên nhiều node/shard để đáp ứng với số lượng lớn request đến hệ thống. Mỗi KEY sẽ được phân bố đều các node/shard dựa theo việc Data của nó được phân bố ở đâu, việc này được xác định bằng việc băm (hashing) KEY bằng một hàm băm ổn định (Consistent hashing).
Tuy nhiên nếu một vài số lượng KEYS nhỏ được truy vấn quá nhiều so với phần còn lại (HOT KEYS) sẽ dẫn tới việc một node/shard chứa HOT KEYS đó sẽ bị quá tải so với phần còn lại, do đó việc sharding sẽ không còn ý nghĩa nữa. Lấy một ví dụ ta có một hệ thống Redis chạy Sharding với 99 node, và có 1 node có chứa HOT KEY là “sexy_ladies” chịu tới cả triệu request / giây, và tất nhiên là cả triệu request đó chỉ tập trung 1 node duy nhất chứ không phải phân tải đều cho 98 nodes còn lại.
Để kiểm tra các HOT KEYS, Redis cung cấp cho chúng ta tham số --hotkeys
ví dụ
$ redis-cli -h localhost -p 6379 --hotkeys
Lời khuyên / Best practices: Lời khuyên ở đây là trong quá trình phát triển không nên tạo ra một lượng nhỏ các keys được thường xuyên sử dụng (ví dụ các tham số setting trong hệ thống), mà thay vào đó cố gắng phân tán nó ra thành nhiều các keys khác và phân chia chúng đều ra từng node/shard.
4. Mở mỗi connection một request.
Việc mở mỗi connection một request và sau khi lấy dữ liệu xong thì đóng nó lại là một điều khá phổ biến và bình thường khi ta làm việc với CSDL hay với các REST API. Nhưng với Redis thì lại được thiết kế khác, mỗi connection nên được lưu trữ lại (persistent) trong một khoảng thời gian dài (long-lived connection) và được sử dụng cho nhiều request cùng lúc vào thời điểm đó. Nhưng với thói quen làm việc với DB lâu năm, thường các Developer sẽ không để ý tới đặc điểm này của Redis và mỗi request họ sẽ mở ra một connection và sau đó dùng xong họ lại đóng lại. Thực tế thì việc này về mặt kỹ thuật thì vẫn chạy được, nhưng nó sẽ ảnh hưởng tới performance của Redis.
Lời khuyên / Best practices: Cố gắng mở (open) và giữ (hold) mỗi connection cho nhiều request khác nhau (long polling) bằng cách thiết lập và sử dụng Redis Connection Pool.
5. Sử dụng Redis thay thế cho Database chính.
Redis được thế kế như một Cached layer, tuy nhiên đôi khi ta có thể thấy một vài dự án lại sử dụng Redis như một DB chính (primary database). Để sử dụng Redis như một DB chính ta đòi hỏi thiết lập nhiều config khác nhau để bảo toàn dữ liệu (consistency) hay tính khả dụng (high availability). Vì với hệ thống Redis thì bản chất của nó là một bộ đệm để tăng performance cho hệ thống hay giảm tải cho DB chính, do đó việc mất dữ liệu hay không tìm thấy dữ liệu là một điều hết sức bình thường, nhưng với một primary database thì điều đó là không được phép xảy ra. Và nếu Redis hay Cached Layer của ta down thì hệ thống vẫn có thể hoạt động được, tuy rằng có thể chậm hoặc quá tải, tuy nhiên nếu primary DB mà down thì cả hệ thống sẽ sụp đổ ngay lập tức.
Lời khuyên / Best practices: Sử dụng cơ chế AOF/snapshotting để backup dữ liệu để đảm bảo tính consistency của Redis, và sử dụng Redis Sentinel để bảo toán tính sẵn sàng (high availability) của Redis. Tuy nhiên việc này cũng sẽ ảnh hưởng tới performance của Redis, bởi vậy tốt nhất không nên sử dụng Redis như một DB chính mà chỉ nên dùng nó như Cached layer.
6. Không giới hạn số lượng values trong các kiểu CTDL dạng hash hay list như HGETALL, LRANGE, SMEMBERS, and ZRANGE
Như bạn đã biết, kiểu cấu trúc dữ liệu kiểu HGETALL có thể lưu trữ dạng key-value trong từng Redis key, nói dễ hiểu thì gần giống như một Redis thu nhỏ trong 1 Key của Redis. Số lượng value có trong HGETALL có thể tới 2³² và độ phức tạp thuật toán khi tìm kiếm key trong HGETALL cũng là O(n) với n là số lượng values trong HGETALL.
Nếu một ta không giới hạn số lượng value trong HGETALL dẫn tới nó có quá nhiều key, chẳng hạn có tới 2³² key trong HGETALL và cũng có 2³² key trong Redis, thì lúc này để tìm kiếm một value trong HGETALL độ phức tạp thuật toán lên tới O(n²) và ta cũng sẽ gặp vấn đề tương tự với KEYS như bên trên ta đã đề cập.
Tương tự với kiểu dữ liệu dạng List snhư LRANCE hay Sorted Sets / Sets như SMEMBERS / ZRANGE ta cũng sẽ gặp tình trạng tương tự nếu không giới hạn số lượng value trong mỗi kiểu CSDL đó.
Lời khuyên / Best practices: Hạn chế số lượng value trong các kiểu CTDL dạng hashs, lists, sets không nên chứa quá nhiều value trong một Redis key. Nếu yêu cầu cần thiết phải chứa rất nhiều các value trong 1 Key dạng đó, ta nên làm tương tự với best practices của KEYS là giới hạn số lượng value mỗi lần truy vấn bằng cách sử dụng HLEN cho hashes, LLEN cho lists, SCARD cho sets và ZCARD cho sorted sets.
7. Sử dụng nhiều Database trên cùng một Redis Instances.
Có thể bạn chưa biết là Redis cung cấp một tính năng là phân chia các Database khác nhau trên cùng 1 instance, có nghĩa là mỗi Redis instance có thể chứa nhiều khu lưu trữ dữ liệu (database) khác nhau. Số lượng tối đa mà Redis hỗ trợ trên mỗi instance là 16 database [0–15], và chúng ta sử dụng command SELECT để di chuyển sang các database khác nhau, ví dụ để switch sang database số 16 ta sử dụng câu lệnh:
127.0.0.1:6379> select 15
Trên mỗi DB các Key-Value được lưu trữ một cách độc lập có nghĩa là các Key có thể trùng nhau trên mỗi database. Thú vị rằng tính năng này rất ít được biết đến và không được thông dụng cho lắm, và chính tác giả của Salvatore Sanfilippo của Redis cũng ta từng nói rằng: “Sai lầm lớn nhất của tôi khi thiết kế Redis là tính năng numbered databases, nó đem lại những rắc rối và phức tạp không cần thiết”. Thực tế thì đúng vậy, nhất là với việc bạn phải làm việc với cluster/scaling Redis, multiple DBs sẽ đem lại rất nhiều “đau đớn” trên Production, tin tôi đi!
Lời khuyên / Best practices: Không nên sử dụng numbered databases trên single Redis instance, thay vào đó hay chạy nhiều các Redis instance một cách độc lập nhau.
Nguồn: