Sidekiq - Cấu trúc và một số cơ chế hoạt động
Bài đăng này đã không được cập nhật trong 6 năm

1. Tổng quan về Background Job
Như chúng ta đã biết, mô hình chung của một ứng dụng web thường như sau: Web application nhận request từ người dùng, tiến hành xử lý logic (service, Database, ...) và trả về một response cho người dùng.
Đây là mô hình đơn giản, server xử lý nhanh chóng và phản hồi ngay lập tức kết quả cho người dùng. Tuy nhiên có những tác vụ, request server không xử lý ngay lập tức được, cần thời gian thực thi lâu hơn bình thường, người dùng phải chờ một khoảng thời gian trước khi server phản hồi lại. Những tác vụ như vậy gọi là synchronous task và có thể xử lý bằng background job hay asynchronous job (xử lý bất đồng bộ) trên một luồng hoàn toàn riêng biệt .
Cách xử lý này giúp người dùng tránh phải chờ nhưng vẫn đảm bảo tác vụ được thực thi, không ảnh hưởng đến luồng làm việc đồng bộ của ứng dụng.

2. Khi nào nên sử dụng Background Job?
Background Job nên được sử dụng khi thực hiện:
- Xử lý các tác vụ nặng có liên quan tới hiệu năng, CPU
- Xử lý các tác vụ liên quan nhiều tới I/O
- Batch jobs (send mail, ...), scheduled jobs
- …
3. Sidekiq là gì?
Sidekiq là một full-featured background processing framework cho Ruby. Đơn giản hóa việc tích hợp với bất kỳ ứng dụng Rails và cho hiệu năng cao hơn nhiều so với các giải pháp hiện có khác như Resque hay Delayed Jobs vì Sidekiq xử lý đa luồng và sử dụng Redis thực thi đồng thời nhiều jobs.
4. Cấu trúc
Sidekiq cho phép mở rộng quy mô ứng dụng bằng cách thực hiện tác vụ ở chế độ chạy nền. Do vậy, yêu cầu có 3 phần chính:
Sidekiq client
- Chạy trong bất kỳ Ruby
processnào (thường làpumahoặcpassenger) - Tạo job để xử lý sau và đẩy jobs vào queue qua các lệnh Redis như LPUSH, …
- Có 2 cách tạo job: hai phương thức được sử dụng bên dưới là tương đương nhau, đều tạo một
Hashđại diện cho job,serializeHash đó thànhJSON Stringvà push String đó vào queue trong Redis.
MyWorker.perform_async(1, 2, 3)
Sidekiq::Client.push('class' => MyWorker, 'args' => [1, 2, 3])
- Một lưu ý là các đối số cho
Workerphải là kiểu dữ liệuJSONđơn giản (numbers, strings, boolean, array, hash). Cácobject Rubyphức tạp (Date, Time, ActiveRecord models) sẽ không đượcserializechính xác.
Redis
Tại sao lại nên sử dụng Redis thì mọi người có thể kham thảo thêm một số bài viết sau Tìm hiểu chung về Redis, So sánh Redis, MySQL và MongoDB.
Sidekiqsử dụng Redis để lưu trữ tất cả dữ liệu, các job cần xử lý. Điểm khác biệt quan trọng củaSidekiqvớiDelayed Job.Redischứa tất cả dữ liệu của job cùng vớiruntimevà dữ liệu lịch sử choUI's webcủa Sidekiq.- Theo mặc định, Sidekiq kết nối với Redis tại
localhost: 6379trong môi trườngdevelopment. - Redis thường được dùng để
cachedữ liệu, tuy nhiên việc cache vàstorage joblà khác nhau (cache có thểinvalidatenhưng job thì không), do vậy nên tách rời 2 server Redis cho việc cache và lưu trữ job sidekiq giúp hạn chếtimeoutkhifull memory. (Sidekiq chỉ lưu1000 jobcuối cùng để tránh lưu quá nhiều dẫn tới full memory.)
Chi tiết hơn tại Using Redis.
Sidekiq server
- Là một process
độc lập, pull job từ queue trong Redis và xử lý nó. - Sidekiq boot Rails để job và worker có đầy đủ API Rails, gồm Active Record, có sẵn để sử dụng. Máy chủ sẽ khởi tạo job và thực hiện
performvới các đối số đã cho. - Sử dụng lệnh Redis BRPOP để lấy jobs: khi có job trong queue thì lấy, queue rỗng sẽ đợi đến khi có job thì lấy tiếp.
5. Vòng đời của một job
Các trạng thái của một job và cách chuyển đổi giữa chúng:
- Processed: thực thi thành công và sẽ không có hành động nào nữa.
- Failed: số lần tất cả các job được thực hiện bởi Sidekiq và phát sinh lỗi (default max là 25). Một job sẽ không bao giờ kết thúc trong trạng thái Failed, vì đây là một trạng thái bắc cầu. Các trạng thái cuối cùng chỉ có thể là Processed hoặc Dead.
- Busy: hiện đang thực thi.
- Enqueued: chờ đến lượt trong processing queue (được liệt kê theo thứ tự thời gian, theo hàng đợi).
- Retries: thất bại, nhưng đôi khi sẽ tự động được thực thi lại trong tương lai (được liệt kê theo thứ tự thời gian).
- Scheduled: được cấu hình để chạy ở một thời điểm nào đó trong tương lai (có thể được xử lý khi thời gian xử lý của chúng xuất hiện).
- Dead: không được thực thi lại mà được lưu trữ để có thể thực thi lại bằng cách thủ công tại một thời điểm nào đó trong tương lai gần.
Cần lưu ý khi một job đơn có thể làm tăng cả bộ đếm Processed và Failed nếu nó thất bại một lần hoặc hơn, nhưng success khi thử lại.
6. Một số cơ chế hoạt động
- Đẩy và lấy job từ Redis.
- Xử lý các tín hiệu (signals)
- Xử lý lỗi.
- Xử lý scheduled jobs.
- Về Delayed Extensions.
- Cùng sử dụng với Active Job.
- Deployment
- …
Chi tiết tại Sidekiq Wiki.
7. Best Practices
- Tạo các tham số job nhỏ và đơn giản.
- Các job nên idempotent và transactional:
- Idempotency có nghĩa là job có thể thực hiện một cách an toàn nhiều lần.
- Thiết kế các jobs có thể chạy đồng thời song song một thời điểm.
8. Tham khảo
All rights reserved