Với đặc quyền nói chuyện với nhiều người và công ty dùng Redis cho nhiều use cases từ simple caching đến multi-terabyte setups, chủ đề tôi được hỏi nhiều nhất là performance. Redis khác biệt trong cách approach performance. Với hầu hết database servers, bạn cố improve performance. Với Redis, mục tiêu là không làm chậm nó lại. Đây là approach rất khác và cần mindset khác để tận dụng.
Performance Metrics – Latency có phải King?
Có 2 performance metrics chính khi dùng Redis: bao nhiêu commands (hoặc transactions) per second có thể execute và chúng mất bao lâu. Khi phân tích, bạn thấy metric thứ hai là secondary result từ metric thứ nhất. Vì Redis single-threaded, ops/sec bạn push tuyệt đối tied đến thời gian chúng mất. Vì vậy, điều quan trọng cuối cùng là "command latency".
Tôi coi một advantage của Redis là sự đơn giản. Bạn issue commands, không phải queries. Commands là route đơn giản hơn để pull data, và simplicity này phản ánh trong speed của commands. Nó cũng cho phép developers cung cấp optimized commands thay vì optimize cho various queries. Sự đơn giản thanh lịch này sau đó được trao cho programmers consume Redis. Thường nghĩa là làm "query" type operations như filtering set, ở client side thay vì server software làm.
Mặc dù một số người thấy query type này tốt nhất làm consistent way trên server, tôi hiện tại cho rằng không còn là preferred route nữa. Lý do là "scalability" bugbear. Khi chạy "horizontally scalable" web service/site, sớm tìm thấy pattern này work fine. Nhưng khi handle "obscene" traffic levels, nhanh chóng học được database là significant bottleneck. Ngay sau đó học được database này, thường là SQL store như MySQL, không "horizontally scalable". Không thể đơn giản add more.
Command Latency
Redis cũng không horizontally scalable. Nhưng khác biệt ở chỗ: bằng cách keep filtering logic, sorting, và bất cứ thứ gì không thể execute trong single Redis command hoặc tối đa vài commands, bạn không load DB down với logic - và do đó "things to process". Redis nên dùng như "data store", không phải traditional "database server". Đây là aspect đầu tiên của "don't slow Redis down" cần grok. Không cần nói rằng khi bắt đầu path Lua scripting, bạn run risk net lower performance. Có thể không thấy ở development khi traffic low-moderate. Nhưng khi hit large scales bạn sẽ thấy. Và lúc đó logic thường đã baked in và trở thành heavy technical debt để move vào application code. Chúng ta đều biết priority thường dành cho clearing technical debt như thế nào.
Không nói Lua scripting không có chỗ đứng. Chỉ có nghĩa là nó nên bị highly scrutinized. Rule of thumb tốt về khi Lua script là hoặc không phải net performance loss: compare cost của additional round trips bạn phải execute nếu handle logic client-side. Không phải là client code làm được bao lâu. Coi như sau: nếu reduce round trip cost 2ms, nhưng add 3ms script execution time thì bạn đi sai hướng.
Ở đây cần keenly aware bản chất single-threaded server. 3ms script blocking potentially hundreds (hoặc thousands) commands trong khi execute. Nếu split thành (pull) -> (logic) -> (pull) sequence, server able process additional requests trong phase "(logic)". Bằng cách keep logic trong client code, bạn preserve concurrency inherent to multi-client based system. Nếu cần transactions hoặc Lua scripting thì dùng. Nhưng đừng dùng vì chúng làm code "easier". Luôn aware concurrency performance hit, measure it, và make choice consciously.
Đây dẫn đến rule thứ 2 của "Don't Slow Redis Down": preserve concurrency bằng cách avoid server logic via scripts. Side benefit: ability migrate to Redis Cluster setup mà không rewrite hoặc dump Lua scripts operate trên multiple keys.
Các cách khác Redis bị slow down
Có vài system-level, operational aspects chạy Redis server có thể slow Redis down. Như bất kỳ server nào dùng I/O, resource limits có thể slow Redis down. Ví dụ: cần 8GB network bandwidth nhưng chỉ có 1GB, sẽ "slow" cho bạn. Nếu daemon process limited to fewer open sockets hơn concurrent connections cần, time spent waiting connections close thay vì execute commands.
Hai operational choices phổ biến nhất khiến Redis slow down: 1) đặt trên virtual machine - đặc biệt Xen hypervisor based, và 2) heavy disk persistence.
Cái đầu well-addressed trong standard Redis literature: đừng đặt trên Xen hypervisor VM. Cái thứ 2, persistence, dường như cũng được address nhưng theo tôi chưa đủ sâu.
Có standard recommendations: dùng local fast disk, đảm bảo enough memory handle CoW dance khi persist - thậm chí chạy persistence trên slaves only. Những này indeed có effects ripple đến command latency. Cái missing là how to properly determine nếu chúng có ảnh hưởng.
Một standard way test này: dùng inbuilt latency testing. Trước khi vào technical details, muốn address larger "how" question. Main subset: khi nào run tests. Thứ nhất, test này likely meaningless nếu dataset nhỏ. Nhỏ đến đâu? Xác định bao lâu dump data to disk. Nếu nói một hoặc hai giây, thậm chí mười, less likely get meaningful data. Tất cả predicated trên bạn làm BGSAVE thay vì SAVE.
Persistence Latency
Đây dẫn đến principle đầu của "persistence latency" - time từ command hit server đến result hit persistence form: Tìm persistence option ít introduce latency nhất. Tùy network và disk, AoF hoặc Slave server sẽ là lowest latency bumping persistence option, RDB last.
RDB last chủ yếu vì inbuilt delay N changes over T seconds. Giả sử đủ changes trong minimal duration (smallest default window 60 seconds), persistence delay là interval T + time write RDB to disk. Nếu mất 30s dump memory to disk với default 60s interval, "persistence latency" là (60+30) 90 seconds.
Điều này begs question: persistence latency có phải problem? Có 2 aspects: 1) Sufficient cho business requirements? 2) Nó slow down Redis?
Câu 1 không có generic answer cho mọi người. Tuy nhiên, nếu requirements persistence latency tight hơn formula trên reveal, answers likely trend toward "use slave và/hoặc AoF" thay vì RDB. Giả sử không making obvious mistakes trên platform chạy Redis. Đưa đến aspect 2: nó slow down Redis?
Với một số người, "bao lâu save RDB file" trở thành paramount. Theo tôi, đây là mistake. Có quan trọng bao lâu nó mất? Câu trả lời: "save có slow down Redis không". Nếu không, thì bạn không nên care nó mất 1 giây hay 1 giờ. Ví dụ: Server A mất 1000s save RDB. Khi không save, intrinsic command latency range 30-100 microseconds. Trong lúc save, latency vẫn 30-100 microsecond range. Case này, premature optimization để work trên reducing RDB save time dưới notion poor Redis performance.
Tuy nhiên Server B chỉ mất 10s, nhưng command latency nhảy từ 30-100us lên 130-250us. Bây giờ có reason concerned về bao lâu RDB file generate vì save đang slow Redis down và bạn muốn minimize. Nếu nghĩa là faster disks, ít nhất bây giờ có reason justify chúng - giả sử increase ~100-150 microseconds gây performance anxiety cho app. Nếu không, quay lại premature optimization.
Về cách measure latency đó, tôi sẽ detail hơn ở part 2 vì bài này đã khá dài.