Bởi Andrei Chernikov
Redis là một lưới trong bộ nhớ phổ biến được sử dụng để liên lạc giữa các quá trình và lưu trữ dữ liệu. Bạn có thể đã nghe nói rằng nó cho phép bạn chạy các tập lệnh Lua, nhưng bạn vẫn không chắc tại sao. Nếu điều này có vẻ giống bạn, hãy đọc tiếp.
Điều kiện tiên quyết
Bạn nên cài đặt Redis trên hệ thống của mình để làm theo hướng dẫn này. Có thể hữu ích nếu kiểm tra tham chiếu lệnh Redis trong khi đọc.
Tại sao tôi cần Lua Script?
Tóm lại:đạt được hiệu suất. Hầu hết các tác vụ bạn thực hiện trong Redis đều bao gồm nhiều bước. Thay vì thực hiện các bước này bằng ngôn ngữ ứng dụng của bạn, bạn có thể thực hiện nó trong Redis bằng Lua.
- Điều này có thể mang lại hiệu suất tốt hơn.
- Ngoài ra, tất cả các bước trong tập lệnh đều được thực thi theo cách nguyên tử. Không có lệnh Redis nào khác có thể chạy trong khi tập lệnh đang thực thi.
Ví dụ:tôi sử dụng tập lệnh Lua để thay đổi chuỗi JSON được lưu trữ trong Redis. Tôi mô tả chi tiết điều này ở gần cuối bài viết này.
Nhưng tôi không biết Lua nào cả
Một người không biết lua
Đừng lo lắng, Lua không khó hiểu lắm đâu. Nếu bạn biết bất kỳ ngôn ngữ nào thuộc họ C, bạn sẽ thấy ổn với Lua. Ngoài ra, tôi đang cung cấp các ví dụ hoạt động trong bài viết này.
Cho tôi xem một ví dụ
Hãy bắt đầu bằng cách chạy tập lệnh qua redis-cli . Bắt đầu với:
redis-cli
Bây giờ hãy chạy lệnh sau:
eval “redis.call(‘set’, KEYS[1], ARGV[1])” 1 key:name value
EVAL command là lệnh yêu cầu Redis chạy tập lệnh tiếp theo. ”redis.call(‘set’, KEYS[1], ARGV[1])” string là tập lệnh của chúng tôi có chức năng giống với set của Redis lệnh. Ba tham số theo văn bản script:
- Số lượng khóa được cung cấp
- Tên khóa
- Đối số đầu tiên
Đối số tập lệnh được chia thành hai nhóm:KEYS và ARGV .
Chúng tôi chỉ định số lượng khóa mà tập lệnh yêu cầu với số ngay sau nó. Trong ví dụ của chúng tôi, đó là 1 . Ngay sau số này, chúng ta cần cung cấp các key này lần lượt. Chúng có thể truy cập được dưới dạng KEYS bảng trong tập lệnh. Trong trường hợp của chúng tôi, nó chứa một giá trị duy nhất key:name tại chỉ mục 1 .
Lưu ý rằng các bảng được lập chỉ mục Lua bắt đầu bằng chỉ mục 1, không 0 .
Chúng tôi có thể cung cấp số lượng đối số bất kỳ sau các khóa, sẽ có sẵn trong Lua dưới dạng ARGV cái bàn. Trong ví dụ này, chúng tôi cung cấp một ARGV -argument:chuỗi value . Như bạn đã đoán, lệnh trên đặt khóa key:name để có giá trị value .
Việc cung cấp các khóa mà tập lệnh sử dụng làm KEYS được coi là một phương pháp hay và tất cả các đối số khác dưới dạng ARGV . Vì vậy bạn không nên chỉ định KEYS bằng 0 rồi cung cấp tất cả các khóa trong ARGV bảng.
Bây giờ hãy kiểm tra xem tập lệnh đã hoàn thành thành công chưa. Chúng ta sẽ thực hiện việc này bằng cách chạy một tập lệnh khác lấy khóa từ Redis:
eval “return redis.call('get', KEYS[1])” 1 key:name
Đầu ra phải là ”value” , có nghĩa là tập lệnh trước đã đặt thành công khóa “key:name” .
Bạn có thể giải thích kịch bản được không?
Doge sau khi xem đoạn script trên
Tập lệnh đầu tiên của chúng tôi bao gồm một câu lệnh duy nhất:redis.call chức năng:
redis.call(‘set’, KEYS[1], ARGV[1])
Vớiredis.call bạn có thể thực thi bất kỳ lệnh Redis nào. Đối số đầu tiên là tên của lệnh này, theo sau là các tham số của nó. Trong trường hợp set lệnh, các đối số này là khóa và giá trị . Tất cả các lệnh Redis đều được hỗ trợ. Theo tài liệu:
Redis sử dụng cùng trình thông dịch Lua để chạy tất cả các lệnh
Tập lệnh thứ hai của chúng tôi thực hiện nhiều việc hơn là chỉ chạy một lệnh duy nhất — nó còn trả về một giá trị:
eval “return redis.call(‘get’, KEYS[1])” 1 key:name
Mọi thứ được tập lệnh trả về sẽ được gửi đến quá trình gọi. Trong trường hợp của chúng tôi, quá trình này là redis-cli và bạn sẽ thấy kết quả trong cửa sổ terminal của mình.
Cái gì đó phức tạp hơn?
Người dự định xây dựng tập lệnh Redis phức tạp
Tôi đã từng sử dụng tập lệnh Lua để trả về các phần tử từ bản đồ băm theo một thứ tự cụ thể. Bản thân thứ tự đã được chỉ định bởi các khóa băm được lưu trữ trong một tập hợp được sắp xếp.
Trước tiên, hãy thiết lập dữ liệu của chúng ta bằng cách chạy các lệnh này trong redis-cli :
hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6
zadd order 1 key:3 2 key:1 3 key:2
Các lệnh này tạo bản đồ băm tại khóa hkeys và một tập hợp được sắp xếp tại khóa order chứa các khóa được chọn từ hkeys theo một thứ tự cụ thể.
Bạn có thể muốn kiểm tra hmset và zadd tham khảo lệnh để biết chi tiết.
Hãy chạy tập lệnh sau:
eval “local order = redis.call(‘zrange’, KEYS[1], 0, -1); return redis.call(‘hmget’,KEYS[2],unpack(order));” 2 order hkeys
Bạn sẽ thấy kết quả sau:
“value:3”
“value:1”
“value:2”
Điều đó có nghĩa là chúng ta đã nhận được giá trị của các khóa mà chúng ta muốn và theo đúng thứ tự.
Tôi có phải chỉ định toàn bộ văn bản tập lệnh để chạy nó không?
Không! Redis cho phép bạn tải trước tập lệnh vào bộ nhớ bằng TẢI SCRIPT lệnh:
script load “return redis.call(‘get’, KEYS[1])”
Bạn sẽ thấy kết quả như thế này:
“4e6d8fc8bb01276962cce5371fa795a7763657ae”
Đây là hàm băm duy nhất của tập lệnh mà bạn cần cung cấp cho EVALSHA lệnh chạy tập lệnh:
evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name
Lưu ý:bạn nên sử dụng thực tế SHA1 băm được trả về bởi TẢI TẬP BẢN lệnh, hàm băm ở trên chỉ là một ví dụ.
Bạn đã đề cập gì về việc thay đổi JSON?
Đôi khi mọi người lưu trữ các đối tượng JSON trong Redis. Ý tưởng hay hay không lại là chuyện khác nhưng trên thực tế việc này xảy ra rất nhiều.
Nếu bạn phải thay đổi khóa trong đối tượng JSON này, bạn cần lấy nó từ Redis, phân tích cú pháp, thay đổi khóa, sau đó tuần tự hóa và đặt lại thành Redis. Có một số vấn đề với cách tiếp cận này:
- Đồng thời. Một quy trình khác có thể thay đổi JSON này giữa các hoạt động get và set của chúng tôi. Trong trường hợp này, thay đổi sẽ bị mất.
- Hiệu suất. Nếu bạn thực hiện những thay đổi này đủ thường xuyên và nếu đối tượng khá lớn thì điều này có thể trở thành nút thắt cổ chai cho ứng dụng của bạn. Bạn có thể đạt được hiệu suất nào đó bằng cách triển khai logic này trong Lua.
Hãy thêm chuỗi JSON thử nghiệm vào Redis dưới khóa obj :
set obj ‘{“a”:”foo”,”b”:”bar”}’
Bây giờ hãy chạy tập lệnh của chúng ta:
EVAL ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’ 1 obj b bar2
Bây giờ chúng ta sẽ có đối tượng sau dưới khóa obj :
{“a”:”foo”,”b”:”bar2"}
Thay vào đó, bạn có thể tải tập lệnh này bằng SCRIPT LOAD lệnh:
SCRIPT LOAD ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’
và sau đó chạy nó như thế này:
EVALSHA <your_script_sha> 1 obj b bar2
Một số lưu ý:
- Số
..là toán tử nối chuỗi trong Lua. - Chúng tôi sử dụng mẫu RegEx để khớp khóa và thay thế giá trị của nó. Nếu bạn không hiểu Biểu thức chính quy này, bạn có thể xem hướng dẫn gần đây của tôi.
- Một điểm khác biệt của phiên bản Lua RegEx so với hầu hết các phiên bản khác là chúng tôi sử dụng
%vừa là dấu tham chiếu ngược vừa là ký tự thoát cho các ký hiệu đặc biệt RegEx. - Chúng ta vẫn thoát khỏi
”với\chứ không phải%bởi vì chúng tôi thoát khỏi dấu phân cách chuỗi Lua, không phải ký hiệu đặc biệt RegEx.
Tôi có nên luôn sử dụng tập lệnh Lua không?
Không. Tôi khuyên bạn chỉ nên sử dụng chúng khi bạn có thể chứng minh rằng nó mang lại hiệu suất tốt hơn. Luôn chạy điểm chuẩn trước.
Nếu tất cả những gì bạn muốn là tính nguyên tử thì thay vào đó bạn nên kiểm tra các giao dịch Redis.
Ngoài ra, kịch bản của bạn không nên quá dài. Hãy nhớ rằng trong khi tập lệnh đang chạy, mọi thứ khác đang chờ nó kết thúc. Nếu tập lệnh của bạn mất khá nhiều thời gian, nó có thể gây ra tắc nghẽn thay vì cải thiện hiệu suất. Tập lệnh dừng sau khi hết thời gian chờ (5 giây theo mặc định).
Tập lệnh Redis không nên mất quá nhiều thời gian
Lời cuối cùng
Để biết thêm thông tin về Lua, hãy kiểm tra lua.org.
Bạn có thể kiểm tra thư viện node.js của tôi trên GitHub để biết một số ví dụ về tập lệnh Lua (xem src/lua thư mục). Bạn cũng có thể sử dụng thư viện này trong node.js để thay đổi các đối tượng JSON mà không cần tự viết bất kỳ tập lệnh Lua nào.
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Cảm ơn bạn đã đọc bài viết này. Các câu hỏi và ý kiến được đánh giá cao. Bạn cũng có thể theo dõi tôi trên Twitter .
Học cách viết mã miễn phí. Chương trình giảng dạy mã nguồn mở của freeCodeCamp đã giúp hơn 40.000 người có được việc làm với tư cách là nhà phát triển. Bắt đầu