
Ngày nay, không thể tưởng tượng một dự án dựa trên Kubernetes mà không có ngăn xếp ELK, giúp lưu nhật ký của cả ứng dụng và thành phần hệ thống của cụm. Trong thực tế, chúng tôi sử dụng ngăn xếp EFK với Fluentd thay vì Logstash.
Fluentd là một trình thu thập nhật ký phổ quát, hiện đại đang ngày càng trở nên phổ biến và đã tham gia Tổ chức Điện toán Đám mây, đó là lý do tại sao vectơ phát triển của nó tập trung vào việc sử dụng cùng với Kubernetes.
Việc sử dụng Fluentd thay vì Logstash không làm thay đổi bản chất chung của gói phần mềm, tuy nhiên, Fluentd được đặc trưng bởi các sắc thái riêng do tính linh hoạt của nó.
Ví dụ: khi chúng tôi bắt đầu sử dụng EFK trong một dự án bận rộn với cường độ ghi nhật ký cao, chúng tôi phải đối mặt với thực tế là ở Kibana một số thông báo được hiển thị lặp đi lặp lại nhiều lần. Trong bài viết này, chúng tôi sẽ cho bạn biết lý do tại sao hiện tượng này xảy ra và cách giải quyết vấn đề.
Vấn đề sao chép tài liệu
Trong các dự án của chúng tôi, Fluentd được triển khai dưới dạng DaemonSet (tự động khởi chạy trong một phiên bản trên mỗi nút của cụm Kubernetes) và giám sát nhật ký vùng chứa thiết bị xuất chuẩn trong /var/log/containers. Sau khi thu thập và xử lý, nhật ký ở dạng tài liệu JSON sẽ được gửi đến ElasticSearch, được nâng lên ở dạng cụm hoặc dạng độc lập, tùy thuộc vào quy mô của dự án cũng như các yêu cầu về hiệu suất và khả năng chịu lỗi. Kibana được sử dụng làm giao diện đồ họa.
Khi sử dụng Fluentd với plugin đệm đầu ra, chúng tôi đã gặp phải tình huống trong đó một số tài liệu trong ElasticSearch có nội dung giống hệt nhau và chỉ khác nhau ở mã nhận dạng. Bạn có thể xác minh rằng đây là sự lặp lại thông báo bằng cách sử dụng nhật ký Nginx làm ví dụ. Trong tệp nhật ký, thông báo này tồn tại trong một bản sao duy nhất:
127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -Tuy nhiên, có một số tài liệu trong ElasticSearch có chứa thông báo này:
{
"_index": "test-custom-prod-example-2020.01.02",
"_type": "_doc",
"_id": "HgGl_nIBR8C-2_33RlQV",
"_version": 1,
"_score": 0,
"_source": {
"service": "test-custom-prod-example",
"container_name": "nginx",
"namespace": "test-prod",
"@timestamp": "2020-01-14T05:29:47.599052886 00:00",
"log": "127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -",
"tag": "custom-log"
}
}
{
"_index": "test-custom-prod-example-2020.01.02",
"_type": "_doc",
"_id": "IgGm_nIBR8C-2_33e2ST",
"_version": 1,
"_score": 0,
"_source": {
"service": "test-custom-prod-example",
"container_name": "nginx",
"namespace": "test-prod",
"@timestamp": "2020-01-14T05:29:47.599052886 00:00",
"log": "127.0.0.1 192.168.0.1 - [28/Feb/2013:12:00:00 0900] "GET / HTTP/1.1" 200 777 "-" "Opera/12.0" -",
"tag": "custom-log"
}
}Hơn nữa, có thể có nhiều hơn hai lần lặp lại.
Trong khi khắc phục sự cố này trong nhật ký Fluentd, bạn có thể thấy một số lượng lớn cảnh báo có nội dung sau:
2020-01-16 01:46:46 +0000 [warn]: [test-prod] failed to flush the buffer. retry_time=4 next_retry_seconds=2020-01-16 01:46:53 +0000 chunk="59c37fc3fb320608692c352802b973ce" error_class=Fluent::Plugin::ElasticsearchOutput::RecoverableRequestFailure error="could not push logs to Elasticsearch cluster ({:host=>"elasticsearch", :port=>9200, :scheme=>"http", :user=>"elastic", :password=>"obfuscated"}): read timeout reached"Những cảnh báo này xảy ra khi ElasticSearch không thể trả về phản hồi cho một yêu cầu trong khoảng thời gian được chỉ định bởi tham số request_timeout, đó là lý do tại sao không thể xóa đoạn bộ đệm được chuyển tiếp. Sau đó, Fluentd cố gắng gửi lại đoạn bộ đệm tới ElasticSearch và sau một số lần thử tùy ý, thao tác sẽ hoàn tất thành công:
2020-01-16 01:47:05 +0000 [warn]: [test-prod] retry succeeded. chunk_id="59c37fc3fb320608692c352802b973ce"
2020-01-16 01:47:05 +0000 [warn]: [test-prod] retry succeeded. chunk_id="59c37fad241ab300518b936e27200747"
2020-01-16 01:47:05 +0000 [warn]: [test-dev] retry succeeded. chunk_id="59c37fc11f7ab707ca5de72a88321cc2"
2020-01-16 01:47:05 +0000 [warn]: [test-dev] retry succeeded. chunk_id="59c37fb5adb70c06e649d8c108318c9b"
2020-01-16 01:47:15 +0000 [warn]: [kube-system] retry succeeded. chunk_id="59c37f63a9046e6dff7e9987729be66f"Tuy nhiên, ElasticSearch coi mỗi đoạn bộ đệm được chuyển là duy nhất và gán cho chúng các giá trị trường _id duy nhất trong quá trình lập chỉ mục. Đây là cách bản sao của tin nhắn xuất hiện.
Ở Kibana nó trông như thế này:

