- vừa được xem lúc

Kill Sidekiq When It Reaches Memory Threshold

0 0 17

Người đăng: LamDN

Theo Viblo Asia

Như đã nói ở bài viết Sidekiq Memory Problem, nếu như tất cả các giải pháp mà bạn sử dụng không thể giải quyết triệt để được vấn đề memory của Sidekiq thì việc restart lại Sidekiq có thể sẽ là phương án bạn nên thử. Thông thường, nếu sử dụng cloud services, hệ thống của bạn sẽ có cơ chế healthcheck, nó sẽ tự động kiểm tra và restart lại những instance đang gặp vấn đề. Vì vậy, trong bài viết này chúng ta sẽ tập trung vào việc xử lý kill Sidekiq.

Prerequisites

Điều kiện đầu tiên là hệ thống của bạn nên có từ 2 Sidekiq instances trở lên, điều này để tránh gián đoạn trong quá trình sử dụng của người dùng. Tiếp theo, một instance chỉ được kill khi thoả mãn tất cả các điều kiện dưới đây:

  • Lượng memory sử dụng đã vượt quá con số cho phép

  • Còn ít nhất một instance Sidekiq khác khả dụng

  • Không còn remaining jobs

Các bước sẽ được thực hiện theo chu trình này:

image

Implement

Chúng ta cần tạo một middleware với nhiệm vụ kiểm tra trạng thái memory của instance và thực hiện tiến trình kill Sidekiq.

require "sidekiq"
require "sidekiq/api"
require "sidekiq/util" module SidekiqMiddlewares class ProcessKiller include Sidekiq::Util MAX_RSS = 2000 MUTEX = Mutex.new SHUTDOWN_WAIT = 30 KILL_SIGNAL = "SIGKILL" def call worker, _, _ yield return if already_request_shutdown? GC.start(full_mark: true, immediate_sweep: true) return unless over_memory_limit? warn("current RSS #{current_rss}MB is over limit #{MAX_RSS}MB") return warn("no other process available!") unless other_process_available? request_shutdown end private def request_shutdown Thread.new do shutdown if MUTEX.try_lock end end def shutdown quiet_process mark_for_shutdown wait_for_remaining_jobs stop_process force_kill_process! end def quiet_process warn "sending quiet" sidekiq_process.quiet! sleep(5) end def mark_for_shutdown redis_key = request_shutdown_key(identity) redis{|conn| conn.set(redis_key, true, ttl: 1.hour)} end def wait_for_remaining_jobs warn "waiting for remaining jobs..." sleep(1) until remaining_jobs_finished? warn "all remaining jobs finished" end def stop_process warn "stopping..." sidekiq_process.stop! end def force_kill_process! sleep(SHUTDOWN_WAIT) warn "sending #{KILL_SIGNAL}" ::Process.kill(KILL_SIGNAL, ::Process.pid) end def already_request_shutdown? request_shutdown?(sidekiq_process) end def over_memory_limit? current_rss > MAX_RSS end def other_process_available? Sidekiq::ProcessSet.new.any? do |process| !current_process?(process) && !request_shutdown?(process) end end def remaining_jobs_finished? sidekiq_process.stopping? && sidekiq_process["busy"] == 0 end def current_rss OS.rss_bytes / 1.megabytes end def sidekiq_process find_current_process || raise("No process with identity #{identity} found") end def find_current_process Sidekiq::ProcessSet.new.find{|process| current_process?(process)} end def request_shutdown? process redis{|conn| conn.get(request_shutdown_key(process.identity))} end def long_job_processing? worker, job long_worker?(job) && !current_job?(worker, job) end def long_worker? job job.dig("payload", "class").in?(LONG_WORKERS) end def current_job? worker, job job.dig("payload", "jid").eql?(worker.jid) end def current_process? process (process.is_a?(String) ? process : process.identity).eql?(identity) end def request_shutdown_key identity "shutting_down_#{identity}" end def warn message Sidekiq.logger.warn("#{identity}: #{message}") end end
end

Sau đó bạn cần đăng ký middleware này với Sidekiq:

Sidekiq.configure_server do |config| config.server_middleware do |chain| chain.add(SidekiqMiddlewares::ProcessKiller) end
end

Với cách làm trên, mỗi khi kết thúc một job, quá trình kiểm tra Sidekiq memory sẽ được thực hiện. Bạn cũng có thể tạo một cron job kiểm tra định kỳ (vài phút một lần) thay vì sử dụng middleware. Cách làm đó có ưu điểm là không can thiệp vào tiến trình chạy job, tuy nhiên quá trình xử lý sẽ phức tạp hơn vì bạn cần lấy được thông tin memory của các instances Sidekiq khi đang ở server chạy cron job.

Conclusion

Kill Sidekiq process là giải pháp cuối cùng để giải quyết vấn đề liên quan đến memory của Sidekiq. Trên đây là một ví dụ bạn có thể tham khảo, logic xử lý có thể sẽ thay đổi tuỳ thuộc vào mục đích cụ thể của bạn.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tạo batch background jobs với Sidekiq

Khi chúng ta muốn tạo nhiều background jobs chạy song song và muốn biết lúc nào tất cả các jobs đó đã complete hay chưa, vậy chúng ta phải làm thế nào. Installation. gem "sidekiq-batch". .

0 0 53

- vừa được xem lúc

Sidekiq trick: Thực thi job trên 1 host cố định trong cluster

Sidekiq. Các bạn code ruby chắc hẳn không hề xa lại với sidekiq. Đây là một gem thường được dùng cho việc xử lý background jobs trong Rails. Sidekiq gồm 3 phần chính là Sidekiq Client, Sidekiq Server và Redis.

0 0 92

- vừa được xem lúc

Tìm hiểu Active Job trong ruby on rails

NỘI DUNG. 1. Activejob là gì . .

0 0 160

- vừa được xem lúc

Sử dụng nhiều sidekiq trên cùng một ứng dụng Rails

Các luồng xử lý của sidekiq được giả định kết nối với 1 redis duy nhất. Bởi vậy khi kết nối ứng dụng đến nhiều redis, số lượng sidekiq cần tương ứng với số lượng redis.

0 0 29

- vừa được xem lúc

Dùng Sidekiq vào tính năng xếp hạng 1 dãy các dữ liệu

Dạo gần đây mình có khởi động lại project cá nhân để luyện tập tay nghề(Hàng dùng view mặc định của Ruby, không dùng framework JS tử tế cho frontend và dùng Bootstrap 5.3 làm giao diện thôi.

0 0 23

- vừa được xem lúc

Sidekiq Memory Problem

Nếu đã từng sử dụng Sidekiq trong ứng dụng Rails, chắc hẳn bạn đã nghe hoặc gặp phải vấn đề liên quan đến memory. Dễ thấy nhất là việc memory mà Sidekiq chiếm dụng ngày một tăng lên và không có dấu hi

0 0 16