Computer >> Máy Tính >  >> Lập trình >> Ruby

Bộ nhớ đệm phân mảnh trong Rails

Khi một ứng dụng Rails chấp nhận một yêu cầu, bộ điều khiển thường sẽ yêu cầu mô hình cho dữ liệu được yêu cầu. Sau đó, mô hình tìm nạp nó từ cơ sở dữ liệu và chuyển nó trở lại bộ điều khiển. Bộ điều khiển cuối cùng hiển thị chế độ xem đại diện cho dữ liệu ở định dạng con người có thể đọc được.

Trong một số tình huống, hiển thị chế độ xem là một thao tác tốn kém, đặc biệt nếu chế độ xem cần hiển thị nhiều dữ liệu, chẳng hạn như khi hiển thị danh sách tất cả các sản phẩm có sẵn trong cửa hàng. Trong những trường hợp như vậy, việc lưu vào bộ nhớ đệm các phần của chế độ xem trả về có thể tăng tốc độ mọi thứ, đặc biệt là khi dữ liệu không thay đổi quá thường xuyên.

👋 Và nếu bạn thích bài viết này, chúng tôi đã viết nhiều hơn về hiệu suất của Ruby (trên Rails), hãy xem danh sách kiểm tra giám sát hiệu suất Ruby của chúng tôi.

Kiểm tra bộ nhớ đệm cục bộ

Bộ nhớ đệm bị tắt trong quá trình phát triển theo mặc định, để đảm bảo bạn luôn nhận được phản hồi mới từ ứng dụng của mình. Để kiểm tra bộ nhớ đệm cục bộ, bạn sẽ phải bật tính năng này trong cấu hình phát triển của mình.

Trong Rails 5, bạn có thể tạm thời bật bộ nhớ đệm từ dòng lệnh. Điều này sẽ sử dụng bộ nhớ lưu trữ, có nghĩa là các đoạn được lưu trong bộ nhớ cache sẽ được lưu trong bộ nhớ trong quy trình Ruby của máy chủ web.

$ rails dev:cache
Development mode is now being cached.

Bạn có thể chạy lệnh tương tự để tắt bộ nhớ đệm.

Bộ nhớ đệm phân mảnh

Giả sử chúng ta có một trang hiển thị tất cả các sản phẩm trong cửa hàng trên một trang. Để làm điều đó, chúng tôi có chế độ xem chỉ mục hiển thị các sản phẩm.

# app/views/products/index.html.erb
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Description</th>
      <th>Image url</th>
      <th>Price</th>
      <th colspan="3"></th>
    </tr>
  </thead>
 
  <tbody>
    <% @products.each do |product| %>
      <%= render product %>
    <% end %>
  </tbody>
</table>

Đối với mỗi sản phẩm, _product.html.erb một phần được hiển thị, giúp hiển thị một hàng trong bảng với thông tin chi tiết của sản phẩm.

# app/views/products/_product.html.erb
<tr>
  <td><%= product.title %></td>
  <td><%= product.description %></td>
  <td><%= product.image_url %></td>
  <td><%= product.price %></td>
  <td><%= link_to 'Show', product %></td>
  <td><%= link_to 'Edit', edit_product_path(product) %></td>
  <td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>

Yêu cầu trang cục bộ, ở chế độ phát triển, với 25 sản phẩm trong cơ sở dữ liệu mất khoảng 300 mili giây. Hầu như tất cả thời gian đó được dành để hiển thị các phần.

Nhiều khả năng, phản hồi sẽ nhanh hơn trong quá trình sản xuất, vì nội dung đi kèm, ít ghi nhật ký hơn và máy chủ web nhanh hơn. Mặc dù các con số trong quá trình phát triển không chính xác, nhưng chúng sẽ cho thấy phần nào trong yêu cầu của chúng tôi là chậm nhất, vì vậy chúng tôi có thể cố gắng tăng tốc độ.

