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

Mở rộng quy mô Ruby on Rails để tăng trưởng lượng lớn người dùng

Hôm nay chúng ta sẽ đi sâu vào một số chiến lược mà bạn có thể sử dụng để mở rộng quy mô ứng dụng Ruby on Rails cho cơ sở người dùng khổng lồ.

Một cách rõ ràng để mở rộng quy mô ứng dụng là ném nhiều tiền hơn vào chúng. Và nó hoạt động rất tốt — thêm một vài máy chủ nữa, nâng cấp máy chủ cơ sở dữ liệu của bạn và thì đấy, rất nhiều vấn đề về hiệu suất chỉ xảy ra poof !

Nhưng cũng thường có thể mở rộng quy mô ứng dụng mà không cần thêm máy chủ. Đó là điều chúng ta sẽ thảo luận hôm nay.

Hãy bắt đầu nào!

Sử dụng AppSignal cho ứng dụng Rails của bạn

Trước khi chúng ta đi sâu vào việc mở rộng quy mô và tối ưu hóa hiệu suất, trước tiên bạn cần xác định nếu bạn cần thực hiện việc này, xem ứng dụng của bạn có những điểm nghẽn nào và những tài nguyên nào có thể mở rộng quy mô.

Một cách dễ dàng để thực hiện việc này là sử dụng các số liệu và giám sát hiệu suất của AppSignal cho Ruby.

Trang tổng quan hiệu suất giúp bạn xác định chính xác các hành động của bộ điều khiển và các tác vụ chạy nền có tốc độ trung bình chậm.

Ví dụ:đây là cách bảng thông tin hiệu suất có thể tìm kiếm ActiveRecord:

Mở rộng quy mô Ruby on Rails để tăng trưởng lượng lớn người dùng

Điều này mang lại điểm khởi đầu tốt cho bất kỳ hành trình mở rộng nào — cho dù bạn quyết định thêm nhiều máy chủ hay tối ưu hóa hiệu suất thông qua mã.

Bây giờ, hãy chuyển sang một trong những kỹ thuật đơn giản nhất mà bạn có thể sử dụng để mở rộng ứng dụng Rails của mình — bộ nhớ đệm.

Bộ nhớ đệm trong Ruby on Rails

Bộ nhớ đệm cho phép bạn ngừng tính toán lặp đi lặp lại những việc giống nhau.

Ví dụ:giả sử bạn điều hành một nền tảng truyền thông xã hội và có một bài đăng rất phổ biến. Bộ nhớ đệm có thể ngay lập tức giúp bạn lấy lại tất cả các chu kỳ CPU mà bạn dành để hiển thị bài đăng đó cho mọi người dùng. Và đó chỉ là một phần những gì bộ nhớ đệm có thể giúp bạn thực hiện.

Hãy xem xét tất cả các tài nguyên có thể được lưu vào bộ nhớ đệm.

Chế độ xem bộ nhớ đệm

Hiển thị chế độ xem đôi khi có thể là một thao tác tốn kém, đặc biệt khi chế độ xem đó có nhiều dữ liệu cần hiển thị. Ngay cả khi thao tác không tốn kém, việc sử dụng chế độ xem được kết xuất trước sẽ mang lại cho bạn hiệu suất cao hơn so với việc hiển thị cùng một chế độ xem đó hàng triệu lần.

Rails hỗ trợ tính năng này ngay lập tức bằng cách sử dụng cache xem người trợ giúp. Ví dụ:đây là cách nó có thể lưu vào bộ đệm từng bài đăng khi hiển thị danh sách:

 

Đối với điều này, Rails tự động lưu trữ từng bài đăng theo một khóa cụ thể phụ thuộc vào nội dung HTML của mẫu, id bài đăng và dấu thời gian cập nhật.

Để đọc thêm về kỹ thuật này, hãy xem các bài đăng Bộ nhớ đệm phân mảnh trong bộ nhớ đệm Rails và Rails.

Tuy nhiên, một điều cần lưu ý là các khóa bộ đệm không bao gồm nội dung mẫu lồng nhau. Vì vậy, nếu bạn lồng các lệnh gọi bộ nhớ đệm sâu hơn một cấp thì có thể có kết quả cũ. Đọc thêm về điều này trong bộ nhớ đệm búp bê Nga trong Rails.

