Tìm hiểu Sidekiq gem
Tìm hiểu Sidekiq gem I. Giới thiệu Sidekiq Sidekiq là framework để thực hiện các công việc chạy ngầm, nó là giải pháp đơn giản và hiệu quả nhất tích hợp với các ứng dụng Rails cần yêu cầu cao về performance. Sidekiq sử dụng các luồng _ thread_ để thực hiện nhiều công việc cùng lúc trong ...
Tìm hiểu Sidekiq gem
I. Giới thiệu Sidekiq
Sidekiq là framework để thực hiện các công việc chạy ngầm, nó là giải pháp đơn giản và hiệu quả nhất tích hợp với các ứng dụng Rails cần yêu cầu cao về performance.
Sidekiq sử dụng các luồng _ thread_ để thực hiện nhiều công việc cùng lúc trong cùng một tiến trình xử lý. Nó không yêu cầu về Rails nhưng có thể tích hợp chặt chẽ với Rails để xử lý chạy ngầm các tiến trình nặng nề một cách đơn giản.
Resque cũng là một nền tảng dùng để chạy ngầm các job. Tuy nhiên, Sidekiq có thể tương thích hoàn toàn với Resque, nó sử dụng cùng định dạng message. Ta có thể sử dụng cả Sidekiq và Resque chạy đồng thời cùng thời điểm và sử dụng máy client chạy Resque để thêm các job vào Redis và được xử lý bởi Sidekiq
Ta có bảng thống kê về tính hiệu quả của Sidekiq
Version | Latency | Garbage created for 10,000 jobs | Time to process 100,000 jobs | Throughput |
---|---|---|---|---|
Sidekiq 4.0.0 | 10ms | 151MB | 22 sec | 4500 jobs/sec |
Sidekiq 3.5.1 | 22ms | 1257MB | 125 sec | 800 jobs/sec |
Resque 1.25.2 | 420 sec | 240 jobs/sec | ||
DelayedJob 4.1.1 | 465 sec | 215 jobs/sec |
ta có thể thấy Sidekiq xử lý các job chạy ngầm rất nhanh và hiệu quả
II. Sử dụng Sidekiq
1. Yêu cầu
-
Ruby:
Ruby 2.2, 2.1 và 2.0 JRuby 9k Ruby 1.9 không được hỗ trợ
-
Rails:
Các phiên bản Rails từ 3.2 trở đi
-
Redis:
Redis từ 2.8 trở lên, Bản 3.0.3 là tối ưu cho việc xử lý hàng nghìn thread
2. Cài đặt
Ta thêm Sidekiq vào trong Gemfile
gem 'sidekiq'
chạy bundle exec sidekiq để cài đặt
3. Cách dùng
Thêm một Worker trong app/workers để xử lý job không đồng bộ
class HardWorker include Sidekiq::Worker def perform(name, count) # thực hiện công việc end end
Tạo 1 job:
Có vài cách tạo job để chạy ngầm:
HardWorker.perform_async('bob', 5)
hay
Sidekiq::Client.push('class' => MyWorker, 'args' => ['bob', 5])
Ngoài ra, ta cũng có thể hẹn giờ để 1 job được thực hiện
HardWorker.perform_in(5.minutes, 'bob', 5)
Hoặc tạo job thông qua hàm delay
User.delay.do_some_stuff(current_user.id, 20)
4. Cơ chế xử lý
Tạo Job
Thông qua gọi các hàm tạo Job, sẽ sinh ra 1 Hash tương ứng với job, chuyển đổi Hash thành JSON String và đẩy String đấy vào hàng đợi của Redis.
Các tham số truyền vào của job chỉ đơn thuần là các kiểu dữ liệu JSON đơn giản (numbers, strings, boolean, array, hash)
Các đối tượng phức tạp hơn (như Date, Time, các model Active Record) sẽ không được chuyển đổi một cách thích hợp
Redis
Redis cung cấp nơi chứa dữ liệu cho Sidekiq. Nó giữ tất cả dữ liệu job trong thời gian thực và lịch sử của dữ liệu trong Sidekiq's Web
Server
Mỗi server Sidekiq lấy các job từ hàng đợi trong Redis và thực thi chúng. Giống như các tiến trình của trang web, Sidekiq tải lại framework Rails cho các job và workers có đầy đủ các Rails API bao gồm Active Record để thực hiện. Server sẽ khởi tạo các worker và truyền vào các tham số. Mọi thứ sẽ được thực hiện dựa theo mục đích của job.
III. Một vài cách tối ưu Sidekiq
1. Truyền các tham số đơn giản
Ví dụ khi tạo 1 job
quote = Quote.find(quote_id) SomeWorker.perform_async(quote)
Để thực hiện chạy ngầm, Sidekiq sẽ phải chuyển đổi đối tượng Quote cho Redis. Chuyện gì sẽ xảy ra nếu hàng đợi trong Redis được backup và đối tượng quote thay đổi cùng lúc, Sidekiq sẽ không lưu trạng thái của nó. Vì vậy nên truyền các tham số đơn giản
SomeWorker.perform_async(quote_id)
Các tham số truyền vào perform_async phải là các kiểu dữ liệu JSON đơn giản: string, integer, boolean, null, array và hash. API của Sidekiq client sẽ sử dụng JSON.dump để gửi dữ liệu đến Redis. Sidekiq server đẩy dữ liệu JSON từ Redis và sử dụng JSON.load để chuyển dử liệu về kiểu Ruby truyền vào hàm thực thi.
Không truyền kiểu symbol hay các đối tượng Ruby phức tạp (như Date hay Time), nó sẽ khiến quá trình dump/load thực hiện thiếu chính xác.
2. Tạo job idempotent and transactional
Idempotency nghĩa là job có thể thực hiện nhiều lần. Ví dụ, cố gắng thực thi khi gặp lỗi, job có thể thực hiện một nửa, bắn ra lỗi, sau đó thực hiện lại, lặp đi lặp lại tới khi thực hiện thành công. Điều này có thể thấy ở các job thực hiện giao dịch cho thẻ tín dụng rồi gửi email đến người dùng, có cho phép họ biết được tiền của họ đã bị hoàn lại.
def perform(card_charge_id) charge = CardCharge.find(card_charge_id) charge.void_transaction Emailer.charge_refunded(charge).deliver end
Điều gì sẽ xảy ra khi email bị lỗi, khi đó hàm transaction phải bổ sung trường hợp khi tiền bị gửi trả lại. Ta có thể sử dụng transaction của database để đảm bảo dữ liệu thay đổi được khôi phục lại nếu có một lỗi hay một đoạn code trả về lỗi nào đó. Tuy nhiên Sidekiq chỉ thực thi job đúng một lần.
3. Đảm bảo liên tục
Sidekiq được thiết kế để xử lý song song, để có thể chạy nhiều job cùng một lúc.
Ta có thể sử dụng một công cụ kết nối giới hạn tổng số kết nối đến một server bị giới hạn tài nguyên khi các tiến trình Sidekiq bị tắc nghẽn.
Sidekiq không cung cấp các đặc tính để xử lý cho job thiếu tính liên tục.
IV. Tổng kết
Sidekiq là một công cụ rất hữu ích để cải thiện performance cho Rails, giúp giảm bớt tác vụ mà Rails server phải xử lý, tăng tốc hệ thống.
Ngoài ra, Sidekiq cũng có các phiên bản ứng với các mục đích khác nhau như Sidekiq Pro, Sidekiq Enterprise, cung cấp nhiều đặc tính tốt hơn.
Nguồn tài liệu tham khảo
- gem Sidekiq
- Railscasts.com