Started GET "/products" for ::1 at 2018-03-13 12:16:08 +0100
Processing by ProductsController#index as HTML
  Rendering products/index.html.erb within layouts/application
  Product Load (0.4ms)  SELECT "products".* FROM "products"
  Rendered products/_product.html.erb (1.4ms)
  Rendered products/_product.html.erb (0.4ms)
  Rendered products/_product.html.erb (0.4ms)
  Rendered products/_product.html.erb (0.3ms)
  Rendered products/_product.html.erb (0.5ms)
  Rendered products/_product.html.erb (2.0ms)
  Rendered products/_product.html.erb (0.9ms)
  Rendered products/_product.html.erb (0.4ms)
  Rendered products/_product.html.erb (0.5ms)
  Rendered products/_product.html.erb (0.5ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.7ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.7ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.5ms)
  Rendered products/_product.html.erb (0.7ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.9ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/_product.html.erb (0.5ms)
  Rendered products/_product.html.erb (0.6ms)
  Rendered products/index.html.erb within layouts/application (257.5ms)
Completed 200 OK in 295ms(Views: 290.4ms | ActiveRecord: 0.4ms)

Để tiết kiệm thời gian hiển thị tất cả các phần tử này, chúng ta có thể sử dụng bộ nhớ đệm phân đoạn tích hợp sẵn của Rails , nơi lưu trữ một phần của chế độ xem được kết xuất dưới dạng một mảnh. Đối với các yêu cầu tiếp theo, phân đoạn đã lưu trước được sử dụng thay vì hiển thị lại.

Để lưu vào bộ nhớ cache một phân đoạn, bạn bọc nó trong một khối bằng cách sử dụng cache người trợ giúp.

<table>
  # ...
  <tbody>
    <% @products.each do |product| %>
      <% cache(product) do %>
        <%= render product %>
      <% end %>
    <% end %>
  </tbody>
</table>

Để xem liệu các sản phẩm này có tăng tốc độ phản hồi của chúng tôi trong bộ nhớ đệm hay không, chúng tôi sẽ yêu cầu trang này hai lần. Yêu cầu thứ hai sẽ thực thi nhanh hơn rất nhiều, vì mỗi sản phẩm trong chế độ xem đã được hiển thị trước và được lưu trữ trong bộ nhớ cache.

Started GET "/products" for ::1 at 2018-03-13 12:17:29 +0100
Processing by ProductsController#index as HTML
  Rendering products/index.html.erb within layouts/application
  Product Load (0.4ms)  SELECT "products".* FROM "products"
  Rendered products/index.html.erb within layouts/application (21.2ms)
Completed 200 OK in 55ms (Views: 50.8ms | ActiveRecord: 0.4ms)

Nó đã làm việc! Yêu cầu thứ hai nhanh hơn yêu cầu đầu tiên hơn năm lần. Lưu ý rằng các bản ghi không hiển thị bất kỳ kết xuất nào của các thành phần, vì chúng được tải trực tiếp từ bộ nhớ cache.

Hết bộ nhớ đệm

Khi gọi cache trong ví dụ trên, chúng tôi đã chuyển product đối tượng dưới dạng phụ thuộc bộ nhớ cache . Điều này cho phép người trợ giúp biết rằng nội dung của phân đoạn được lưu trong bộ nhớ cache phụ thuộc vào đối tượng sản phẩm.

Bên trong, đối tượng sản phẩm có #cache_key , được sử dụng để tạo khóa cho phân đoạn được lưu trong bộ nhớ cache. Chìa khóa cho toàn bộ phân đoạn có thể trông như thế này:

views/products/42-20180302103130041320/75dda06d36880e8b0ae6cac0a44fb56d

Khóa bộ nhớ cache bao gồm một số phần:

  • "lượt xem / sản phẩm" là lớp trong bộ nhớ cache .
  • 42 là ID của sản phẩm
  • 20180302103130041320 là ngày update_at của sản phẩm
  • 75dda06d36880e8b0ae6cac0a44fb56d là một bản tóm tắt của cây mẫu

Khóa này thay đổi bất cứ khi nào sản phẩm được cập nhật hoặc bất kỳ thứ gì trong mẫu thay đổi. Khi nó xảy ra, nó gây ra lỗi trong bộ nhớ cache, khiến phân mảnh hiển thị lại và lưu một phân mảnh mới. Điều này đảm bảo phân đoạn vẫn mới, ngay cả khi các thành phần của nó thay đổi.

Bộ nhớ đệm ngoài phân đoạn

Mặc dù các đoạn được lưu trong bộ nhớ cache được thảo luận trong ví dụ này mang lại một tốc độ tăng nhỏ, nhưng có nhiều thứ để lưu vào bộ nhớ đệm hơn chúng ta đã thảo luận ngày hôm nay. Bằng cách sử dụng các chiến lược như bộ nhớ đệm của búp bê Nga hoặc các phương pháp cấp thấp hơn như bộ nhớ đệm kết quả truy vấn cơ sở dữ liệu, có thể đạt được tốc độ lớn hơn.

Tất nhiên, chúng ta sẽ đi sâu vào những điều này trong một tập sau của AppSignal Academy. Bất cứ điều gì cụ thể bạn muốn tìm hiểu về? Vui lòng cho chúng tôi biết tại @AppSignal. Tất nhiên, chúng tôi muốn biết bạn thích bài viết này như thế nào hoặc nếu bạn có chủ đề khác mà bạn muốn biết thêm.