logo

Lộ trình

Khóa học

Tài liệu

Mock Interview

Liên hệ

Quay lại
  • Trang chủ

    /

  • Tài liệu

    /

  • Time-To-Live (TTL) trong Redis hoạt động như nào?
Tài liệu

Time-To-Live (TTL) trong Redis hoạt động như nào?

Ronin Engineer

9 Tháng 8 2023

<p>Redis là một công nghệ cool ngầu. Nó giải quyết nhiều bài toán khó về caching và distributed system (hệ phân tán). Ngoài ra, nó còn support nhiều cấu trúc dữ liệu đáp ứng cho nhiều use case khác nhau và nhiều algorithm ẩn bên trong.</p><p>Hôm nay mình và các bạn sẽ cùng tìm hiểu:</p><ul><li>Time-To-Live (TTL) trong Redis hoạt động như nào?</li><li>Những vấn đề mà các cách tiếp cận gặp phải</li><li>Best Practices khi đặt TTL</li></ul><h2 id="%C4%91%E1%BB%8Bnh-ngh%C4%A9a-time-to-live-ttl">Định nghĩa Time-To-Live (TTL)</h2><p>Time-To-Live là khái niệm phổ biến được sử dụng trong 2 lĩnh vực:</p><ul><li><strong>Mạng máy tính (Computer Networking)</strong>: Mỗi packet (network layer) chứa 1 trường TTL dùng để đếm số router (hop) mà packet có thể đi qua được. Khi đi qua mỗi router (hop), TTL sẽ bị trừ đi 1 đơn vị. Nếu TTL = 0 thì packet sẽ bị drop.</li><li><strong>Bộ nhớ đệm (Caching)</strong>: TTL ám chỉ khoảng thời gian mà dữ liệu được lưu trước khi dữ liệu đó bị xoá đi. Việc xoá dữ liệu này phản ánh <strong>dữ liệu có thể còn không hợp lệ</strong> và giúp <strong>giải phóng bộ nhớ</strong>.</li></ul><figure class="kg-card kg-image-card"><img src="https://images.viblo.asia/2fec62e4-53b5-4ef0-80c5-7023a89d7408.jpeg" class="kg-image" alt="" loading="lazy" width="825" height="413"></figure><h2 id="time-to-live-trong-redis-ho%E1%BA%A1t-%C4%91%E1%BB%99ng-nh%C6%B0-n%C3%A0o">Time-To-Live trong Redis hoạt động như nào?</h2><p>Khi một key được cài đặt Time-To-Live, sau khoảng thời gian TTL đó, key đó sẽ tự động được xoá đi.</p><h3 id="c%C3%A1ch-ti%E1%BA%BFp-c%E1%BA%ADn-ban-%C4%91%E1%BA%A7u">Cách tiếp cận ban đầu</h3><p>Redis sử dụng và kết hợp đồng thời 2 cách để xoá key khi hết hạn:</p><p><strong>Passive Way</strong>:</p><p>Redis <strong>không xoá key ngay khi hết hạn</strong>. Cho tới khi ta lấy (GET) key đó, Redis mới check key đã hết hạn chưa. Nếu đã hết hạn thì sẽ trả về null trước rồi <strong>xoá key đó đi một cách bất đồng bộ</strong>.</p><p>Cách này khá đơn giản nhưng gặp 1 vấn đề. Đó là có những key mà sẽ bao giờ được động tới, như vậy nó sẽ chiếm không gian nhớ.<br>Để khắc phục tình trạng này, Redis kết hợp với Active Way - xoá chủ động.</p><p><strong>Active Way</strong>:</p><p>Redis thực hiện job xoá key chủ động 10 lần / giây (trong code gọi là <code>activeExpireCycle</code>)</p><ul><li>Bước 1: Lấy random 20 keys có gắn TTL. Trong có thể có keys hết hạn và key chưa hết hạn.</li><li>Bước 2: Thử xoá 20 keys đó</li><li>Bước 3: Nếu có nhiều hơn 25% của 20 keys bị hết hạn, lặp lại bước 1.</li></ul><p></p><p>Do Redis hoạt động dựa trên single-thread, khi job xoá key chủ động chạy thì sẽ <strong>block các request khác</strong>. Do đó, Redis có <strong>cấu hình timeout cho job</strong> này tránh tình trạng bị treo do quá nhiều key đồng thời hết hạn.</p><p>Việc kết hợp 2 cách này hoạt động rất tốt trong hầu hết các trường hợp thực tế. Tuy nhiên vẫn có trường số lượng key expire lớn và việc lấy sampling random khiến job <code>activeExpireCycle</code> hoạt động không hiệu quả. Mọi người có thể đọc thêm ở reference [4].</p><h3 id="c%C3%A1ch-ti%E1%BA%BFp-c%E1%BA%ADn-m%E1%BB%9Bi">Cách tiếp cận mới</h3><p>Redis khắc phục nhược điểm của cách tiếp cận trên bằng cách: <strong>các key sẽ được sắp xếp bởi thời gian hết hạn (expiration time)</strong> và lưu trong Sorted Set (ZSET) giúp cho việc tìm kiếm key hết hạn nhanh chóng hơn.</p><p>*Lưu ý: Có người nói key được sort bởi Radix Tree. Nhưng phần này mình thấy trong code và document không nói rõ ràng. Nếu bạn biết chính xác keys được sort như nào thì comment bên dưới giúp mình để mọi người rõ hơn nhé.</p><h2 id="best-practices-khi-%C4%91%E1%BA%B7t-ttl">Best Practices khi đặt TTL</h2><ul><li><strong>Dựa trên yêu cầu nghiệp vụ</strong>: dựa vào ý nghĩa của dữ liệu mà ta đặt TTL cho phù hợp. Ví dụ dữ liệu về session thì có TTL ngắn hơn so với static content như ảnh, đường dẫn, …</li><li><strong>Đối với những TTL dài thì ta cần random các giá trị này để chúng được dải đều ra</strong>. Tránh tình trạng “thundering herd" xảy ra khi tất cả key đồng thời hết hạn, gây ra load cao ở các tầng app và DB</li><li><strong>Sử dụng đúng kiểu dữ liệu</strong>: Không phải tất cả kiểu dữ liệu điều có cơ chế TTL giống nhau. Ví dụ, List và Set hỗ trợ TTL theo từng phần tử, còn Sorted Set và Hash thì không.</li><li><strong>Chú ý cấu hình Eviction Policy</strong> dựa trên yêu cầu của hệ thống. Khi Redis ăn hết mem, nó sẽ evict key dựa trên cấu hình (LRU, LFU, …)</li><li>Nếu không có yêu cầu đặc biệt từ nghiệp vụ thì thông thường <strong>nên đặt TTL ngắn</strong> để tránh chiếm mem và dữ liệu được update.</li><li>Nếu bạn có bổ sung thêm best practice thì comment bên dưới giúp mình nhé.</li></ul><hr><p>🏢 System Design VN: <a href="https://fb.com/groups/systemdesign.vn?ref=roninhub.com">https://fb.com/groups/systemdesign.vn</a></p><hr><h2 id="tham-kh%E1%BA%A3o">Tham Khảo</h2><p>[1] <a href="https://redis.com/ebook/part-2-core-concepts/chapter-3-commands-in-redis/3-7-other-commands/3-7-3-expiring-keys/?ref=roninhub.com">https://redis.com/ebook/part-2-core-concepts/chapter-3-commands-in-redis/3-7-other-commands/3-7-3-expiring-keys/</a></p><p>[2] <a href="https://redis.io/commands/expire/?ref=roninhub.com">https://redis.io/commands/expire/</a></p><p>[3] <a href="https://github.com/redis/redis/blob/7.0.12/src/expire.c?ref=roninhub.com">https://github.com/redis/redis/blob/7.0.12/src/expire.c</a></p><p>[4] <a href="https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/improving-key-expiration-in-redis?ref=roninhub.com">https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/improving-key-expiration-in-redis</a></p>