Phản hồi lưu vào bộ nhớ đệm

Ngoài các chế độ xem/đoạn lưu vào bộ nhớ đệm, bạn cũng có thể chọn lưu vào bộ nhớ đệm phản hồi đầy đủ của GET yêu cầu. Điều này được hỗ trợ thông qua If-None-MatchIf-Modified-Since tiêu đề được gửi bởi trình duyệt.

Khi có If-None-Match tiêu đề xuất hiện trong yêu cầu, máy chủ có thể trả về 304 Not Modified phản hồi không có nội dung nếu không có thay đổi nào đối với phản hồi. Etag do máy chủ tính toán được so sánh với giá trị bên trong tiêu đề đó.

Tương tự, nếu If-Modified-Since tiêu đề hiện diện mà không có If-None-Match , máy chủ có thể trả về 304 Not Modified phản hồi không có nội dung (miễn là phản hồi không thay đổi kể từ ngày đó).

Rails cung cấp những cách dễ dàng để thực hiện việc này bên trong các hành động của bộ điều khiển. Bạn chỉ cần viết:

 

Rails sẽ gửi tất cả các tiêu đề cần thiết để hỗ trợ bộ nhớ đệm, xử lý các tiêu đề đến và phản hồi bằng 304 khi dữ liệu không thay đổi. Máy chủ có thể bỏ qua việc hiển thị lại toàn bộ chế độ xem trừ khi mọi thứ thay đổi. Bạn có thể đọc thêm về cấu hình nâng cao cho chiến lược này trong Bộ nhớ đệm phía máy khách trong Rails:yêu cầu GET có điều kiện.

Giá trị bộ nhớ đệm

Cuối cùng, cũng có thể lưu các giá trị thô vào bộ đệm (bất kỳ thứ gì có thể được tuần tự hóa vào kho lưu trữ bộ đệm). Điều này thường hữu ích để lưu vào bộ nhớ đệm các kết quả của các hoạt động tốn nhiều tài nguyên hoặc chậm và tránh thực hiện lại chúng.

Việc xác định giá trị có thể hưởng lợi từ bộ nhớ đệm này phụ thuộc rất lớn vào ứng dụng, nhưng thông thường, việc xem xét các sự kiện chậm nhất có thể giúp bạn đi đúng hướng.

Cuối cùng, khi bạn xác định những gì cần lưu vào bộ đệm, API mà Rails cung cấp cho việc này rất dễ sử dụng:

 

Đoạn mã trên sẽ perform_the_slow_computation chỉ một lần và sau đó lưu giá trị vào bộ đệm cache_key_with_version chìa khóa. Lần tiếp theo khi mã tương tự được gọi, trước tiên Rails sẽ kiểm tra xem chúng ta đã có giá trị được lưu trong bộ nhớ cache hay chưa và sử dụng giá trị đó thay vì kích hoạt perform_the_slow_computation một lần nữa.

Phần quan trọng nhất của chiến lược bộ đệm này là tính toán khóa bộ đệm tốt phụ thuộc vào tất cả đầu vào được sử dụng trong tính toán giá trị. Điều này nhằm đảm bảo chúng tôi không tiếp tục sử dụng giá trị cũ.

Cửa hàng bộ nhớ đệm

Bây giờ chúng ta đã biết những gì cần lưu vào bộ đệm và các kỹ thuật mà Rails cung cấp để lưu trữ mọi thứ trong bộ đệm, câu hỏi hợp lý tiếp theo là - chúng ta lưu trữ dữ liệu này vào bộ đệm ở đâu? Rails đi kèm với một số bộ điều hợp lưu trữ bộ nhớ đệm tích hợp sẵn. Các kho lưu trữ bộ đệm phổ biến nhất cho các trường hợp sử dụng sản xuất là Redis và Memcached. Ngoài ra còn có một số tùy chọn khác — lưu trữ tệp và  lưu trữ bộ nhớ. Bạn có thể tìm thấy thảo luận đầy đủ về các cửa hàng này trong bài đăng Cửa hàng bộ nhớ đệm tích hợp của Rails:tổng quan.

