Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Rails 컬렉션 캐싱

우리는 이전에 AppSignal Academy의 Rails에서 프래그먼트 캐싱을 살펴보았습니다. 이것은 보기의 더 작은 조각을 캐싱하여 보기의 성능을 크게 향상시킵니다. 부분을 ​​캐싱할 때 적은 비용으로 뷰의 다른 곳에서 재사용할 수 있다는 추가 이점이 있습니다.

이것은 작은 컬렉션에서는 잘 작동하지만 더 큰 컬렉션에서는 문제가 빠르게 발생합니다. 이 기사에서는 Rails 컬렉션 캐싱이 작동하는 방식과 이를 사용하여 대규모 컬렉션의 렌더링 속도를 높이는 방법을 살펴보겠습니다.

<블록 인용>

👋 그리고 이 기사가 마음에 드시면 Ruby(on Rails) 성능에 대해 더 많이 썼습니다. Ruby 성능 모니터링 체크리스트를 확인하세요.

컬렉션 렌더링

블로그 색인 페이지에 대한 최근 100개의 게시물을 로드하는 작은 컨트롤러부터 시작하겠습니다.

class PostsController < ApplicationController
  def index
    @posts = Post.all.order(:created_at => :desc).limit(100)
  end
end

보기에서 이러한 게시물을 렌더링하기 위해 @posts를 반복합니다. 인스턴스 변수.

<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
 
<div class="posts">
  <% @posts.each do |post| %>
    <div class="post">
      <h2><%= post.title %></h2>
      <small><%= post.author %></small>
 
      <div class="body">
        <%= post.body %>
      </div>
    </div>
  <% end %>
</div>

이 페이지를 요청하면 데이터베이스에서 게시물을 가져오고 뷰가 렌더링되는 것을 볼 수 있습니다. 보기 레이어에서 32밀리초만 사용하므로 이 페이지는 매우 빠릅니다.

Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.5ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
  Rendered posts/index.html.erb within layouts/application (19.4ms)
Completed 200 OK in 37ms (Views: 32.4ms | ActiveRecord: 2.7ms)

부분적으로 컬렉션 렌더링

다음으로 post 요소를 다른 보기에 추가하므로 게시물 HTML을 부분으로 이동합니다.

<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
 
<div class="posts">
  <% @posts.each do |post| %>
    <%= render post %>
  <% end %>
</div>
 
<!-- app/views/posts/_post.html.erb -->
<div class="post">
  <h2><%= post.title %></h2>
  <small><%= post.author %></small>
 
  <div class="body">
    <%= post.body %>
  </div>
</div>
Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.2ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
...
  Rendered posts/_post.html.erb (0.1ms)
  Rendered posts/_post.html.erb (0.1ms)
  Rendered posts/index.html.erb within layouts/application (205.4ms)
Completed 200 OK in 217ms (Views: 213.8ms | ActiveRecord: 1.7ms)

뷰 레이어에서 213밀리초를 사용하면 렌더링 시간이 상당히 증가한 것을 볼 수 있습니다. 이는 모든 게시물에 대해 새 파일(부분)을 로드, 컴파일 및 렌더링해야 하기 때문입니다. 프래그먼트 캐싱으로 렌더링 시간을 개선하는 방법을 간단히 살펴보겠습니다.

조각 캐싱

프래그먼트 캐싱 문서에 설명된 대로 cache render 주변 보기의 도우미 전화. 이러한 방식으로 모든 게시물에 대한 부분 렌더링을 캐시합니다.

<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
 
<div class="posts">
  <% @posts.each do |post| %>
    <%= cache post do %>
      <%= render post %>
    <% end %>
  <% end %>
</div>
Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index_with_partial_caching.html.erb within layouts/application
  Post Load (1.4ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
...
Read fragment views/posts/index.1ms)
  Rendered posts/_post.html.erb (0.1ms)
Write fragment views/posts/index.1ms)
Read fragment views/posts/index.5ms)
  Rendered posts/_post.html.erb (0.1ms)
Write fragment views/posts/index.1ms)
  Rendered posts/index.html.erb within layouts/application (274.5ms)
Completed 200 OK in 286ms (Views: 281.4ms | ActiveRecord: 2.4ms)