Redis là một công nghệ cool ngầu. Nó giải quyết nhiều bài toán khó về caching và distributed system (hệ phân tán). Ngoài ra, nó còn support nhiều cấu trúc dữ liệu đáp ứng cho nhiều use case khác nhau và nhiều algorithm ẩn bên trong.

Hôm nay mình và các bạn sẽ cùng tìm hiểu:

  • Time-To-Live (TTL) trong Redis hoạt động như nào?
  • Những vấn đề mà các cách tiếp cận gặp phải
  • Best Practices khi đặt TTL

Định nghĩa Time-To-Live (TTL)

Time-To-Live là khái niệm phổ biến được sử dụng trong 2 lĩnh vực:

  • Mạng máy tính (Computer Networking): Mỗi packet (network layer) chứa 1 trường TTL dùng để đếm số router (hop) mà packet có thể đi qua được. Khi đi qua mỗi router (hop), TTL sẽ bị trừ đi 1 đơn vị. Nếu TTL = 0 thì packet sẽ bị drop.
  • Bộ nhớ đệm (Caching): TTL ám chỉ khoảng thời gian mà dữ liệu được lưu trước khi dữ liệu đó bị xoá đi. Việc xoá dữ liệu này phản ánh dữ liệu có thể còn không hợp lệ và giúp giải phóng bộ nhớ.