Các kho lưu trữ tệp và bộ nhớ có thể rất hữu ích cho việc sử dụng trong quá trình phát triển để giúp mọi thứ được thiết lập và chạy nhanh chóng. Tuy nhiên, chúng thường không phù hợp để sản xuất, đặc biệt nếu bạn đang làm việc trong môi trường phân tán có nhiều máy chủ. Redis và memcached đều phù hợp để sử dụng trong sản xuất. Bạn thường sử dụng cái nào tùy thuộc vào ứng dụng.

Nhân viên chạy nền trong Ruby on Rails

Hầu hết các ứng dụng đều cần các công việc nền cho người gửi thư, dọn dẹp thường xuyên hoặc bất kỳ hoạt động tốn thời gian nào khác mà không yêu cầu người dùng phải có mặt. Rất có thể bạn đã thiết lập xong nhân viên nền.

Bất cứ khi nào bạn thấy mình đang làm bất cứ điều gì mất hơn một giây để thực hiện bên trong một hành động của bộ điều khiển, hãy xem liệu bạn có thể chuyển nó sang một nhân viên chạy nền hay không. Điều này có thể bao gồm từ hoạt động hướng tới người dùng như tìm kiếm dữ liệu trong một bảng lớn đến phương thức API sử dụng một lượng lớn dữ liệu.

Ví dụ triển khai

Để chạy các công việc tùy chỉnh, Rails cung cấp khung Công việc Hoạt động. Hãy xem cách chúng ta có thể sử dụng nó để chuyển logic lọc rất phức tạp sang công việc nền. Trước tiên, hãy tạo công việc nền của chúng ta:

 

Chúng ta có thể chạy công việc này từ bộ điều khiển như thế này:

 

Chúng ta cần hiển thị chỉ báo tải trên mẫu của mình trong khi chờ công việc tính toán dữ liệu và đưa ra kết quả.

Nhưng làm sao chúng ta có thể thu được kết quả từ công việc của mình đến view? Turbo làm cho việc này thực sự dễ dàng. Ví dụ:bên trong chế độ xem, chúng ta có thể đăng ký các sự kiện turbo-stream trên một kênh thông báo cụ thể bằng cách sử dụng turbo_stream_from .

Sử dụng cái này, hãy viết các mẫu của chúng tôi:

 
 

Vì dữ liệu không được xác định trong hành động ban đầu của bộ điều khiển nên chúng tôi sẽ chỉ hiển thị chỉ báo tải. Bây giờ hãy mang lại kết quả từ công việc của chúng ta:

 

Phần quan trọng ở đây là notify_completed phương pháp. Nó sử dụng Turbo::StreamsChannel, phát sóng sự kiện thay thế tới [user, :huge_datasets] luồng thông báo mà chúng tôi đã đăng ký từ chế độ xem của chúng tôi.

Đó là tất cả những gì chúng ta cần để chuyển các hoạt động phức tạp từ bộ điều khiển sang các công việc nền. Ưu điểm chính của việc di chuyển các tác vụ xuống nền là nhân viên nền có thể được mở rộng quy mô độc lập với máy chủ web. Điều này giải phóng đáng kể tài nguyên ở phía máy chủ web. Đối với người dùng, những giao diện như vậy cũng mang lại cảm giác phản hồi nhanh hơn nhiều vì chúng tôi có thể phản hồi nhanh chóng và mang lại kết quả tăng dần.

Lưu ý :Nếu bạn cần trợ giúp để quyết định giữa một nhân viên làm công việc nền, hãy đọc Công việc bị trì hoãn so với Sidekiq:Cái nào tốt hơn?

Mở rộng cơ sở dữ liệu trong ứng dụng Ruby on Rails của bạn

Tài nguyên có thể mở rộng cuối cùng mà chúng ta sẽ thảo luận trong bài đăng này là cơ sở dữ liệu. Cơ sở dữ liệu là cốt lõi của hầu hết các ứng dụng. Khi dữ liệu và số lượng máy chủ truy cập dữ liệu đó tăng lên, cơ sở dữ liệu bắt đầu cảm thấy tải.

