2012-08-04 10 views
13

Tôi muốn triển khai redis nền tảng lưu trữ phiên, tôi đặt dữ liệu phiên thành redis. Nhưng tôi không biết cách xử lý session-expire.I có thể lặp lại tất cả các khóa redis (sessionid) và loại bỏ dữ liệu lastaccess và maxidle, vì vậy tôi cần tải tất cả các khóa vào máy khách, và có thể là các khóa phiên 1000m và có thể dẫn dắt hiệu suất I/O rất lớn.
Tôi muốn cho phép redis quản lý hết hạn, nhưng không có người nghe hoặc gọi lại khi khóa hết hạn, vì vậy không thể bắt chước HttpSessionListener. bất kỳ lời khuyên nào?làm thế nào để xử lý phiên hết hạn redis cơ sở?

+0

Không có trong Redis, nhưng bạn có thể muốn xem cách nó được thực hiện trong Tarantool: https://github.com/mailru/tntlua/blob/master/expirationd.lua Tóm lại, trong Tarantool bạn có thể chạy các kịch bản Lua của riêng bạn trong cơ sở dữ liệu và đặt chính sách hết hạn của riêng bạn trong đó. Không có daemon bên ngoài là cần thiết. – Kostja

Trả lời

33

Vì vậy, bạn cần ứng dụng của mình được thông báo khi phiên hết hạn trong Redis.

Trong khi Redis không hỗ trợ tính năng này, có một số thủ thuật bạn có thể sử dụng để triển khai.

Cập nhật: Từ phiên bản 2.8.0, Redis không hỗ trợ này http://redis.io/topics/notifications

Thứ nhất, mọi người đang nghĩ về nó: này vẫn đang được thảo luận, nhưng nó có thể được thêm vào một phiên bản tương lai của Redis. Xem các vấn đề sau:

Bây giờ, đây là một số giải pháp mà bạn có thể sử dụng với các phiên bản Redis hiện hành.

Giải pháp 1: vá Redis

Trên thực tế, thêm một thông báo đơn giản khi Redis thực hiện hết hạn chủ chốt không phải là khó. Nó có thể được thực hiện bằng cách thêm 10 dòng vào tệp db.c của mã nguồn Redis. Dưới đây là một ví dụ:

https://gist.github.com/3258233

này ngắn vá viết một chìa khóa để danh sách #expired nếu phím đã hết hạn và bắt đầu bằng ký tự '@' (lựa chọn tùy ý). Nó có thể dễ dàng được điều chỉnh theo nhu cầu của bạn. Sau đó, nó sẽ là tầm thường để sử dụng lệnh EXPIRE hoặc SETEX để đặt thời gian hết hạn cho đối tượng phiên của bạn và viết một daemon nhỏ lặp trên BRPOP để khử từ danh sách "#expired" và truyền thông báo trong ứng dụng.

Một điểm quan trọng là hiểu cơ chế hết hạn hoạt động như thế nào trong Redis. Trên thực tế có hai đường dẫn khác nhau hết hạn, cả hai hoạt động cùng một lúc:

  • Cơ chế lười (thụ động). Hết hạn có thể xảy ra mỗi khi một khóa được truy cập.

  • Cơ chế hoạt động. Một công việc nội bộ thường xuyên (ngẫu nhiên) lấy mẫu một số khóa với tập hợp hết hạn, cố gắng tìm ra những khóa hết hạn.

Lưu ý rằng bản vá ở trên hoạt động tốt với cả hai đường dẫn.

Hậu quả là thời gian hết hạn của Redis không chính xác.Nếu tất cả các khóa đã hết hạn, nhưng chỉ có một khóa sắp hết hạn và không được truy cập, công việc hết hạn hoạt động có thể mất vài phút để tìm khóa và đã hết hạn. Nếu bạn cần một số chính xác trong thông báo, đây không phải là cách để đi.

Giải pháp 2: mô phỏng hết hạn với zsets

Ý tưởng ở đây là để không phụ thuộc vào cơ chế hết hạn key Redis, nhưng mô phỏng nó bằng cách sử dụng một chỉ số bổ sung cộng với một daemon bỏ phiếu. Nó có thể hoạt động với phiên bản Redis 2.6 chưa sửa đổi.

Mỗi lần một phiên được thêm vào Redis, bạn có thể chạy:

MULTI 
SET <session id> <session content> 
ZADD to_be_expired <current timestamp + session timeout> <session id> 
EXEC 

Tập sắp xếp to_be_expired chỉ là một cách hiệu quả để truy cập vào các phím đầu tiên mà nên hết hạn. Một daemon có thể thăm dò ý kiến ​​trên to_be_expired sử dụng Lua server-side script sau:

local res = redis.call('ZRANGEBYSCORE',KEYS[1], 0, ARGV[1], 'LIMIT', 0, 10) 
if #res > 0 then 
    redis.call('ZREMRANGEBYRANK', KEYS[1], 0, #res-1) 
    return res 
else 
    return false 
end 

Lệnh để khởi động kịch bản sẽ là:

EVAL <script> 1 to_be_expired <current timestamp> 

Các daemon sẽ nhận được tối đa 10 mục. Đối với mỗi người trong số họ, nó phải sử dụng lệnh DEL để loại bỏ các phiên, và thông báo cho ứng dụng. Nếu một mục đã được xử lý thực sự (tức là sự trở lại của kịch bản lệnh Lua không rỗng), thì daemon sẽ lặp lại ngay lập tức, nếu không một trạng thái chờ đợi thứ hai có thể được giới thiệu. Nhờ kịch bản Lua, có thể khởi chạy một vài daemon thăm dò song song (tập lệnh đảm bảo rằng một phiên nhất định sẽ chỉ được xử lý một lần, vì các khóa được xóa khỏi to_be_expired bởi chính kịch bản Lua).

Giải pháp 3: sử dụng một phân phối hẹn giờ bên ngoài

Một giải pháp khác là dựa vào một bộ đếm thời gian phân phối bên ngoài. beanstalk lightweight queuing system là một khả năng tốt cho

Mỗi lần phiên được thêm vào hệ thống, ứng dụng sẽ gửi ID phiên tới hàng đợi beanstalk với độ trễ tương ứng với thời gian chờ của phiên. Một daemon đang nghe hàng đợi. Khi nó có thể dequeue một mục, nó có nghĩa là một phiên đã hết hạn. Nó chỉ cần làm sạch phiên trong Redis, và thông báo cho ứng dụng.

+0

Câu trả lời tuyệt vời - cảm ơn rất nhiều! Bạn có thể làm rõ câu này mặc dù: "daemon nên lặp lại ngay lập tức, nếu không một trạng thái chờ đợi 1 giây có thể được giới thiệu". Vòng lặp có ý nghĩa gì trong ngữ cảnh này - và tại sao/1 giây chờ đợi này được giới thiệu ở đâu? –

+0

Daemons là chương trình thường trú mà đôi khi tỉnh táo để thực hiện một số hoạt động trong hệ thống. Vì chúng liên tục chạy, hầu hết mã được bao bọc trong một vòng lặp chính. Bây giờ một daemon cũng cần một trạng thái chờ, để tránh dùng CPU 100% trong khi lặp lại. Không có lệnh chặn nào liên quan đến một tập hợp zset với Redis (không giống như BLPOP/BRPOP cho danh sách), do đó, nó phải được mô phỏng bằng cách bỏ phiếu và ngủ nếu không có gì được trả về. –

+2

Điều này đã được thực hiện bằng redis. Những vấn đề đó đã bị đóng. Sẽ rất tuyệt nếu ai đó cập nhật câu trả lời này. –