Phân tích TSDB trong Prometheus 2

Phân tích TSDB trong Prometheus 2

Cơ sở dữ liệu chuỗi thời gian (TSDB) trong Prometheus 2 là một ví dụ tuyệt vời về giải pháp kỹ thuật cung cấp những cải tiến lớn so với bộ lưu trữ v2 trong Prometheus 1 về tốc độ tích lũy dữ liệu, thực thi truy vấn và hiệu quả sử dụng tài nguyên. Chúng tôi đang triển khai Prometheus 2 trong Giám sát và Quản lý Percona (PMM) và tôi đã có cơ hội hiểu được hiệu suất của Prometheus 2 TSDB. Trong bài viết này tôi sẽ nói về kết quả của những quan sát này.

Khối lượng công việc trung bình của Prometheus

Đối với những người đã quen làm việc với cơ sở dữ liệu có mục đích chung, khối lượng công việc điển hình của Prometheus khá thú vị. Tốc độ tích lũy dữ liệu có xu hướng ổn định: thông thường các dịch vụ bạn giám sát gửi cùng số lượng số liệu và cơ sở hạ tầng thay đổi tương đối chậm.
Yêu cầu thông tin có thể đến từ nhiều nguồn khác nhau. Một số trong số chúng, chẳng hạn như cảnh báo, cũng cố gắng đạt được giá trị ổn định và có thể dự đoán được. Những yêu cầu khác, chẳng hạn như yêu cầu của người dùng, có thể gây ra bùng nổ, mặc dù điều này không xảy ra đối với hầu hết các khối lượng công việc.

Kiểm tra tải

Trong quá trình thử nghiệm, tôi tập trung vào khả năng tích lũy dữ liệu. Tôi đã triển khai Prometheus 2.3.2 được biên dịch bằng Go 1.10.1 (như một phần của PMM 1.14) trên dịch vụ Linode bằng tập lệnh này: StackScript. Để tạo tải thực tế nhất, hãy sử dụng StackScript Tôi đã khởi chạy một số nút MySQL với tải thực (Sysbench TPC-C Test), mỗi nút mô phỏng 10 nút Linux/MySQL.
Tất cả các thử nghiệm sau đây được thực hiện trên máy chủ Linode có tám lõi ảo và bộ nhớ 32 GB, chạy 20 mô phỏng tải theo dõi hai trăm phiên bản MySQL. Hoặc, theo thuật ngữ của Prometheus, 800 mục tiêu, 440 mẩu tin lưu niệm mỗi giây, 380 nghìn bản ghi mỗi giây và 1,7 triệu chuỗi thời gian hoạt động.

Thiết kế

Cách tiếp cận thông thường của cơ sở dữ liệu truyền thống, bao gồm cả cơ sở dữ liệu được Prometheus 1.x sử dụng, là giới hạn bộ nhớ. Nếu nó không đủ để xử lý tải, bạn sẽ gặp phải độ trễ cao và một số yêu cầu sẽ không thành công. Việc sử dụng bộ nhớ trong Prometheus 2 có thể được cấu hình thông qua phím storage.tsdb.min-block-duration, xác định thời gian lưu giữ các bản ghi trong bộ nhớ trước khi chuyển vào đĩa (mặc định là 2 giờ). Dung lượng bộ nhớ cần thiết sẽ phụ thuộc vào số lượng chuỗi thời gian, nhãn và mẩu tin lưu niệm được thêm vào luồng mạng đến. Về dung lượng ổ đĩa, Prometheus đặt mục tiêu sử dụng 3 byte cho mỗi bản ghi (mẫu). Mặt khác, yêu cầu về bộ nhớ cao hơn nhiều.

Mặc dù có thể định cấu hình kích thước khối nhưng không nên định cấu hình thủ công, vì vậy bạn buộc phải cung cấp cho Prometheus nhiều bộ nhớ mà nó yêu cầu cho khối lượng công việc của bạn.
Nếu không có đủ bộ nhớ để hỗ trợ luồng số liệu đến, Prometheus sẽ hết bộ nhớ hoặc kẻ sát nhân OOM sẽ lấy được nó.
Việc thêm trao đổi để trì hoãn sự cố khi Prometheus hết bộ nhớ không thực sự hữu ích, vì việc sử dụng chức năng này sẽ gây ra tình trạng tiêu thụ bộ nhớ bùng nổ. Tôi nghĩ đó là điều gì đó liên quan đến Go, trình thu gom rác và cách nó xử lý trao đổi.
Một cách tiếp cận thú vị khác là cấu hình khối head để được xóa vào đĩa tại một thời điểm nhất định, thay vì đếm nó từ đầu quá trình.