Time-To-Live trong Redis hoạt động như nào?

Khi một key được cài đặt Time-To-Live, sau khoảng thời gian TTL đó, key đó sẽ tự động được xoá đi.

Cách tiếp cận ban đầu

Redis sử dụng và kết hợp đồng thời 2 cách để xoá key khi hết hạn:

Passive Way:

Redis không xoá key ngay khi hết hạn. Cho tới khi ta lấy (GET) key đó, Redis mới check key đã hết hạn chưa. Nếu đã hết hạn thì sẽ trả về null trước rồi xoá key đó đi một cách bất đồng bộ.

Cách này khá đơn giản nhưng gặp 1 vấn đề. Đó là có những key mà sẽ bao giờ được động tới, như vậy nó sẽ chiếm không gian nhớ.
Để khắc phục tình trạng này, Redis kết hợp với Active Way - xoá chủ động.

Active Way:

Redis thực hiện job xoá key chủ động 10 lần / giây (trong code gọi là activeExpireCycle)

  • Bước 1: Lấy random 20 keys có gắn TTL. Trong có thể có keys hết hạn và key chưa hết hạn.
  • Bước 2: Thử xoá 20 keys đó
  • Bước 3: Nếu có nhiều hơn 25% của 20 keys bị hết hạn, lặp lại bước 1.

Do Redis hoạt động dựa trên single-thread, khi job xoá key chủ động chạy thì sẽ block các request khác. Do đó, Redis có cấu hình timeout cho job này tránh tình trạng bị treo do quá nhiều key đồng thời hết hạn.

Việc kết hợp 2 cách này hoạt động rất tốt trong hầu hết các trường hợp thực tế. Tuy nhiên vẫn có trường số lượng key expire lớn và việc lấy sampling random khiến job activeExpireCycle hoạt động không hiệu quả. Mọi người có thể đọc thêm ở reference [4].

Cách tiếp cận mới

Redis khắc phục nhược điểm của cách tiếp cận trên bằng cách: các key sẽ được sắp xếp bởi thời gian hết hạn (expiration time) và lưu trong Sorted Set (ZSET) giúp cho việc tìm kiếm key hết hạn nhanh chóng hơn.

*Lưu ý: Có người nói key được sort bởi Radix Tree. Nhưng phần này mình thấy trong code và document không nói rõ ràng. Nếu bạn biết chính xác keys được sort như nào thì comment bên dưới giúp mình để mọi người rõ hơn nhé.

Best Practices khi đặt TTL

  • Dựa trên yêu cầu nghiệp vụ: dựa vào ý nghĩa của dữ liệu mà ta đặt TTL cho phù hợp. Ví dụ dữ liệu về session thì có TTL ngắn hơn so với static content như ảnh, đường dẫn, …
  • Đối với những TTL dài thì ta cần random các giá trị này để chúng được dải đều ra. Tránh tình trạng “thundering herd" xảy ra khi tất cả key đồng thời hết hạn, gây ra load cao ở các tầng app và DB
  • Sử dụng đúng kiểu dữ liệu: Không phải tất cả kiểu dữ liệu điều có cơ chế TTL giống nhau. Ví dụ, List và Set hỗ trợ TTL theo từng phần tử, còn Sorted Set và Hash thì không.
  • Chú ý cấu hình Eviction Policy dựa trên yêu cầu của hệ thống. Khi Redis ăn hết mem, nó sẽ evict key dựa trên cấu hình (LRU, LFU, …)
  • Nếu không có yêu cầu đặc biệt từ nghiệp vụ thì thông thường nên đặt TTL ngắn để tránh chiếm mem và dữ liệu được update.
  • Nếu bạn có bổ sung thêm best practice thì comment bên dưới giúp mình nhé.

🏢 System Design VN: https://fb.com/groups/systemdesign.vn


Tham Khảo

[1] https://redis.com/ebook/part-2-core-concepts/chapter-3-commands-in-redis/3-7-other-commands/3-7-3-expiring-keys/

[2] https://redis.io/commands/expire/

[3] https://github.com/redis/redis/blob/7.0.12/src/expire.c

[4] https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/improving-key-expiration-in-redis

