2011-11-16 31 views
8

Tôi đã đọc rất nhiều tài liệu trên web về an toàn và hiệu suất của chuỗi trong các phiên bản ruby ​​và đường ray khác nhau và tôi nghĩ rằng tôi hiểu những điều đó khá tốt vào thời điểm này.Làm thế nào để triển khai một ứng dụng Rails không đồng bộ theo chủ đề?

Điều gì dường như bị bỏ sót kỳ lạ từ các cuộc thảo luận là làm thế nào để triển khai ứng dụng Rails không đồng bộ. Khi nói về chủ đề và đồng bộ trong một ứng dụng, có hai điều mọi người muốn tối ưu hóa:

  1. sử dụng tất cả các lõi CPU với việc sử dụng tối thiểu RAM
  2. việc có thể để phục vụ các yêu cầu mới trong khi yêu cầu trước đó đang chờ đợi trên IO

Điểm 1 là nơi mọi người nhận được (đúng) vui mừng về JRuby. Đối với câu hỏi này, tôi chỉ cố gắng để tối ưu hóa điểm 2.

nói đây là bộ điều khiển chỉ trong ứng dụng của tôi:

TheController < ActionController::Base 
    def fast 
    render :text => "hello" 
    end 

    def slow 
    render :text => User.count.to_s 
    end 
end 

fast không có IO và có thể phục vụ hàng trăm hoặc hàng ngàn yêu cầu mỗi giây, và slow phải gửi yêu cầu qua mạng, chờ công việc được thực hiện, sau đó nhận câu trả lời qua mạng và do đó chậm hơn nhiều so với fast.

Vì vậy, triển khai lý tưởng sẽ cho phép hàng trăm yêu cầu đến fast được hoàn thành trong khi yêu cầu slow đang chờ IO.

Điều gì dường như bị thiếu trong các cuộc thảo luận trên web là lớp ngăn xếp nào chịu trách nhiệm bật đồng thời này. mỏng có cờ --threaded, sẽ "Gọi ứng dụng Rack trong chủ đề [thử nghiệm]" - điều đó có bắt đầu một chuỗi mới cho mỗi yêu cầu gửi đến không? Spool up rack trường hợp ứng dụng trong các chủ đề mà vẫn tồn tại và chờ đợi cho các yêu cầu gửi đến?

Là cách duy nhất hoặc có những người khác không? Liệu vấn đề thời gian chạy ruby ​​để tối ưu hóa điểm 2?

+0

Tôi nghi ngờ phiên bản ruby ​​của bạn sẽ có nhiều điểm liên quan đến điểm 2. Điều này sẽ phụ thuộc nhiều vào việc triển khai đồng thời của máy chủ và cách đặt chính xác đường ray. – providence

Trả lời

6

Phương pháp phù hợp với bạn phụ thuộc rất nhiều vào phương thức slow của bạn đang thực hiện.

Trong một thế giới hoàn hảo, bạn có thể sử dụng một cái gì đó như đá quý sinatra-synchrony để xử lý từng yêu cầu trong một sợi. Bạn chỉ bị giới hạn bởi số lượng sợi tối đa. Thật không may, kích thước ngăn xếp trên sợi là hardcoded và rất dễ bị tràn ngập trong ứng dụng Rails. Ngoài ra, tôi đã đọc một vài câu chuyện kinh dị về những khó khăn của việc gỡ lỗi sợi, do khả năng tự động sau khi IO được khởi động. Điều kiện chủng tộc vẫn có thể sử dụng khi sử dụng xơ. Hiện nay, chất xơ Ruby là một chút của một khu ổ chuột, ít nhất là trên mặt trước của một ứng dụng web.

Một giải pháp thực dụng hơn không yêu cầu thay đổi mã là sử dụng máy chủ Rack có nhóm chủ đề công nhân như Rainbows! hoặc Puma. Tôi tin lá cờ --threaded của Thin xử lý từng yêu cầu trong một chủ đề mới, nhưng việc kéo sợi chỉ hệ điều hành gốc không phải là rẻ. Tốt hơn để sử dụng một hồ bơi thread với kích thước hồ bơi thiết lập đủ cao. Trong Rails, đừng quên đặt config.threadsafe! trong quá trình sản xuất.

Nếu bạn đồng ý với việc thay đổi mã, bạn có thể kiểm tra xuất sắc của Konstantin Haase talk on real-time Rack. Ông thảo luận về việc sử dụng lớp EventMachine::Deferrable để tạo ra phản hồi bên ngoài chu kỳ yêu cầu/phản hồi truyền thống mà Rack được xây dựng trên đó. Điều này có vẻ thực sự gọn gàng, nhưng bạn phải viết lại mã theo kiểu không đồng bộ.

Ngoài ra, hãy xem CrampGoliath. Điều này cho phép bạn triển khai phương thức slow của mình trong một ứng dụng Rack riêng biệt được lưu trữ cùng với ứng dụng Rails của bạn, nhưng có thể bạn sẽ phải viết lại mã của mình để hoạt động trong trình xử lý Cramp/Goliath.

Đối với câu hỏi của bạn về thời gian chạy Ruby, nó cũng phụ thuộc vào công việc mà slow đang thực hiện. Nếu bạn đang tính toán CPU nặng, thì bạn có nguy cơ bị GIL cung cấp cho bạn các vấn đề. Nếu bạn đang thực hiện IO, thì GIL không được để cản trở bạn. (Tôi nói không nên bởi vì tôi tin rằng tôi đã đọc về các vấn đề với đá quý mysql cũ hơn chặn GIL.)

Cá nhân, tôi đã thành công bằng cách sử dụng đồng bộ sinatra cho dịch vụ web phụ trợ, dịch vụ web. Tôi có thể đưa ra một số yêu cầu cho các dịch vụ web bên ngoài song song và chờ cho tất cả các yêu cầu đó trở lại. Trong khi đó, máy chủ Rails lối vào sử dụng một nhóm luồng và yêu cầu trực tiếp đến phần cuối. Không hoàn hảo, nhưng nó hoạt động đủ tốt ngay bây giờ.

Các vấn đề liên quan