Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Làm chủ Hiệu suất Cơ sở dữ liệu: Kỹ thuật Giám sát & Tối ưu hóa Thực tế

Việc quan sát toàn bộ kiến trúc ứng dụng — chứ không chỉ các khía cạnh riêng lẻ — và hiểu rõ cách các phần khác nhau kết nối với nhau là điều thiết yếu. Khả năng quan sát (observability) đến trước, sau đó mới đến giám sát (monitoring).

Trong bài viết này, chúng ta sẽ đi sâu vào phần cơ sở dữ liệu của kiến trúc để chỉ cách bạn có thể giám sát và tối ưu hóa hiệu suất database. Hầu hết các nguyên tắc dưới đây đều áp dụng được, bất kể stack công nghệ của bạn là gì, hay bạn muốn giám sát và tối ưu cho PostgreSQL, MongoDB hay bất kỳ database nào khác.

Tại sao Cần Giám sát Hiệu suất Database?

Giả sử một truy vấn chạy rất chậm, khiến ứng dụng phải chờ đợi kết quả — dẫn đến việc mọi thứ "đứng yên" đối với người dùng cuối và/hoặc một phần của ứng dụng.

Giống như ùn tắc giao thông, một đoạn đường có thể bị đứng yên do sự cố xảy ra ở nơi khác. Nếu nhiều truy vấn mất quá nhiều thời gian để giải quyết, có thể do các truy vấn khác đang "cản đường".

Mục tiêu của bạn là tìm ra nguyên nhân gốc rễ của vấn đề trước khi mọi thứ bắt đầu sai lệch ở các phần khác của ứng dụng.

Bước tiếp theo là chủ động sử dụng giám sát để tối ưu hóa kiến trúc và xem làm sao để mọi thứ chạy nhanh hơn. Nhưng chúng ta đang nói trước về bước 1:

Bước 1: Đo lường — Hay Còn Gọi Là Instrumenting Hiệu suất Database

Giám sát database bắt đầu bằng việc đảm bảo bạn đo lường đúng các chỉ số quan trọng:

  • Lỗi (Errors)
  • Hiệu suất (Performance)
  • Giá trị trung bình và phần trăm thứ 90 (p90) của thời gian thực hiện truy vấn (query duration)
  • Tổng thông lượng (total throughput) — cung cấp cách khác để thiết lập cảnh báo/flag khi thông lượng gặp vấn đề

May mắn thay, việc thu thập dữ liệu này đã được lo liệu sẵn: phần mềm APM của bạn thường cho phép cấu hình những gì bạn muốn instrument và đo lường. Nếu bạn dùng AppSignal, việc thu thập và tổng hợp dữ liệu diễn ra tự động, gần như không cần thiết lập. Chúng tôi đã gánh vác phần "nặng nhọc" cho bạn!

Bước 2: Điểm Khởi đầu — Tìm các Truy vấn Có Tác động Lớn

Khi ứng dụng đã được instrument và dữ liệu thực tế bắt đầu đổ về, các mô hình sẽ hiện rõ. Trên AppSignal, chúng tôi đã xây dựng các màn hình cho các API request chậm nhất và các truy vấn chậm nhất dưới mục "Improve" (Cải thiện) trên thanh điều hướng:

Màn hình này cung cấp điểm khởi đầu tuyệt vời cho việc tối ưu hóa. Mặc định, các truy vấn chậm được sắp xếp theo tác động (impact). Đó là những truy vấn bạn thực hiện thường xuyên. Tác động = thông lượng (throughput) × thời gian truy vấn trung bình.

Chuyển đổi giữa các cách sắp xếp này sẽ giúp bạn nắm được: truy vấn nào có khối lượng lớn nhất, truy vấn nào chậm nhất (nhưng có thể chỉ là background job chạy một lần mỗi đêm mà bạn có thể bỏ qua), và truy vấn nào có tác động lớn nhất.

Bước Ngắn: Sửa một vài Truy vấn Riêng lẻ

Bây giờ bạn có thể tìm được một số truy vấn để đi sâu vào sửa chữa.

Nếu click vào một truy vấn chậm, bạn sẽ thấy tất cả chi tiết của nó bên phải: từ thông lượng và thời gian phản hồi cho đến chính tên truy vấn:

Di chuột lên thời gian phản hồi tại một đỉnh (peak), sau đó zoom vào bằng cách click vào tùy chọn "what happened here" (điều gì xảy ra ở đây). Bạn sẽ thấy lỗi gì xảy ra tại thời điểm đó, trong mẫu đó, và điều gì xảy ra trên host.

Chúng tôi làm cho một anti-pattern cụ thể trở nên rất dễ nhận biết: N+1. Anti-pattern N+1 xảy ra khi một truy vấn được thực thi cho mỗi kết quả của một truy vấn trước đó.

Số lượng truy vấn = N + 1, với N là số truy vấn cho các kết quả của truy vấn ban đầu. Nếu truy vấn ban đầu có 1 kết quả, N+1 = 2. Nếu có 1.000 kết quả, N+1 = 1.001 truy vấn. "Bùng nổ".

Nếu truy vấn tuân theo anti-pattern N+1, đó là "may mắn trong bất hạnh" — chúng được gán nhãn ở đây để bạn tìm thấy nhanh chóng:

