Làm thế nào để bộ nhớ đệm dựa trên khóa hoạt động?


10

Gần đây tôi đã đọc một bài viết trên blog 37Signals và tôi không biết làm thế nào mà họ nhận được khóa bộ nhớ cache.

Tất cả đều tốt và tốt khi có khóa bộ đệm bao gồm dấu thời gian của đối tượng (điều này có nghĩa là khi bạn cập nhật đối tượng, bộ đệm sẽ bị vô hiệu); nhưng làm thế nào để bạn sử dụng khóa bộ đệm trong một mẫu mà không gây ra một cú đánh DB cho chính đối tượng mà bạn đang cố gắng tìm nạp từ bộ đệm.

Cụ thể, điều này ảnh hưởng như thế nào đến nhiều mối quan hệ nơi bạn đang hiển thị Nhận xét của Bài đăng chẳng hạn.

Ví dụ trong Django:

{% for comment in post.comments.all %}
   {% cache comment.pk comment.modified %}
     <p>{{ post.body }}</p>
   {% endcache %}
{% endfor %}

Là bộ nhớ đệm trong Rails khác với chỉ yêu cầu ghi nhớ chẳng hạn (tôi biết rằng họ chuyển đổi khóa bộ nhớ cache của bạn thành một cái gì đó khác). Có phải họ cũng lưu trữ khóa bộ nhớ cache?


Hãy xem rossp.org/blog/2012/feb/29/fragment-caching cho một ví dụ Django!
vdboor

Tôi đã có một cái nhìn về điều đó và dường như bị vấn đề chính xác như vậy. Dữ liệu anh ấy đang cố gắng lưu vào bộ đệm được yêu cầu để truy cập bộ đệm. Điều duy nhất anh ta dường như đang tiết kiệm là trong hoạt động đắt tiền bên trong, không giống như hầu hết các trường hợp sử dụng cho loại bộ đệm này.
Dominic Santos

Điều đó đúng, một điều cũng xảy ra với mã 37signals, nó tập trung vào mã kết xuất. Thủ thuật là lưu trữ toàn bộ danh sách trong một bộ chứa khác hoặc lưu bộ đệm của đối tượng ở nơi khác.
vdboor

Trên thực tế chiến lược lưu trữ của họ có vẻ giáo dục hơn một chút. Tôi cũng đề xuất bài viết này: 37signals.com/svn/posts/ Nhật
JensG

Có vẻ như đoạn mã của bạn có một lỗi đánh máy - được post.bodydự định là comment.body?
Izkata

Câu trả lời:


3

Để lưu trữ bộ đệm thẳng của một đối tượng đã được tải, vâng, bạn không thu được gì hoặc không có gì. Đó không phải là những gì những ví dụ đó đang mô tả - họ đang mô tả một hệ thống phân cấp, trong đó bất kỳ thay đổi nào đối với thứ gì đó thấp hơn cũng sẽ kích hoạt một bản cập nhật cho mọi thứ cao hơn trong hệ thống phân cấp.

Ví dụ đầu tiên, từ blog 37signals, sử dụng Project -> Todolist -> Todolàm hệ thống phân cấp. Một ví dụ dân cư có thể trông như thế này:

Project: Foo (last_modified: 2014-05-10)
   Todolist:  Bar1 (last_modified: 2014-05-10)
       Todo:  Bang1 (last_modified: 2014-05-09)
       Todo:  Bang2 (last_modified: 2014-05-09)

   Todolist:  Bar2 (last_modified: 2014-04-01)
       Todo:  Bang3 (last_modified: 2014-04-01)
       Todo:  Bang4 (last_modified: 2014-04-01)

Vì vậy, hãy nói rằng Bang3đã được cập nhật. Tất cả cha mẹ của nó cũng được cập nhật:

Project: Foo (last_modified: 2014-05-16)
   Todolist:  Bar2 (last_modified: 2014-05-16)
       Todo:  Bang3 (last_modified: 2014-05-16)

Sau đó, khi đến lúc kết xuất, việc tải Projecttừ cơ sở dữ liệu về cơ bản là không thể tránh khỏi. Bạn cần một điểm để bắt đầu tại. Tuy nhiên, vì đây last_modifiedlà chỉ báo cho tất cả các con của nó , đó là những gì bạn sử dụng làm khóa bộ đệm trước khi thử tải các con.


Trong khi các bài đăng trên blog sử dụng các mẫu riêng biệt, tôi sẽ gộp chúng lại thành một mẫu. Hy vọng nhìn thấy sự tương tác hoàn toàn ở một nơi sẽ làm cho nó rõ ràng hơn một chút.

Vì vậy, mẫu Django có thể trông giống như thế này:

{% cache 9999 project project.cache_key %}
<h2>{{ project.name }}<h2>
<div>
   {% for list in project.todolist.all %}
   {% cache 9999 todolist list.cache_key %}
      <ul>
         {% for todo in list.todos.all %}
            <li>{{ todo.body }}</li>
         {% endfor %}
      </ul>
   {% endcache %}
   {% endfor %}