Cách dễ nhất để mở rộng quy mô cơ sở dữ liệu là bổ sung thêm sức mạnh xử lý và bộ nhớ cho máy chủ cơ sở dữ liệu. Ngược lại với việc mở rộng quy mô máy chủ web, thực hiện việc này với cơ sở dữ liệu thường là thao tác rất chậm, đặc biệt nếu bạn có dung lượng lưu trữ cao.

Tùy chọn thứ hai để mở rộng quy mô cơ sở dữ liệu là mở rộng quy mô theo chiều ngang bằng cách sử dụng nhiều cơ sở dữ liệu hoặc bằng cách chia nhỏ cơ sở dữ liệu của bạn. Hãy xem Nhiều cơ sở dữ liệu có Bản ghi hoạt động để biết thêm chi tiết về điều này.

Thay vào đó, chúng tôi sẽ tập trung vào việc tối ưu hóa hiệu suất cơ sở dữ liệu của bạn bằng cách xem xét PostgreSQL.

Tìm các truy vấn tốn thời gian trong PostgreSQL

Đầu tiên, chúng ta cần xác định các truy vấn tốn nhiều thời gian nhất. Cách chúng ta có thể làm là truy vấn pg_stat_statements bảng chứa số liệu thống kê về tất cả các câu lệnh SQL được thực thi trên máy chủ. Hãy xem cách chúng tôi có thể tìm thấy 100 truy vấn hàng đầu có thời gian chạy cao nhất:

 

Điều này sẽ trả về truy vấn, số lượng cuộc gọi và thời gian chạy trung bình của các truy vấn này. Hãy thử tìm những cái mà bạn nghĩ có thể nhanh hơn và phân tích lý do tại sao chúng chậm.

Bạn cũng có thể chạy EXPLAIN hoặc EXPLAIN ANALYZE trên truy vấn để xem kế hoạch truy vấn và chi tiết thực hiện thực tế tương ứng.

Một trong những điều quan trọng nhất cần chú ý trong kết quả là Seq Scan , điều này cho biết rằng Postgres phải lần lượt duyệt qua tất cả các bản ghi để chạy truy vấn. Nếu điều này xảy ra, hãy thử bỏ qua quá trình quét tuần tự đó bằng cách thêm chỉ mục vào các cột bạn đã lọc.

Các bảng có số lần quét tuần tự nhiều nhất

Một truy vấn hữu ích khác mà tôi muốn chạy là tìm tổng số lần quét tuần tự chạy trên một bảng:

 

Nếu bạn thấy một bảng rất lớn (với số lượng hàng cao) và giá trị đếm cao từ kết quả này thì bạn đã gặp vấn đề. Hãy thử kiểm tra tất cả các truy vấn đối với bảng đó, tìm những truy vấn có thể chạy quét tuần tự và thêm các chỉ mục để tổng hợp bảng đó.

Sử dụng chỉ mục

Bạn cũng có thể tìm số liệu thống kê về việc sử dụng chỉ mục bằng cách chạy truy vấn này:

 

Điều này trả về phần trăm sử dụng chỉ mục cho mỗi bảng. Số thấp có nghĩa là bạn đang thiếu một số chỉ mục trên bảng đó.

Kết thúc

Trong bài đăng này, chúng tôi đã khám phá một số chiến lược để mở rộng quy mô ứng dụng Ruby on Rails của bạn, bao gồm cả bộ nhớ đệm và trình xử lý nền. Chúng tôi cũng đã xem xét việc tối ưu hóa hiệu suất cơ sở dữ liệu PostgreSQL của bạn.

Rails giúp việc thêm nhiều lớp tối ưu hóa hiệu suất vào ứng dụng của bạn thực sự dễ dàng.

Việc cân nhắc quan trọng nhất với khả năng mở rộng là xác định các điểm nghẽn trong ứng dụng trước khi chúng ta có thể xử lý chúng. Một công cụ giám sát hiệu suất tốt có thể giúp ích. Nếu bạn cần, hãy xem AppSignal dành cho Ruby.

Chúc bạn viết mã vui vẻ!

Tái bút. Nếu bạn muốn đọc các bài đăng của Ruby Magic ngay khi chúng được đăng tải, hãy đăng ký nhận bản tin Ruby Magic của chúng tôi và không bao giờ bỏ lỡ một bài đăng nào!