Các giải pháp
Có một số lựa chọn để giải quyết vấn đề này. Một trong số đó là cơ chế được tích hợp trong plugin Fluent-plugin-elasticsearch để tạo hàm băm duy nhất cho mỗi tài liệu. Nếu bạn sử dụng cơ chế này, ElasticSearch sẽ nhận ra các lần lặp lại ở giai đoạn chuyển tiếp và ngăn chặn các tài liệu trùng lặp. Nhưng chúng tôi phải lưu ý rằng phương pháp giải quyết vấn đề này gặp khó khăn trong quá trình điều tra và không loại bỏ được lỗi thiếu thời gian chờ, vì vậy chúng tôi đã từ bỏ việc sử dụng nó.
Chúng tôi sử dụng plugin đệm trên đầu ra Fluentd để tránh mất nhật ký trong trường hợp xảy ra sự cố mạng ngắn hạn hoặc cường độ ghi nhật ký tăng. Nếu vì lý do nào đó ElasticSearch không thể ghi tài liệu ngay vào chỉ mục thì tài liệu sẽ được xếp hàng đợi và lưu trữ trên đĩa. Do đó, trong trường hợp của chúng tôi, để loại bỏ nguồn gốc của sự cố dẫn đến lỗi được mô tả ở trên, cần thiết lập các giá trị chính xác cho các tham số bộ đệm, tại đó bộ đệm đầu ra Fluentd sẽ có kích thước đủ và đồng thời giải quyết xong trong thời gian quy định.
Điều đáng chú ý là giá trị của các tham số được thảo luận bên dưới là riêng lẻ trong từng trường hợp cụ thể của việc sử dụng bộ đệm trong plugin đầu ra, vì chúng phụ thuộc vào nhiều yếu tố: cường độ ghi tin nhắn vào nhật ký theo dịch vụ, hiệu suất hệ thống đĩa, mạng tải kênh và băng thông của nó. Do đó, để có được các cài đặt bộ đệm phù hợp với từng trường hợp riêng lẻ nhưng không dư thừa, tránh việc tìm kiếm dài dòng một cách mù quáng, bạn có thể sử dụng thông tin gỡ lỗi mà Fluentd ghi vào nhật ký của nó trong quá trình hoạt động và tương đối nhanh chóng nhận được các giá trị chính xác.
Vào thời điểm sự cố được ghi lại, cấu hình trông như thế này:
<buffer>
@type file
path /var/log/fluentd-buffers/kubernetes.test.buffer
flush_mode interval
retry_type exponential_backoff
flush_thread_count 2
flush_interval 5s
retry_forever
retry_max_interval 30
chunk_limit_size 8M
queue_limit_length 8
overflow_action block
</buffer>Khi giải quyết vấn đề, các giá trị của các tham số sau đã được chọn thủ công:
chunk_limit_size - kích thước của các khối mà thông điệp trong bộ đệm được chia thành.
- Flush_interval - khoảng thời gian sau đó bộ đệm sẽ bị xóa.
- queue_limit_length - số lượng khối tối đa trong hàng đợi.
- request_timeout là thời điểm thiết lập kết nối giữa Fluentd và ElasticSearch.
Tổng kích thước bộ đệm có thể được tính bằng cách nhân các tham số queue_limit_length và chunk_limit_size, có thể được hiểu là “số lượng khối tối đa trong hàng đợi, mỗi khối có một kích thước nhất định”. Nếu kích thước bộ đệm không đủ, cảnh báo sau sẽ xuất hiện trong nhật ký:
2020-01-21 10:22:57 +0000 [warn]: [test-prod] failed to write data into buffer by buffer overflow action=:blockCó nghĩa là bộ đệm không có thời gian để xóa trong thời gian quy định và dữ liệu vào bộ đệm đầy sẽ bị chặn, dẫn đến mất một phần nhật ký.
Bạn có thể tăng bộ đệm theo hai cách: bằng cách tăng kích thước của từng đoạn trong hàng đợi hoặc số lượng đoạn có thể có trong hàng đợi.
Nếu bạn đặt kích thước chunk chunk_limit_size lớn hơn 32 megabyte thì ElasticSeacrh sẽ không chấp nhận vì gói đến sẽ quá lớn. Vì vậy, nếu bạn cần tăng thêm bộ đệm, tốt hơn hết bạn nên tăng độ dài hàng đợi tối đa queue_limit_length.
Khi bộ đệm ngừng tràn và chỉ còn lại thông báo hết thời gian chờ, bạn có thể bắt đầu tăng tham số request_timeout. Tuy nhiên, nếu bạn đặt giá trị lớn hơn 20 giây, các cảnh báo sau sẽ bắt đầu xuất hiện trong nhật ký Fluentd:
2020-01-21 09:55:33 +0000 [warn]: [test-dev] buffer flush took longer time than slow_flush_log_threshold: elapsed_time=20.85753920301795 slow_flush_log_threshold=20.0 plugin_id="postgresql-dev" Thông báo này không ảnh hưởng đến hoạt động của hệ thống dưới bất kỳ hình thức nào và có nghĩa là thời gian xóa bộ đệm mất nhiều thời gian hơn do tham số Slow_flush_log_threshold thiết lập. Đây là thông tin gỡ lỗi và chúng tôi sử dụng nó khi chọn giá trị của tham số request_timeout.
Thuật toán lựa chọn tổng quát như sau:
- Đặt request_timeout thành giá trị được đảm bảo lớn hơn mức cần thiết (hàng trăm giây). Trong quá trình thiết lập, tiêu chí chính để cài đặt chính xác tham số này sẽ là sự biến mất của các cảnh báo về việc thiếu thời gian chờ.
- Đợi thông báo về việc vượt quá ngưỡng Slow_flush_log_threshold. Văn bản cảnh báo trong trường elapsed_time sẽ hiển thị thời gian thực bộ đệm đã bị xóa.
- Đặt request_timeout thành giá trị lớn hơn giá trị elapsed_time tối đa thu được trong khoảng thời gian quan sát. Chúng tôi tính giá trị request_timeout là elapsed_time + 50%.
- Để xóa cảnh báo về việc xóa bộ đệm dài khỏi nhật ký, bạn có thể tăng giá trị của Slow_flush_log_threshold. Chúng tôi tính giá trị này là elapsed_time + 25%.
Giá trị cuối cùng của các tham số này, như đã lưu ý trước đó, được lấy riêng cho từng trường hợp. Bằng cách làm theo thuật toán trên, chúng tôi đảm bảo sẽ loại bỏ lỗi dẫn đến các tin nhắn lặp lại.
Bảng dưới đây cho thấy số lượng lỗi mỗi ngày, dẫn đến sự trùng lặp của thông báo, thay đổi trong quá trình chọn giá trị của các tham số được mô tả ở trên:
nút-1
nút-2
nút-3
nút-4
Trước sau
Trước sau
Trước sau
Trước sau
không thể xóa bộ đệm
1749/2
694/2
47/0
1121/2
thử lại thành công
410/2
205/1
24/0
241/2
Cũng cần lưu ý rằng cài đặt kết quả có thể mất đi mức độ liên quan khi dự án phát triển và theo đó, số lượng nhật ký sẽ tăng lên. Dấu hiệu chính của việc không đủ thời gian chờ là việc trả lại các thông báo về quá trình xóa bộ đệm dài vào nhật ký Fluentd, nghĩa là vượt quá ngưỡng Slow_flush_log_threshold. Từ thời điểm này trở đi, vẫn còn một khoảng cách nhỏ trước khi vượt quá tham số request_timeout, do đó cần phải phản hồi kịp thời các thông báo này và lặp lại quá trình chọn cài đặt tối ưu được mô tả ở trên.
Kết luận
Tinh chỉnh bộ đệm đầu ra Fluentd là một trong những giai đoạn chính của việc định cấu hình ngăn xếp EFK, xác định tính ổn định trong hoạt động của nó và vị trí chính xác của tài liệu trong các chỉ mục. Dựa trên thuật toán cấu hình được mô tả, bạn có thể chắc chắn rằng tất cả nhật ký sẽ được ghi vào chỉ mục ElasticSearch theo đúng thứ tự, không bị lặp lại hoặc bị mất.
Cũng đọc các bài viết khác trên blog của chúng tôi:
Nguồn: www.habr.com