첫 번째 요청은 여전히 ​​모든 부분을 처음으로 렌더링하고 캐시 저장소에 저장해야 하기 때문에 그렇게 빠르지는 않습니다.

Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (2.2ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
...
Read fragment views/posts/index.1ms)
Read fragment views/posts/index.1ms)
  Rendered posts/index.html.erb within layouts/application (63.8ms)
Completed 200 OK in 78ms (Views: 75.5ms | ActiveRecord: 2.2ms)

후속 요청에서 보기에 소요된 시간이 286밀리초에서 78밀리초로 상당히 줄어든 것을 볼 수 있습니다. 그러나 원래 코드로 얻은 것보다 여전히 훨씬 느립니다. 거의 두 배나 느립니다.

참고:로그에 "Read/Write fragment" 줄이 표시되지 않으면 개발 환경에서 false로 설정된 조각 캐시 로깅을 활성화해야 합니다. 기본적으로 Rails 5.1 이상:

# config/environments/development.rb
config.action_controller.enable_fragment_cache_logging = true

컬렉션 캐싱

Rails 5에서는 컬렉션 캐싱을 더 빠르게 만들기 위해 많은 작업이 수행되었습니다. 이러한 개선 사항을 활용하려면 보기 코드를 변경해야 합니다. cache를 호출하는 대신 우리는 Rails에 전체 컬렉션을 렌더링하고 동시에 캐시하도록 요청할 수 있습니다.

<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
 
<div class="posts">
  <%= render partial: :post, collection: @posts, cached: true %>
</div>

render @collection, cached: true 이 캐싱 속도 향상에는 약기가 작동하지 않습니다.

Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.4ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
  Rendered collection of posts/_post.html.erb [0 / 100 cache hits] (28.2ms)
  Rendered posts/index.html.erb within layouts/application (46.6ms)
Completed 200 OK in 64ms (Views: 59.9ms | ActiveRecord: 2.0ms)

첫 번째 요청에서 이미 보기 계층에 소요되는 시간이 크게 개선된 것을 볼 수 있습니다. 이제 Rails가 미리 준비하기 때문입니다. 부분은 각 게시물에 대해 개별적으로 사용되지 않고 전체 컬렉션에 사용됩니다.

Started GET "/posts"
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (1.3ms)  SELECT  "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT ?  [["LIMIT", 100]]
  ↳ app/views/posts/index.html.erb:4
  Rendered collection of posts/_post.html.erb [100 / 100 cache hits] (19.2ms)
  Rendered posts/index.html.erb within layouts/application (26.5ms)
Completed 200 OK in 37ms (Views: 35.7ms | ActiveRecord: 1.3ms)

후속 요청에서는 64밀리초에서 약 35밀리초로 훨씬 더 개선된 것을 볼 수 있습니다. 컬렉션에 대한 Rails 최적화를 통해 전체 컬렉션의 속도가 크게 향상되었습니다. 모든 부분에 대한 캐시의 가용성을 확인하는 대신 Rails는 컬렉션의 모든 캐시 키를 동시에 확인하여 캐시 저장소를 쿼리하는 시간을 절약합니다.

이 캐싱 도우미의 추가 이점은 컬렉션의 요약된 로깅입니다. 첫 번째 요청에서 캐시 키가 발견되지 않았습니다. [0 / 100 cache hits] 하지만 두 번째 요청에서는 모두 [100 / 100 cache hits]이(가) 발견되었습니다. .

데이터베이스의 일부 개체를 업데이트한 후에는 얼마나 많은 키가 오래되었는지 확인할 수 있습니다.

Rendered collection of posts/_post.html.erb [88 / 100 cache hits] (13.4ms)

이 최적화된 컬렉션 렌더링 및 캐싱을 사용하면 속도가 크게 향상됩니다. 더 큰 컬렉션을 렌더링할 때 훨씬 더 큰 차이가 발생합니다. 컬렉션에 대한 사용자 정의 보기가 필요하지 않은 한 이 최적화된 전략이 Rails 앱에 적합한 방법입니다. AppSignal에서 이러한 방식으로 수천 개의 레코드를 렌더링하는 관리자 보기 중 하나의 속도를 크게 높일 수 있었습니다.

Rails의 캐싱 컬렉션에 대해 질문이 있습니까? 주저하지 말고 @AppSignal로 알려주세요! 기사에 대한 의견이 있거나 다루었으면 하는 주제가 있으면 연락해 주십시오.