Phân tích TSDB trong Prometheus 2

Như bạn có thể thấy từ biểu đồ, việc xóa đĩa xảy ra hai giờ một lần. Nếu bạn thay đổi tham số thời lượng khối tối thiểu thành một giờ thì những lần đặt lại này sẽ diễn ra mỗi giờ, bắt đầu sau nửa giờ.
Nếu bạn muốn sử dụng biểu đồ này và các biểu đồ khác trong quá trình cài đặt Prometheus của mình, bạn có thể sử dụng biểu đồ này bảng điều khiển. Nó được thiết kế cho PMM nhưng với những sửa đổi nhỏ, phù hợp với mọi cài đặt Prometheus.
Chúng ta có một khối hoạt động được gọi là khối đầu được lưu trong bộ nhớ; các khối có dữ liệu cũ hơn có sẵn thông qua mmap(). Điều này giúp loại bỏ nhu cầu cấu hình bộ đệm riêng biệt nhưng cũng có nghĩa là bạn cần chừa đủ dung lượng cho bộ đệm của hệ điều hành nếu bạn muốn truy vấn dữ liệu cũ hơn những gì khối đầu có thể chứa.
Điều này cũng có nghĩa là mức tiêu thụ bộ nhớ ảo của Prometheus sẽ khá cao, đây không phải là điều đáng lo ngại.

Phân tích TSDB trong Prometheus 2

Một điểm thiết kế thú vị khác là việc sử dụng WAL (viết trước nhật ký). Như bạn có thể thấy từ tài liệu lưu trữ, Prometheus sử dụng WAL để tránh sự cố. Thật không may, các cơ chế cụ thể để đảm bảo khả năng tồn tại của dữ liệu không được ghi chép đầy đủ. Prometheus phiên bản 2.3.2 chuyển WAL vào đĩa 10 giây một lần và tùy chọn này không thể định cấu hình cho người dùng.

Sự nén chặt

Prometheus TSDB được thiết kế giống như một kho lưu trữ LSM (Hợp nhất Cấu trúc Nhật ký): khối đầu được chuyển định kỳ vào đĩa, trong khi cơ chế nén kết hợp nhiều khối lại với nhau để tránh quét quá nhiều khối trong khi truy vấn. Tại đây bạn có thể thấy số khối mà tôi quan sát được trên hệ thống thử nghiệm sau một ngày tải.

Phân tích TSDB trong Prometheus 2

Nếu muốn tìm hiểu thêm về cửa hàng, bạn có thể kiểm tra tệp meta.json, tệp này có thông tin về các khối có sẵn và cách chúng hình thành.

{
       "ulid": "01CPZDPD1D9R019JS87TPV5MPE",
       "minTime": 1536472800000,
       "maxTime": 1536494400000,
       "stats": {
               "numSamples": 8292128378,
               "numSeries": 1673622,
               "numChunks": 69528220
       },
       "compaction": {
               "level": 2,
               "sources": [
                       "01CPYRY9MS465Y5ETM3SXFBV7X",
                       "01CPYZT0WRJ1JB1P0DP80VY5KJ",
                       "01CPZ6NR4Q3PDP3E57HEH760XS"
               ],
               "parents": [
                       {
                               "ulid": "01CPYRY9MS465Y5ETM3SXFBV7X",
                               "minTime": 1536472800000,
                               "maxTime": 1536480000000
                       },
                       {
                               "ulid": "01CPYZT0WRJ1JB1P0DP80VY5KJ",
                               "minTime": 1536480000000,
                               "maxTime": 1536487200000
                       },
                       {
                               "ulid": "01CPZ6NR4Q3PDP3E57HEH760XS",
                               "minTime": 1536487200000,
                               "maxTime": 1536494400000
                       }
               ]
       },
       "version": 1
}

