Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Tối Ưu Cụm Sidekiq: Script Mới Cho Triển Khai Mượt Mà

Tại Honeybadger, chúng ta phụ thuộc nhiều vào Sidekiq trong pipeline xử lý. Gần như mọi thứ chúng ta làm đều chạy qua một queue tại một thời điểm nào đó. Kết quả là, tôi muốn đảm bảo chúng ta đang chạy Sidekiq tốt. Với chuyển động gần đây sang EC2, chúng ta đã thay đổi từ một tập hợp server long-lived ổn định thành một tập hợp instance luôn thay đổi chạy các job của chúng ta. Điều này nhắc tôi xem lại cách chúng ta start Sidekiq tại boot time, vì đó bây giờ quan trọng hơn nhiều so với trước đây.

Trong quá khứ, chúng ta phụ thuộc vào god để spin up tất cả worker processes, vì chúng ta muốn nó monitor chúng và terminate những process dùng quá nhiều memory. Cấu hình god của chúng ta được hand-tuned cho các server chúng ta đã deploy chạy những worker đó. Thật không may, tôi thấy rằng khi boot cấu hình god cũ trên các instance mới dùng systemd, chúng ta đôi khi nhận được nhiều worker chạy hơn cấu hình chỉ định. Điều này dẫn đến memory pressure trên các instance, tin xấu. Sau khi chỉnh sửa một thời gian, và nhận ra chúng ta không dùng nhiều chức năng của nó, tôi quyết định đã đến lúc dừng dùng god để quản lý processes.

Một lệnh đơn giản để chạy nhiều tiến trình Sidekiq

Điều tôi thực sự muốn là một script tôi có thể chạy như một systemd service sẽ spawn một tiến trình Sidekiq mỗi core và sẽ restart các tiến trình tiêu thụ quá nhiều memory. Script cần có thể làm việc với các EC2 instance kích thước khác nhau, vì số core và lượng RAM có thể thay đổi khi tôi thử các instance size khác nhau để xem gì hoạt động tốt nhất cho workload của chúng ta. Vì tôi không tìm thấy script nào làm chính xác điều đó, tôi đã viết một:

Tất nhiên, có chút code mượn trong script đó. :) Code trong phương thức process_count có thể đến từ Stack Overflow (tôi đã dùng nó nhiều năm trong cấu hình unicorn của chúng ta) và phương thức fork_child về cơ bản là bin sidekiq từ gem sidekiq.

Script này spawn một số tiến trình con dựa trên số CPU core hiện có, với mỗi tiến trình con giống hệt như nếu bạn đã chạy lệnh sidekiq trực tiếp. Kết quả là, bất kỳ tùy chọn dòng lệnh nào bạn truyền cho script này sẽ được truyền cho (và parsed bởi) mã CLI Sidekiq. Nói cách khác, bạn có thể truyền bất kỳ tùy chọn nào cho script này mà bạn có thể truyền cho sidekiq khi chạy trực tiếp, dù một số tùy chọn (như option pid file) không có ý nghĩa để dùng. Một thread cũng được spawn để định kỳ kiểm tra memory usage của mỗi tiến trình con. Nếu bất kỳ tiến trình con nào vượt quá ngưỡng sử dụng, nó bị kill và một tiến trình mới được spawn để thay thế.

Làm việc với cụm

Mặc dù số tiến trình mặc định là số core (giả sử bạn dedicate một instance để chạy tiến trình Sidekiq), bạn có thể ghi đè bằng cách set biến môi trường SK_PROCESS_COUNT trước khi chạy script. Tương tự, ngưỡng memory được set như phần trăm tổng RAM của instance (để dư một chút RAM bằng cách cộng một vào giá trị process_count ở dòng 58), nhưng bạn có thể set bất kỳ phần trăm nào bạn muốn với biến môi trường SK_MEMORY_PCT_LIMIT. Chúng ta dùng hai biến này để hạn chế số tiến trình Sidekiq và memory usage trên các instance chạy Rails app powering UI của chúng ta.

Là một bonus thêm, script này bắt các signal thường dùng để quản lý tiến trình Sidekiq và truyền những signal đó cho các tiến trình con. Điều này cho phép chúng ta dùng pkill -f -USR1 skcluster để các tiến trình con ngừng chấp nhận việc mới (đây là task sớm trong script deploy của chúng ta), và chúng ta có thể dùng pkill -f skcluster để terminate mọi thứ.

Cấu hình systemd

Định nghĩa service systemd đơn giản:

Vì chúng ta dùng pgbouncer trên mọi instance để proxy kết nối đến postgres, chúng ta đảm bảo service pgbouncer đang chạy trước khi các tiến trình sidekiq được boot. Nếu chúng ta chạy redis trên cùng instance, chúng ta cũng sẽ thêm redis-server.service vào dòng Requires và After. EnvironmentFile dùng prefix - cho tên file để bảo systemd rằng ổn nếu file không tồn tại. Điều này cho phép chúng ta bỏ qua file đó khi muốn dùng process count và memory limit mặc định. Chúng ta dùng option --require để cho Sidekiq biết đâu để load cấu hình và initializers của Rails app của chúng ta. Vì script skcluster bắt SIGTERM, chúng ta có thể dùng systemctl restart skcluster.service để restart tất cả worker (đây là task muộn trong script deploy của chúng ta).

Chúng ta đã dùng script này một thời gian, và nó hoạt động như một champion. Chúng ta không còn vấn đề quá nhiều tiến trình được spawn tại boot, không còn cảnh báo memory usage từ monitoring, và chúng ta có thể launch bất kỳ loại EC2 instance nào chúng ta muốn. Hassle-free ops là loại ops tôi thích nhất. :)