Hôm nay chúng ta sẽ đi sâu vào bộ nhớ đệm của Russian Doll như một chiến thuật để cải thiện hơn nữa bộ nhớ đệm của bạn ngoài bộ nhớ đệm phân mảnh tích hợp sẵn của Rails.
Bộ nhớ đệm phân mảnh
Khi sử dụng bộ nhớ đệm phân đoạn tích hợp sẵn của Rails, các phần của dạng xem được hiển thị được lưu trữ dưới dạng các đoạn dạng xem và được sử dụng lại nếu chúng được yêu cầu lại. Các đoạn đã lưu trong bộ nhớ cache này được sử dụng lại cho đến khi chúng chuyển sang cũ , nghĩa là chúng đã lỗi thời vì dữ liệu chúng hiển thị đã thay đổi kể từ khi tạo phân đoạn. Nếu bạn muốn đọc thêm, trong bài đăng trước này, chúng tôi sẽ giải thích sâu hơn một chút về bộ nhớ đệm phân mảnh.
👋 Và nếu bạn muốn đọc về hiệu suất rộng hơn chỉ là bộ nhớ đệm, hãy xem danh sách kiểm tra giám sát hiệu suất Ruby của chúng tôi.
Mặc dù điều này giúp tăng tốc độ tốt, đặc biệt đối với các chế độ xem phức tạp hoặc các chế độ xem có nhiều phần được kết xuất, chúng tôi có thể cải thiện điều này một số chi tiết bằng cách tăng gấp đôi với cách tiếp cận có tên là Bộ nhớ đệm búp bê Nga .
Khi sử dụng cách tiếp cận bộ nhớ đệm này, các phân đoạn xem được đặt bên trong nhau, giống như búp bê “Matryoshka” mà chiến lược được đặt tên theo. Bằng cách chia nhỏ các đoạn đã lưu trong bộ nhớ cache thành các phần nhỏ hơn, bộ nhớ đệm bên ngoài có thể được hiển thị nhanh hơn khi chỉ một trong các đoạn lồng nhau của nó thay đổi.
Một ví dụ về bộ nhớ đệm cho búp bê Nga
Ví dụ, hãy sử dụng một cửa hàng bán sản phẩm. Mỗi sản phẩm có thể có một số biến thể, chẳng hạn như cho phép bán nhiều màu của một mặt hàng. Trên chỉ mục, chúng tôi sẽ hiển thị từng sản phẩm có sẵn để bán, cũng như tất cả các biến thể của nó.
Trên chỉ mục sản phẩm, chúng tôi đã gói từng sản phẩm một phần trong cache
khối. Chúng tôi đang sử dụng product
đối tượng để xây dựng khóa bộ nhớ cache, được sử dụng để làm mất hiệu lực của phân đoạn được lưu trong bộ nhớ cache. Nó bao gồm id của đối tượng, ngày update_at và một bản tóm tắt của cây mẫu, vì vậy nó tự động được coi là cũ nếu đối tượng thay đổi hoặc nếu nội dung của mẫu thay đổi.
# app/views/products/index.html.erb
<h1>Products</h1>
<% @products.each do |product| %>
<% cache product do %>
<%= render product %>
<% end %>
<% end %>
Mẹo :Chúng tôi đang viết toàn bộ khối cho rõ ràng, nhưng bạn có thể hiển thị từng sản phẩm trong một khối bộ nhớ cache bằng cách sử dụng <%= render partial: 'products/product', collection: @products, cached: true %>
thay vào đó.
Trong phần sản phẩm, chúng tôi hiển thị một hàng cho từng biến thể của sản phẩm.
# app/views/products/_product.html.erb
<article>
<h1><%= product.title %></h1>
<ul>
<% product.variants.each do |variant| %>
<%= render variant %>
<% end %>
</ul>
</article>
Vô hiệu bộ nhớ cache
Mặc dù các khóa bộ đệm trong bộ đệm phân mảnh của Rails giúp việc vô hiệu hóa bộ đệm dễ dàng hơn, nhưng bạn không bao giờ hoàn toàn lo lắng về việc xác thực bộ đệm (một trong hai điều khó khăn nổi tiếng trong khoa học máy tính).
Trong ví dụ này, chúng tôi lưu vào bộ nhớ cache một phần các sản phẩm, chứa danh sách các biến thể của sản phẩm. Vì khóa bộ nhớ cache không bao gồm bất kỳ thông tin nào về các biến thể, mọi biến thể mới được thêm vào sẽ không hiển thị trừ khi bản thân sản phẩm cũng thay đổi.
Cách để khắc phục điều này là đảm bảo sản phẩm không thay đổi khi có bất kỳ điều gì thay đổi trong một trong các biến thể của nó. Để làm điều đó, chúng tôi sẽ cập nhật updated_at
của sản phẩm thuộc tính bất cứ khi nào điều đó xảy ra. Vì điều này rất phổ biến, nên có một đối số cho belongs_to
(và các phương thức quan hệ khác của ActiveModel), được gọi là :touch
, điều đó sẽ tự động cập nhật update_at của đối tượng mẹ cho chúng tôi.
class Variant < ApplicationRecord
belongs_to :product, touch: true
end
Các đoạn lồng nhau
Bây giờ chúng tôi đã đảm bảo cập nhật các phân đoạn sản phẩm khi các biến thể của chúng thay đổi, đã đến lúc lưu các biến thể vào bộ nhớ cache. Giống như trước đây, chúng tôi sẽ thêm cache
chặn xung quanh mỗi cái.
<article>
<h1><%= product.title %></h1>
<ul>
<% product.variants.each do |variant| %>
<% cache(variant) do %>
<%= render variant %>
<% end %>
<% end %>
</ul>
</article>
Mẹo :Chúng tôi đang viết toàn bộ khối cho rõ ràng, nhưng bạn có thể hiển thị từng biến thể trong một khối bộ nhớ cache bằng cách sử dụng <%= render partial: 'variants/variant', collection: product.variants, cached: true %>
thay vào đó.
Trên bộ đệm lạnh (bạn có thể xóa bộ đệm bằng cách chạy rake tmp:cache:clear
), yêu cầu đầu tiên sẽ hiển thị từng phần sản phẩm.
Khi yêu cầu trang ngay bây giờ (đừng quên bật bộ nhớ đệm đang phát triển bằng cách chạy rails dev:cache
), mỗi phần sản phẩm sẽ được lưu vào bộ nhớ cache như một phần và yêu cầu thứ hai sẽ trả về các phần được lưu trong bộ nhớ cache.
Started GET "/products" for 127.0.0.1 at 2018-03-30 14:51:38 +0200
Processing by ProductsController#index as HTML
Rendering products/index.html.erb within layouts/application
Product Load (0.2ms) SELECT "products".* FROM "products"
Variant Load (0.9ms) SELECT "variants".* FROM "variants" WHERE "variants"."product_id" IN (27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51)
Rendered variants/_variant.html.erb (0.5ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.0ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered products/_product.html.erb (44.8ms) [cache miss]
...
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered variants/_variant.html.erb (0.1ms)
Rendered products/_product.html.erb (46.2ms) [cache miss]
Rendered products/index.html.erb within layouts/application (1378.6ms)
Completed 200 OK in 1414ms (Views: 1410.5ms | ActiveRecord: 1.1ms)
Started GET "/products" for 127.0.0.1 at 2018-03-30 14:51:41 +0200
Processing by ProductsController#index as HTML
Rendering products/index.html.erb within layouts/application
Product Load (0.3ms) SELECT "products".* FROM "products"
Variant Load (12.7ms) SELECT "variants".* FROM "variants" WHERE "variants"."product_id" IN (27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51)
Rendered products/index.html.erb within layouts/application (48.1ms)
Completed 200 OK in 76ms (Views: 59.0ms | ActiveRecord: 13.0ms)
Thì đấy:Phép thuật búp bê Nga
Có thể thấy sự kỳ diệu của bộ nhớ đệm búp bê Nga khi thay đổi một trong các biến thể. Khi yêu cầu lại chỉ mục sau khi một trong các biến thể thay đổi, phân đoạn sản phẩm được lưu trong bộ nhớ cache sẽ được hiển thị vì updated_at
của nó thuộc tính đã thay đổi.
Một phần sản phẩm bao gồm từng biến thể của sản phẩm. Phân đoạn được lưu trong bộ nhớ cache cho biến thể mà chúng tôi vừa thay đổi đã cũ, vì vậy nó cần được tạo lại, nhưng các biến thể khác không thay đổi, vì vậy các phân đoạn được lưu trong bộ nhớ cache của chúng sẽ được sử dụng lại. Trong nhật ký, chúng ta có thể thấy rằng cả phần biến thể và phần sản phẩm đều được hiển thị cùng một lúc.
Started GET "/products" for 127.0.0.1 at 2018-03-30 14:52:04 +0200
Processing by ProductsController#index as HTML
Rendering products/index.html.erb within layouts/application
Product Load (0.3ms) SELECT "products".* FROM "products"
Variant Load (1.2ms) SELECT "variants".* FROM "variants" WHERE "variants"."product_id" IN (27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51)
Rendered variants/_variant.html.erb (0.5ms)
Rendered products/_product.html.erb (13.3ms) [cache miss]
Rendered products/index.html.erb within layouts/application (45.9ms)
Completed 200 OK in 78ms (Views: 73.5ms | ActiveRecord: 1.5ms)
Kết quả cuối cùng
Bằng cách lồng các phân đoạn bộ nhớ cache như thế này, chế độ xem gần như không bao giờ được hiển thị toàn bộ, trừ khi bộ nhớ cache hoàn toàn trống. Ngay cả khi dữ liệu thay đổi, hầu hết các trang được hiển thị đều được phân phát trực tiếp từ bộ nhớ đệm.
Chúng tôi hy vọng điều này đã giúp bạn có được thông tin chi tiết mới về hiệu suất ứng dụng của mình. Đó là lý do tại sao chúng tôi ở đây. bộ nhớ đệm trong Rails mà chúng tôi đã đề cập trước đó trong bài đăng.