Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การแคชแฟรกเมนต์ใน Rails

เมื่อแอปพลิเคชัน Rails ยอมรับคำขอ ตัวควบคุมมักจะถามโมเดลสำหรับข้อมูลที่ร้องขอ จากนั้นโมเดลจะดึงข้อมูลจากฐานข้อมูลและส่งกลับไปยังคอนโทรลเลอร์ ในที่สุดคอนโทรลเลอร์ก็แสดงมุมมองซึ่งแสดงถึงข้อมูลในรูปแบบที่มนุษย์อ่านได้

ในบางสถานการณ์ การแสดงมุมมองเป็นการดำเนินการที่มีราคาแพง โดยเฉพาะอย่างยิ่งถ้ามุมมองต้องการแสดงข้อมูลจำนวนมาก เช่น เมื่อแสดงรายการของผลิตภัณฑ์ที่มีอยู่ทั้งหมดในร้านค้า เป็นต้น ในกรณีเช่นนี้ การแคชบางส่วนของมุมมองที่ส่งคืนสามารถเร่งความเร็วได้ โดยเฉพาะอย่างยิ่งเมื่อข้อมูลไม่เปลี่ยนแปลงบ่อยเกินไป

👋 และถ้าคุณชอบบทความนี้ ยังมีอีกมากที่เราเขียนเกี่ยวกับประสิทธิภาพของ Ruby (on Rails) ให้ดูที่รายการตรวจสอบการตรวจสอบประสิทธิภาพของ Ruby

การทดสอบการแคชในเครื่อง

การแคชจะถูกปิดในระหว่างการพัฒนาโดยค่าเริ่มต้น เพื่อให้แน่ใจว่าคุณจะได้รับคำตอบใหม่ๆ จากแอปของคุณอยู่เสมอ หากต้องการทดสอบการแคชในเครื่อง คุณจะต้องเปิดใช้ในการกำหนดค่าการพัฒนา

ใน Rails 5 คุณสามารถเปิดแคชชั่วคราวจากบรรทัดคำสั่งได้ การดำเนินการนี้จะใช้ที่เก็บหน่วยความจำ ซึ่งหมายความว่าส่วนย่อยที่แคชไว้จะถูกเก็บไว้ในหน่วยความจำในกระบวนการ Ruby ของเว็บเซิร์ฟเวอร์

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

คุณสามารถเรียกใช้คำสั่งเดียวกันเพื่อปิดการแคชกลับได้

การแคชแฟรกเมนต์

สมมติว่าเรามีเพจที่แสดงสินค้าทั้งหมดในร้านค้าในหน้าเดียว ในการทำเช่นนั้น เรามีมุมมองดัชนีที่แสดงผลิตภัณฑ์

# 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>

สำหรับแต่ละผลิตภัณฑ์ _product.html.erb แสดงผลบางส่วน ซึ่งดูแลการแสดงแถวตารางพร้อมรายละเอียดของผลิตภัณฑ์

# 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>

การขอเพจแบบโลคัลในโหมดการพัฒนาโดยมีผลิตภัณฑ์ 25 รายการในฐานข้อมูลใช้เวลาประมาณ 300 มิลลิวินาที ใช้เวลาเกือบทั้งหมดในการแสดงผลบางส่วน

เป็นไปได้มากว่าการตอบกลับจะเร็วขึ้นในการผลิต เนื่องจากสินทรัพย์ที่รวมเข้าด้วยกัน บันทึกน้อยลง และเว็บเซิร์ฟเวอร์ที่เร็วขึ้น แม้ว่าตัวเลขที่กำลังพัฒนาจะไม่ถูกต้อง แต่จะแสดงว่าคำขอของเราส่วนใดช้าที่สุด ดังนั้นเราจึงสามารถพยายามเร่งความเร็วได้

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)