redis
beginner

Bài viết liên quan

CORS: Bản Chất, Hạn Chế và Best Practices

By Đức Hiếu Cross-Origin Resource Sharing (CORS) là một cơ chế bảo mật quan trọng trong phát triển web application hiện đại, cho phép kiểm soát việc truy cập tài nguyên giữa các domain khác nhau. 1. Vấn đề mà CORS  giải quyết 1.1. Thời kỳ đầu Web: không có Same-Origin Policy (SOP) Trong những ngày đầu của World Wide Web, các trình duyệt không có bất kỳ hạn chế nào về việc truy cập tài nguyên giữa các domain khác nhau. JavaScript code từ một trang web có thể: * Gửi requests đến mọi server

Materialized view với PostgreSQL

Khái niệm view trong relational database chắc hẳn đã quá quen thuộc với anh em dev. View chỉ lưu trữ câu lệnh truy vấn, không lưu kết quả truy vấn và thực hiện truy vấn trên (các) bảng gốc mỗi khi view được truy cập. Vậy nếu truy vấn của view là một truy vấn phức tạp cho thống kế, cần JOIN nhiều bảng, nhiều điều kiện FILTER, tập dữ liệu ở bảng gốc lớn, có nhiều phép tổng hợp như SUM, AVG… Thì các bạn có đoán được vấn đề gì sẽ xuất hiện không? Nếu câu trả lời của các bạn là “hiệu suất của truy

Stack & Queue - Khi array không chỉ để lưu trữ

Stack & Queue là hai cấu trúc dữ liệu cơ bản và phổ biến trong con đường của một lập trình viên, hẳn rằng những lập trình viên có kinh nghiệm đều đã nghe, đã biết đến cấu trúc dữ liệu này, vậy cuối cùng thì, Stack & Queue là gì và nó có tác dụng thế nào? QUEUE - HÀNG ĐỢI Để bắt đầu nhẹ nhàng, chúng ta bắt đầu với Queue trước. Trước tiên thì Queue là một cấu trúc dữ liệu có dạng FIFO (First In Frist Out) tức là vào trước thì ra trước. Một ví dụ dễ thấy trong cuộc sống hàng ngày là việc xếp

Connection Pool: Tối ưu hiệu suất kết nối Database trong hệ thống Backend

By Đức Hiếu 1. Connection Pool là gì? Connection Pool là một cơ chế quản lý kết nối giữa các ứng dụng đến cơ sở dữ liệu (Database Server), trong đó một tập hợp các kết nối được khởi tạo trước và duy trì sẵn sàng để sử dụng. Thay vì phải thiết lập kết nối mới mỗi khi cần truy vấn dữ liệu. Database Client (thường là Backend App) có thể "mượn" một kết nối có sẵn từ pool, sử dụng xong và trả lại pool để tái sử dụng. 1.1. Vấn đề với phương pháp kết nối truyền thống Trong mô hình kết nối truyền

HTTP/1.1 vs HTTP/2 : Tại sao HTTP/2 lại nhanh hơn?

By @VietDuc HTTP (Hypertext Transfer Protocol) là giao thức truyền tải tài nguyên cho Web theo mô hình Client-Server (hoặc Request-Response). Ví dụ khi bạn truy cập https://roninhub.com/ . Trình duyệt sẽ tạo các HTTP request đến Server lấy các file HTML, Ảnh, Text… hiển thị lên như ảnh bên dưới. HTTP hoạt động thế nào? Khi một Client (thường là trình duyệt) gửi một HTTP request, quá trình giao tiếp giữa Client và Server thường diễn ra qua các bước sau: * Thiết lập kết nối TCP: Client

Tất cả bài viết
logo

HỘ KINH DOANH LẬP VƯƠNG

Giấy chứng nhận đăng ký doanh nghiệp số: 8656162915-001. Cấp ngày 21/02/2024. Nơi cấp: Sở Kế hoạch và Đầu tư TP. Hà Nội

PHƯƠNG THỨC THANH TOÁN

vnpay

LIÊN HỆ

roninengineer88@gmail.com

0362228388

26 ngõ 156 Hồng Mai, Hai Bà Trưng, Hà Nội

THEO DÕI CHÚNG TÔI

Facebook

Youtube

Tiktok

CHÍNH SÁCH

Chính sách bảo mật

Chính sách thanh toán

Đổi trả/Hoàn tiền

Hướng dẫn thanh toán VNPAY

PHƯƠNG THỨC THANH TOÁN

vnpay

Ronin Engineer 2024