Quá trình nén trong Prometheus được gắn với thời điểm khối đầu được đưa vào đĩa. Tại thời điểm này, một số hoạt động như vậy có thể được thực hiện.

Phân tích TSDB trong Prometheus 2

Có vẻ như việc nén không bị giới hạn theo bất kỳ cách nào và có thể gây ra xung đột I/O trên đĩa lớn trong quá trình thực thi.

Phân tích TSDB trong Prometheus 2

Tải CPU tăng đột biến

Phân tích TSDB trong Prometheus 2

Tất nhiên, điều này có tác động khá tiêu cực đến tốc độ của hệ thống và cũng đặt ra thách thức nghiêm trọng cho việc lưu trữ LSM: làm cách nào để thực hiện nén để hỗ trợ tốc độ yêu cầu cao mà không gây ra quá nhiều chi phí?
Việc sử dụng bộ nhớ trong quá trình nén cũng có vẻ khá thú vị.

Phân tích TSDB trong Prometheus 2

Chúng ta có thể thấy, sau khi nén, hầu hết bộ nhớ thay đổi trạng thái từ Đã lưu vào bộ nhớ đệm thành Miễn phí: điều này có nghĩa là thông tin có giá trị tiềm ẩn đã bị xóa khỏi đó. Tò mò nếu nó được sử dụng ở đây fadvice() hoặc một số kỹ thuật giảm thiểu khác, hay là do bộ đệm đã được giải phóng khỏi các khối bị phá hủy trong quá trình nén?

Phục hồi sau thất bại

Phục hồi từ thất bại cần có thời gian và vì lý do chính đáng. Đối với luồng đến một triệu bản ghi mỗi giây, tôi phải đợi khoảng 25 phút trong khi quá trình khôi phục được thực hiện có tính đến ổ SSD.

level=info ts=2018-09-13T13:38:14.09650965Z caller=main.go:222 msg="Starting Prometheus" version="(version=2.3.2, branch=v2.3.2, revision=71af5e29e815795e9dd14742ee7725682fa14b7b)"
level=info ts=2018-09-13T13:38:14.096599879Z caller=main.go:223 build_context="(go=go1.10.1, user=Jenkins, date=20180725-08:58:13OURCE)"
level=info ts=2018-09-13T13:38:14.096624109Z caller=main.go:224 host_details="(Linux 4.15.0-32-generic #35-Ubuntu SMP Fri Aug 10 17:58:07 UTC 2018 x86_64 1bee9e9b78cf (none))"
level=info ts=2018-09-13T13:38:14.096641396Z caller=main.go:225 fd_limits="(soft=1048576, hard=1048576)"
level=info ts=2018-09-13T13:38:14.097715256Z caller=web.go:415 component=web msg="Start listening for connections" address=:9090
level=info ts=2018-09-13T13:38:14.097400393Z caller=main.go:533 msg="Starting TSDB ..."
level=info ts=2018-09-13T13:38:14.098718401Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536530400000 maxt=1536537600000 ulid=01CQ0FW3ME8Q5W2AN5F9CB7R0R
level=info ts=2018-09-13T13:38:14.100315658Z caller=web.go:467 component=web msg="router prefix" prefix=/prometheus
level=info ts=2018-09-13T13:38:14.101793727Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536732000000 maxt=1536753600000 ulid=01CQ78486TNX5QZTBF049PQHSM
level=info ts=2018-09-13T13:38:14.102267346Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536537600000 maxt=1536732000000 ulid=01CQ78DE7HSQK0C0F5AZ46YGF0
level=info ts=2018-09-13T13:38:14.102660295Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536775200000 maxt=1536782400000 ulid=01CQ7SAT4RM21Y0PT5GNSS146Q
level=info ts=2018-09-13T13:38:14.103075885Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536753600000 maxt=1536775200000 ulid=01CQ7SV8WJ3C2W5S3RTAHC2GHB
level=error ts=2018-09-13T14:05:18.208469169Z caller=wal.go:275 component=tsdb msg="WAL corruption detected; truncating" err="unexpected CRC32 checksum d0465484, want 0" file=/opt/prometheus/data/.prom2-data/wal/007357 pos=15504363
level=info ts=2018-09-13T14:05:19.471459777Z caller=main.go:543 msg="TSDB started"
level=info ts=2018-09-13T14:05:19.471604598Z caller=main.go:603 msg="Loading configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499156711Z caller=main.go:629 msg="Completed loading of configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499228186Z caller=main.go:502 msg="Server is ready to receive web requests."