เพื่อประหยัดเวลาในการแสดงผลบางส่วนเหล่านี้ เราสามารถใช้ การแคชส่วนย่อย ในตัวของ Rails ซึ่งเก็บส่วนหนึ่งของมุมมองที่แสดงเป็นส่วนย่อย สำหรับคำขอที่ตามมา ส่วนที่บันทึกไว้ล่วงหน้าจะใช้แทนการแสดงผลอีกครั้ง

ในการแคชแฟรกเมนต์ คุณต้องแรปมันในบล็อกโดยใช้ cache ตัวช่วย

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

หากต้องการดูว่าการแคชผลิตภัณฑ์เหล่านี้เร่งการตอบสนองของเราหรือไม่ เราจะขอหน้าเว็บสองครั้ง คำขอที่สองควรดำเนินการเร็วกว่ามาก เนื่องจากผลิตภัณฑ์แต่ละรายการในมุมมองได้รับการแสดงผลล่วงหน้าและจัดเก็บไว้ในแคชแล้ว

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)

มันได้ผล! คำขอที่สองเร็วกว่าคำขอแรกมากกว่าห้าเท่า โปรดทราบว่าบันทึกไม่แสดงการแสดงผลบางส่วน เนื่องจากถูกโหลดจากแคชโดยตรง

แคชหมดอายุ

เมื่อเรียกใช้ cache ตัวช่วยในตัวอย่างข้างต้น เราส่ง product ออบเจ็กต์เป็น การพึ่งพาแคช . ซึ่งช่วยให้ผู้ช่วยรู้ว่าเนื้อหาของส่วนแคชขึ้นอยู่กับวัตถุผลิตภัณฑ์

ภายในอ็อบเจ็กต์ผลิตภัณฑ์มี #cache_key เมธอด ซึ่งใช้ในการสร้างคีย์สำหรับส่วนแคช กุญแจสำหรับทั้งส่วนอาจมีลักษณะดังนี้:

views/products/42-20180302103130041320/75dda06d36880e8b0ae6cac0a44fb56d

คีย์แคชประกอบด้วยสองส่วน:

  • "การดู/ผลิตภัณฑ์" เป็นแคช คลาส .
  • 42 คือรหัสสินค้า
  • 20180302103130041320 คือวันที่ update_at ของผลิตภัณฑ์
  • 75dda06d36880e8b0ae6cac0a44fb56d เป็นการสรุปของแผนผังต้นไม้

คีย์นี้จะเปลี่ยนแปลงทุกครั้งที่มีการอัปเดตผลิตภัณฑ์ หรือมีการเปลี่ยนแปลงใดๆ ในเทมเพลต เมื่อเป็นเช่นนั้น จะทำให้แคชพลาด ทำให้แฟรกเมนต์แสดงผลอีกครั้งและบันทึกแฟรกเมนต์ใหม่ เพื่อให้แน่ใจว่าชิ้นส่วนจะคงความสดแม้ส่วนประกอบจะเปลี่ยนไป

นอกเหนือจากการแคชส่วนย่อย

แม้ว่าส่วนย่อยของแคชที่กล่าวถึงในตัวอย่างนี้ให้การเร่งความเร็วเพียงเล็กน้อย แต่การแคชยังมีอะไรมากกว่าที่เราพูดถึงในวันนี้ การใช้กลยุทธ์อย่างการแคชตุ๊กตารัสเซียหรือวิธีการระดับล่าง เช่น การแคชผลลัพธ์การสืบค้นฐานข้อมูล จะทำให้การเร่งความเร็วเพิ่มขึ้นได้สำเร็จ

แน่นอน เราจะพูดถึงสิ่งเหล่านี้ในตอนต่อๆ ไปของ AppSignal Academy คุณต้องการเรียนรู้อะไรเป็นพิเศษไหม โปรดอย่าลังเลที่จะแจ้งให้เราทราบที่ @AppSignal แน่นอน เราอยากทราบว่าคุณชอบบทความนี้อย่างไร หรือหากคุณมีหัวข้ออื่นที่ต้องการทราบข้อมูลเพิ่มเติม