Sử dụng Memcached: có tốt không khi cập nhật bộ đệm khi cập nhật cơ sở dữ liệu?


13

Câu hỏi này là về thực hành tốt nhất trong kiến ​​trúc.

Kiến trúc hiện tại của chúng tôi

Tôi có một lớp PHP truy cập MySQL cho thông tin người dùng. Hãy gọi nó là User. Userđược truy cập nhiều lần, vì vậy chúng tôi đã triển khai các lớp bộ nhớ đệm để giảm tải.

Lớp đầu tiên là cái mà chúng ta gọi là bộ đệm "theo yêu cầu". Sau khi dữ liệu được lấy từ MySQL, chúng tôi lưu trữ dữ liệu trong một thuộc tính riêng tư của User. Mọi yêu cầu tiếp theo cho dữ liệu sẽ trả về thuộc tính thay vì yêu cầu lại dữ liệu từ MySQL.

Vì yêu cầu web tồn tại và chết trên cơ sở theo yêu cầu, bộ đệm này chỉ ngăn ứng dụng truy cập MySQL nhiều lần trong một yêu cầu.

Lớp thứ hai của chúng tôi là Memcached. Khi tài sản riêng trống, trước tiên chúng tôi kiểm tra Memcached cho dữ liệu. Nếu Memcached trống, chúng tôi truy vấn MySQL để lấy dữ liệu, cập nhật Memcached và cập nhật thuộc tính riêng tư của User.

Câu hỏi

Ứng dụng của chúng tôi là một trò chơi và đôi khi bắt buộc phải cập nhật một số dữ liệu nhất có thể. Trong khoảng năm phút, yêu cầu đọc dữ liệu người dùng có thể xảy ra 10 hoặc 11 lần; sau đó một bản cập nhật có thể xảy ra. Các yêu cầu đọc tiếp theo cần phải được cập nhật hoặc cơ chế trò chơi thất bại.

Vì vậy, những gì chúng tôi đã làm là triển khai một đoạn mã được thực thi khi cập nhật cơ sở dữ liệu xảy ra. Mã này đặt khóa trong Memcached với dữ liệu được cập nhật, vì vậy tất cả các yêu cầu tiếp theo đối với Memcached đều được cập nhật.

Điều này có tối ưu không? Có bất kỳ mối quan tâm về hiệu suất hoặc "vấn đề" nào khác mà chúng ta nên biết khi cố gắng duy trì một loại "bộ đệm sống" như thế này không?


Điều này có liên quan gì đến việc xóa và thêm lại dữ liệu?
Mike Nakis

Làm rõ tiêu đề câu hỏi.
Stephen

Tại sao không hết hạn dữ liệu được lưu trữ? Cập nhật nó có nghĩa là bạn sẽ cần đảm bảo cập nhật được duy trì (để nếu dữ liệu mới cần được cập nhật theo cách này, bạn sẽ phải tiếp tục thay đổi bản cập nhật). Hết hạn bộ đệm có nghĩa là mọi thứ mới được lấy từ cơ sở dữ liệu --- và mọi cập nhật mới không cần thay đổi mới đối với mã cập nhật. Nhược điểm là tải cơ sở dữ liệu có thể cao hơn.
Peter K.

@Peter Vâng, chúng tôi cũng nghĩ về điều đó. Nếu không có vấn đề nào khác với cách tiếp cận hiện tại của chúng tôi, chúng tôi sẽ tiếp tục với nó. Nếu không, chúng tôi có thể đi với những gì bạn đã mô tả.
Stephen

1
@Stephen Cách tiếp cận bạn mô tả được gọi là "Viết qua bộ đệm" và là một cách tiếp cận khá phổ biến.
Sripathi Krishnan

Câu trả lời:


10

Đề nghị của tôi là xem xét hồ sơ sử dụng của bạn và yêu cầu của bạn cho bộ đệm.

Tôi có thể thấy không có lý do tại sao bạn sẽ để lại dữ liệu cũ trong memcached. Tôi nghĩ rằng bạn đã chọn đúng phương pháp, tức là: cập nhật DB.

Trong mọi trường hợp, bạn sẽ cần một trình bao bọc trên bản cập nhật DB của bạn (mà bạn đã thực hiện). Mã của bạn để cập nhật Người dùng trong DB và trong RAM cũng cần thực hiện một cú đẩy để ghi nhớ, HOẶC hết hạn trong memcached.