</div>
{% endcache %}

Giả sử chúng ta vượt qua trong một Dự án cache_keyvẫn còn tồn tại trong bộ đệm. Vì chúng tôi tuyên truyền các thay đổi cho tất cả các đối tượng liên quan đến cha mẹ, thực tế là khóa cụ thể đó vẫn tồn tại có nghĩa là toàn bộ nội dung được hiển thị có thể được kéo từ bộ đệm.

Nếu Dự án cụ thể đó vừa được cập nhật - ví dụ như Fooở trên - thì nó sẽ phải kết xuất con của nó và chỉ sau đó nó mới chạy truy vấn cho tất cả Todolists cho Dự án đó. Tương tự như vậy đối với một Todolist cụ thể - nếu cache_key của danh sách đó tồn tại, thì các todos bên trong nó không thay đổi và toàn bộ có thể được lấy từ bộ đệm.

Cũng lưu ý cách tôi không sử dụng todo.cache_keytrong mẫu này. Điều đó không đáng, vì như bạn nói trong câu hỏi, bodyđã được lấy từ cơ sở dữ liệu. Tuy nhiên, lượt truy cập cơ sở dữ liệu không phải là lý do duy nhất bạn có thể lưu trữ một cái gì đó. Ví dụ: lấy văn bản đánh dấu thô (chẳng hạn như những gì chúng ta nhập vào hộp câu hỏi / câu trả lời trên StackExchange) và chuyển đổi nó thành HTML có thể mất đủ thời gian để lưu trữ kết quả sẽ hiệu quả hơn.

Nếu đúng như vậy, vòng lặp bên trong trong mẫu có thể trông giống như thế này:

         {% for todo in list.todos.all %}
            {% cache 9999 todo todo.cache_key %}
               <li>{{ todo.body|expensive_markup_parser }}</li>
            {% endcache %}
         {% endfor %}

Vì vậy, để kết nối mọi thứ lại với nhau, hãy quay lại dữ liệu gốc của tôi ở đầu câu trả lời này. Nếu chúng ta giả sử:

  • Tất cả các đối tượng đã được lưu trữ trong trạng thái ban đầu của họ
  • Bang3 vừa được cập nhật
  • Chúng tôi đang kết xuất mẫu đã sửa đổi (bao gồm expensive_markup_parser)

Sau đó, đây là cách mọi thứ sẽ được tải:

  • Foo được lấy từ cơ sở dữ liệu
  • Foo.cache_key (2014-05-16) không tồn tại trong bộ đệm
  • Foo.todolists.all()được truy vấn: Bar1Bar2được lấy từ cơ sở dữ liệu
  • Bar1.cache_key(2014-05-10) đã tồn tại trong bộ đệm ; lấy và xuất nó
  • Bar2.cache_key (2014-05-16) không tồn tại trong bộ đệm
  • Bar2.todos.all()được truy vấn: Bang3Bang4được lấy từ cơ sở dữ liệu
  • Bang3.cache_key (2014-05-16) không tồn tại trong bộ đệm
  • {{ Bang3.body|expensive_markup_parser }} Được hiển thị
  • Bang4.cache_key(2014-04-01) đã tồn tại trong bộ đệm ; lấy và xuất nó

Tiết kiệm từ bộ đệm trong ví dụ nhỏ này là:

  • Cơ sở dữ liệu nhấn tránh: Bar1.todos.all()
  • expensive_markup_parsertránh 3 lần: Bang1, Bang2, vàBang4

Và tất nhiên, lần sau nó được xem, Foo.cache_keysẽ được tìm thấy, do đó, chi phí duy nhất để kết xuất là lấy Foomột mình từ cơ sở dữ liệu và truy vấn bộ đệm.


-2

Ví dụ của bạn là tốt nếu nó cần một số truy xuất dữ liệu hoặc xử lý cho mỗi bình luận. Nếu bạn chỉ lấy cơ thể và hiển thị nó - bộ nhớ cache sẽ vô dụng. Nhưng bạn có thể lưu trữ tất cả các cây nhận xét (bao gồm {% cho%}). Trong trường hợp này, bạn cần phải vô hiệu hóa nó với mỗi bình luận được thêm vào, vì vậy bạn có thể đặt dấu thời gian bình luận cuối cùng hoặc đếm bình luận ở đâu đó vào Bài đăng và xây dựng khóa bộ đệm bình luận với nó. Nếu bạn thích dữ liệu được chuẩn hóa hơn và chỉ sử dụng nhận xét trên một trang, bạn chỉ có thể xóa khóa bộ nhớ cache khi lưu nhận xét.

Đối với tôi, việc lưu số bình luận trong Bài viết có vẻ đủ tốt (nếu bạn không cho phép xóa và chỉnh sửa nhận xét) - bạn có một giá trị để hiển thị ở bất cứ đâu với Bài đăng và một phím để lưu vào bộ đệm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.