Vấn đề chính của quá trình khôi phục là mức tiêu thụ bộ nhớ cao. Mặc dù trong điều kiện bình thường, máy chủ có thể hoạt động ổn định với cùng dung lượng bộ nhớ nhưng nếu gặp sự cố, máy chủ có thể không phục hồi được do OOM. Giải pháp duy nhất tôi tìm thấy là vô hiệu hóa tính năng thu thập dữ liệu, khởi động máy chủ, để nó khôi phục và khởi động lại khi kích hoạt tính năng thu thập.

Làm nóng lên

Một hành vi khác cần lưu ý trong quá trình khởi động là mối quan hệ giữa hiệu suất thấp và mức tiêu thụ tài nguyên cao ngay sau khi bắt đầu. Trong một số lần khởi động, nhưng không phải tất cả, tôi nhận thấy CPU và bộ nhớ đang tải nặng.

Phân tích TSDB trong Prometheus 2

Phân tích TSDB trong Prometheus 2

Khoảng trống trong việc sử dụng bộ nhớ cho thấy Prometheus không thể định cấu hình tất cả các bộ sưu tập ngay từ đầu và một số thông tin sẽ bị mất.
Tôi chưa tìm ra lý do chính xác khiến CPU và bộ nhớ tải cao. Tôi nghi ngờ rằng điều này là do việc tạo chuỗi thời gian mới trong khối đầu với tần suất cao.

Tải CPU tăng vọt

Ngoài việc nén tạo ra tải I/O khá cao, tôi nhận thấy tải CPU tăng đột biến nghiêm trọng cứ sau hai phút. Các đợt này sẽ kéo dài hơn khi luồng đầu vào cao và có vẻ như do trình thu gom rác của Go gây ra, với ít nhất một số lõi đã được tải đầy đủ.

Phân tích TSDB trong Prometheus 2

Phân tích TSDB trong Prometheus 2

Những bước nhảy này không phải là không đáng kể. Có vẻ như khi những điều này xảy ra, điểm vào và số liệu nội bộ của Prometheus sẽ không khả dụng, gây ra khoảng trống dữ liệu trong cùng khoảng thời gian này.

Phân tích TSDB trong Prometheus 2

Bạn cũng có thể nhận thấy rằng trình xuất Prometheus ngừng hoạt động trong một giây.

Phân tích TSDB trong Prometheus 2

Chúng ta có thể nhận thấy mối tương quan với việc thu gom rác (GC).

Phân tích TSDB trong Prometheus 2

Kết luận

TSDB trong Prometheus 2 có tốc độ nhanh, có khả năng xử lý hàng triệu chuỗi thời gian và đồng thời hàng nghìn bản ghi mỗi giây bằng phần cứng khá khiêm tốn. Việc sử dụng I/O của CPU và đĩa cũng rất ấn tượng. Ví dụ của tôi hiển thị tới 200 số liệu mỗi giây cho mỗi lõi được sử dụng.

Để lập kế hoạch mở rộng, bạn cần nhớ lượng bộ nhớ vừa đủ và đây phải là bộ nhớ thực. Dung lượng bộ nhớ được sử dụng mà tôi quan sát được là khoảng 5 GB trên 100 bản ghi mỗi giây của luồng đến, cùng với bộ đệm của hệ điều hành đã tạo ra khoảng 000 GB bộ nhớ bị chiếm dụng.

Tất nhiên, vẫn còn rất nhiều việc phải làm để hạn chế sự tăng đột biến của CPU và I/O đĩa, và điều này không có gì đáng ngạc nhiên khi so sánh TSDB Prometheus 2 non trẻ với InnoDB, TokuDB, RocksDB, WiredTiger, nhưng tất cả chúng đều có những điểm tương tự. vấn đề sớm trong vòng đời.

Nguồn: www.habr.com

Thêm một lời nhận xét