Ví dụ: Nếu người dùng của bạn thường thực hiện cập nhật một lần mỗi phiên như một phần của việc đăng xuất, sẽ không có nhiều điểm cập nhật dữ liệu trong bộ đệm (ví dụ: tổng số điểm cao) - bạn nên hết hạn ngay lập tức.

Tuy nhiên, nếu họ sẽ cập nhật dữ liệu (ví dụ: trạng thái trò chơi hiện tại) và sau đó 0,2 giây, bạn sẽ có một trang PHP ngay lập tức sẽ yêu cầu dữ liệu, bạn sẽ muốn nó mới trong bộ đệm.


3

Tôi sẽ không đi về nó khá giống như bạn vạch ra. Những gì bạn cần làm là quyết định xem bạn có thực sự CẦN dữ liệu cập nhật hay không. Sau đó, nếu bạn cần nó, hãy quyết định phần nào của dữ liệu cần được cập nhật mọi lúc và tách chúng khỏi những thứ có thể được lưu trong bộ nhớ cache trong kiến ​​trúc của bạn.

Ví dụ: bạn có thể muốn cập nhật địa chỉ email của người dùng ngay khi họ thay đổi địa chỉ đó, vì vậy bạn không gửi thư đến địa chỉ sai, nhưng không chắc là ngày sinh hoặc họ của người dùng sẽ cần phải hoàn toàn cập nhật để cung cấp trải nghiệm người dùng tốt. (NB Tôi không sử dụng ví dụ về kiến ​​trúc trò chơi vì tôi không biết nên nhắm vào loại trò chơi nào và tôi nghĩ trò chơi này khá dễ hiểu).

Bằng cách này, bạn có hai bộ dữ liệu rõ ràng: dữ liệu có thể lưu trong bộ nhớ cache ngắn và dài hạn. Bạn có thể có thể thoát khỏi thời lượng bộ nhớ cache trong một phút hoặc lâu hơn trên dữ liệu ngắn hạn, chỉ để giảm tải cho DB, nhưng dữ liệu dài hạn có thể được lưu trong bộ đệm trong thời gian trượt miễn là nó đã sử dụng.

Sau đó, bạn cần phải đối phó với các bản cập nhật. Trước tiên tôi xem xét việc sử dụng trình kích hoạt DB để chỉ cần xóa các mục khỏi bộ đệm khi chúng hết hạn. Điều đó sẽ buộc lớp doanh nghiệp của bạn kích hoạt làm mới bộ đệm trong lần tiếp theo nó yêu cầu dữ liệu, giải phóng một số không gian trong bộ đệm nếu dữ liệu không được sử dụng (ví dụ: nếu người dùng thay đổi địa chỉ email của họ thì đăng xuất ngay lập tức) . Nếu điều này sẽ gây ra các vấn đề về hiệu năng trong giao diện người dùng (nghĩa là giới thiệu quá nhiều độ trễ trong khi chờ làm mới bộ đệm) thì bạn có thể xem xét đơn giản là kích hoạt cuộc gọi bộ đệm khi mục bị xóa khỏi bộ đệm. Tôi cũng sẽ xem xét tối ưu hóa thời gian đọc DB cho tập dữ liệu nhỏ này, để đảm bảo rằng bất kỳ độ trễ nào gây ra khi làm mới bộ đệm là tối thiểu (điều này sẽ dễ dàng hơn khi bạn chỉ cần tải dữ liệu bạn thực sự cần).

Những gì tôi sẽ không làm, trong mọi trường hợp, là thêm một phương thức bổ sung để lấp đầy bộ đệm, vì khi đó bạn sẽ cần duy trì cuộc gọi (và móc API, v.v.) ở hai nơi.

Đối với gotchas, điều chính bạn cần cẩn thận nếu bạn ghi trực tiếp vào bộ đệm là đồng bộ hóa. Nếu nhiều luồng cố gắng đọc trong khi bạn đang thực hiện cập nhật im lặng, bạn có thể gặp một số vấn đề dữ liệu không hợp lệ nghiêm trọng, điều này sẽ đánh bại điểm cố gắng giữ dữ liệu cập nhật ở vị trí đầu tiên.

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.