Chúng tôi không đi sâu vào cách giải quyết chúng ở đây — chúng tôi đã viết một bài blog riêng về truy vấn N+1.

Được, bây giờ giả sử chúng ta đã sửa một vài vấn đề "kinh dị", và trong quá trình sửa chúng ta đã nhận ra khi nào chúng xảy ra và thời gian phản hồi tệ nhất.

Bước 3: Tìm kiếm Quyết định các Mô hình — Điều gì đang Sai?

Giám sát thường liên quan đến việc nhìn vào lúc mọi thứ sai lệch. Nhưng một phần của sự phức tạp nằm ở việc định nghĩa cái gì được coi là "sai" cho thiết lập của bạn. Ngoài ra, bạn muốn được cảnh báo bởi một vấn đề rồi nó tự giải quyết, hay bỏ lỡ một vấn đề không tự giải quyết?

Hãy nhìn vào thông lượng và thời gian thực hiện của truy vấn theo trung bình. Bạn có thể thiết lập điều này trên phần mềm APM. Nếu bạn dùng AppSignal để giám sát Node.js và dùng PostgreSQL, chúng tôi tự động tạo dashboard với các chỉ số quan trọng nhất cho bạn.

Dashboard node-postgres sẽ hiển thị dữ liệu như sau:

Nếu bạn muốn thiết lập điều này cho ứng dụng của mình, đây là tài liệu tham khảo thêm.

Khi chuyển đổi giữa các khoảng thời gian khác nhau, bạn sẽ thấy các đỉnh ngắn biến mất trong trung bình của một giờ, cũng như các đỉnh vẫn cao khi zoom ra khoảng thời gian dài hơn.

Từ trải nghiệm xem màn hình truy vấn chậm nhất, chúng ta hiện có ý tưởng về các "thủ phạm" chính và khi nào chúng đỉnh điểm.

Một số đỉnh ngắn về thông lượng có thể ổn — host có thể đang chạy các tiến trình khác làm chậm truy vấn, ví dụ.

Bạn sẽ muốn zoom vào các thời gian truy vấn kéo dài hoặc thông lượng đỉnh điểm kéo dài. So sánh phần trăm thứ 95 (p95) với trung bình (mean) có thể cho biết truy vấn chậm có được trải nghiệm bởi mọi người hay chỉ một tập hợp nhỏ — điều này đôi khi giúp chỉ ra hướng khắc phục.

Bước 4: Điều gì Nên Giữ Làm Bạn Mất Ngủ?

Chúng tôi thường khuyên nên bắt đầu từ phía "nhiễu" (noisy): thiết lập một số trigger cảnh báo bạn trên kênh không đánh thức bạn dậy, như email hoặc Slack, thay vì PagerDuty.

Tạo một custom metrics trigger trên metric "event_duration" và chọn trường mean để nhận cảnh báo về thời gian truy vấn trung bình trong ứng dụng. Chọn phần trăm thứ 90 hoặc 95 để nhận cảnh báo về các truy vấn chậm nhất ứng dụng gặp phải.

Sau đó cấu hình tag "group" và "namespace" cho loại sự kiện bạn muốn được cảnh báo và namespace nào. Ví dụ: "active_record" (Rails) hoặc "postgres" (Node.js) hoặc "ecto" (Elixir) cho group, và "web" hoặc "background" cho namespace:

Sau một tuần, bạn sẽ bắt đầu thấy các mô hình và nắm được trường hợp nào cần chú ý, trường hợp nào thường tự giải quyết.

Sau đó bạn có thể điều chỉnh trigger để bớt "nhiễu" hơn và thêm kênh cho khi bạn muốn bị đánh thức bởi các cảnh báo cụ thể.

Bước 5: Hoàn tất Thiết lập Giám sát Database

Bây giờ, về mặt lý thuyết, chúng ta nên có một thiết lập giám sát đẹp: đúng dữ liệu đổ về, đã đặt trigger cảnh báo trước khi "việc xấu" xảy ra, và đã tìm ra một vài "thủ phạm" lớn. Chúng ta nên xong rồi, đúng không?

Trong thực tế, việc sử dụng ứng dụng có thể tăng lên và tạo ra tắc nghẽn mới. Hoặc thay đổi code có thể tác động đến database, làm tăng thời gian thực hiện. Hoặc một trường cụ thể với payload khổng lồ sẽ kích hoạt điều gì đó. Dù bạn có kinh nghiệm đến đâu, vấn đề và tắc nghẽn mới sẽ vẫn xảy ra.

Nhưng bạn có thể tìm thấy sự an tâm trong việc: với thiết lập đúng đắn, bạn sẽ được cảnh báo và biết cách đi sâu vào kiến trúc để giải quyết các vấn đề này.

Và có lẽ bạn sẽ tìm thấy niềm vui trong việc cải thiện những truy vấn "có tác động lớn" trước khi bất kỳ "vỉa" nào khác bị lỏng. Đó là điều chúng tôi yêu thích nhất — đó, và bánh stroopwafel.

Thử AppSignal, Nhận Stroopwafel 🍪

Nói đến stroopwafel, chúng tôi gửi chúng khắp nơi trên thế giới. Hãy thử phần mềm APM AppSignal cho Ruby, Elixir và Node.js. Nếu bạn đăng ký dùng thử miễn phí và liên hệ với chúng tôi, chúng tôi sẽ tặng bạn một hộp stroopwafel miễn phí.