Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Vì vậy, bạn thu thập số liệu. Như chúng ta vậy. Chúng tôi cũng thu thập số liệu. Tất nhiên là cần thiết cho việc kinh doanh. Hôm nay chúng ta sẽ nói về liên kết đầu tiên của hệ thống giám sát của chúng tôi - một máy chủ tổng hợp tương thích với statsd sinh học, tại sao chúng tôi viết nó và tại sao chúng tôi từ bỏ brubeck.

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Từ các bài viết trước của chúng tôi (1, 2) bạn có thể phát hiện ra điều đó cho đến một lúc nào đó chúng tôi đã thu thập thẻ bằng cách sử dụng Brubeck. Nó được viết bằng C. Từ quan điểm mã, nó đơn giản như một phích cắm (điều này rất quan trọng khi bạn muốn đóng góp) và quan trọng nhất là nó xử lý khối lượng 2 triệu số liệu mỗi giây (MPS) của chúng tôi ở mức cao nhất mà không có bất kỳ vấn đề. Tài liệu nêu rõ hỗ trợ 4 triệu MPS có dấu hoa thị. Điều này có nghĩa là bạn sẽ nhận được con số đã nêu nếu bạn định cấu hình mạng đúng trên Linux. (Chúng tôi không biết bạn có thể nhận được bao nhiêu MPS nếu rời khỏi mạng). Bất chấp những lợi thế này, chúng tôi vẫn có một số phàn nàn nghiêm trọng về món Brubeck.

Yêu cầu 1. Github, nhà phát triển dự án, đã ngừng hỗ trợ nó: xuất bản các bản vá và bản sửa lỗi, chấp nhận PR của chúng tôi và (không chỉ của chúng tôi). Trong vài tháng qua (khoảng từ tháng 2018 đến tháng 2 năm XNUMX), hoạt động đã tiếp tục trở lại, nhưng trước đó đã có gần XNUMX năm hoàn toàn yên tĩnh. Ngoài ra, dự án đang được phát triển cho nhu cầu nội bộ của Gihub, điều này có thể trở thành trở ngại nghiêm trọng cho việc giới thiệu các tính năng mới.

Yêu cầu 2. Độ chính xác của tính toán. Brubeck thu thập tổng cộng 65536 giá trị để tổng hợp. Trong trường hợp của chúng tôi, đối với một số chỉ số, trong khoảng thời gian tổng hợp (30 giây), nhiều giá trị hơn có thể đến (1 ở mức cao nhất). Kết quả của việc lấy mẫu này, các giá trị tối đa và tối thiểu dường như vô dụng. Ví dụ như thế này:

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng
Như nó đã từng

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng
Lẽ ra nó phải như thế nào

Vì lý do tương tự, số tiền thường được tính toán không chính xác. Thêm vào đây một lỗi tràn float 32-bit, lỗi này thường khiến máy chủ gặp lỗi phân tách khi nhận được một số liệu dường như vô hại và mọi thứ trở nên tuyệt vời. Nhân tiện, lỗi vẫn chưa được sửa.

Và cuối cùng, Yêu cầu X. Tại thời điểm viết bài, chúng tôi sẵn sàng giới thiệu nó cho tất cả 14 triển khai statsd hoạt động ít nhiều mà chúng tôi có thể tìm thấy. Hãy tưởng tượng rằng một số cơ sở hạ tầng đơn lẻ đã phát triển đến mức việc chấp nhận 4 triệu MPS là không còn đủ. Hoặc ngay cả khi nó chưa tăng trưởng, nhưng các số liệu đã quan trọng đối với bạn đến mức ngay cả những sự sụt giảm ngắn hạn, 2-3 phút trên biểu đồ cũng có thể trở nên nghiêm trọng và gây ra những cơn trầm cảm không thể vượt qua ở các nhà quản lý. Vì điều trị trầm cảm là một công việc vô ơn nên cần có các giải pháp kỹ thuật.

Thứ nhất, khả năng chịu lỗi, để một sự cố bất ngờ trên máy chủ không gây ra ngày tận thế zombie tâm thần trong văn phòng. Thứ hai, mở rộng quy mô để có thể chấp nhận hơn 4 triệu MPS mà không cần đào sâu vào ngăn xếp mạng Linux và bình tĩnh phát triển “theo chiều rộng” đến kích thước yêu cầu.

Vì chúng tôi có chỗ để mở rộng quy mô nên chúng tôi quyết định bắt đầu với khả năng chịu lỗi. "VỀ! Khả năng chịu lỗi! Thật đơn giản, chúng tôi có thể làm được,” chúng tôi nghĩ và ra mắt 2 máy chủ, tạo một bản sao brubeck trên mỗi máy chủ. Để làm điều này, chúng tôi phải sao chép lưu lượng truy cập có số liệu vào cả hai máy chủ và thậm chí viết cho việc này tiện ích nhỏ. Chúng tôi đã giải quyết được vấn đề về khả năng chịu lỗi bằng cách này, nhưng... không tốt lắm. Lúc đầu, mọi thứ có vẻ tuyệt vời: mỗi brubeck thu thập phiên bản tổng hợp của riêng mình, ghi dữ liệu vào Graphite 30 giây một lần, ghi đè khoảng thời gian cũ (điều này được thực hiện ở phía Graphite). Nếu một máy chủ đột nhiên bị lỗi, chúng tôi luôn có máy chủ thứ hai với bản sao dữ liệu tổng hợp của riêng nó. Nhưng đây là vấn đề: nếu máy chủ bị lỗi, một biểu tượng “cưa” sẽ xuất hiện trên biểu đồ. Điều này là do các khoảng thời gian 30 giây của brubeck không được đồng bộ hóa và tại thời điểm xảy ra sự cố, một trong số chúng không bị ghi đè. Khi máy chủ thứ hai khởi động, điều tương tự cũng xảy ra. Khá chấp nhận được, nhưng tôi muốn tốt hơn! Vấn đề về khả năng mở rộng cũng không biến mất. Tất cả các số liệu vẫn “bay” đến một máy chủ duy nhất và do đó chúng tôi bị giới hạn ở cùng 2-4 triệu MPS, tùy thuộc vào cấp độ mạng.

Nếu bạn suy nghĩ một chút về vấn đề và đồng thời đào tuyết bằng xẻng, thì bạn có thể nảy ra ý tưởng rõ ràng sau đây: bạn cần một statsd có thể hoạt động ở chế độ phân tán. Tức là thực hiện đồng bộ hóa giữa các nút về thời gian và số liệu. “Tất nhiên, giải pháp như vậy có thể đã tồn tại,” chúng tôi nói và tìm đến Google…. Và họ không tìm thấy gì cả. Sau khi xem qua tài liệu về các số liệu thống kê khác nhau (https://github.com/etsy/statsd/wiki#server-implementations kể từ ngày 11.12.2017 tháng XNUMX năm XNUMX), chúng tôi hoàn toàn không tìm thấy gì. Rõ ràng, cả nhà phát triển và người dùng các giải pháp này đều chưa gặp phải RẤT nhiều số liệu, nếu không họ chắc chắn sẽ nghĩ ra điều gì đó.

Và sau đó, chúng tôi nhớ về statsd “đồ chơi” - bioyino, được viết tại hackathon Just for Fun (tên của dự án được tạo theo kịch bản trước khi bắt đầu hackathon) và nhận ra rằng chúng tôi rất cần số liệu thống kê của riêng mình. Để làm gì?

  • bởi vì có quá ít bản sao statsd trên thế giới,
  • bởi vì có thể cung cấp khả năng mở rộng và khả năng mở rộng mong muốn hoặc gần với mức mong muốn (bao gồm đồng bộ hóa các số liệu tổng hợp giữa các máy chủ và giải quyết vấn đề gửi xung đột),
  • bởi vì có thể tính toán số liệu chính xác hơn Brubeck,
  • bởi vì bạn có thể tự mình thu thập số liệu thống kê chi tiết hơn, điều mà thực tế Brubeck không cung cấp cho chúng tôi,
  • bởi vì tôi đã có cơ hội lập trình ứng dụng phòng thí nghiệm quy mô phân tán siêu hiệu suất của riêng mình, ứng dụng này sẽ không lặp lại hoàn toàn kiến ​​trúc của một siêu máy tính tương tự khác... à, thế thôi.

Viết gì lên? Tất nhiên là ở Rust. Tại sao?

  • vì đã có giải pháp nguyên mẫu rồi,
  • bởi vì tác giả của bài báo đã biết đến Rust vào thời điểm đó và mong muốn viết thứ gì đó trong đó để sản xuất với cơ hội đưa nó vào nguồn mở,
  • bởi vì các ngôn ngữ có GC không phù hợp với chúng tôi do tính chất của lưu lượng truy cập nhận được (gần như theo thời gian thực) và việc tạm dừng GC trên thực tế là không thể chấp nhận được,
  • bởi vì bạn cần hiệu suất tối đa tương đương với C
  • bởi vì Rust cung cấp cho chúng ta khả năng xử lý đồng thời không sợ hãi và nếu chúng ta bắt đầu viết nó bằng C/C++, chúng ta sẽ gặp phải nhiều lỗ hổng hơn, lỗi tràn bộ đệm, điều kiện chạy đua và các từ đáng sợ khác hơn là brubeck.

Cũng có một lập luận chống lại Rust. Công ty không có kinh nghiệm tạo dự án trong Rust và hiện tại chúng tôi cũng không có kế hoạch sử dụng nó trong dự án chính. Vì vậy, có những lo ngại nghiêm trọng rằng sẽ không có kết quả gì, nhưng chúng tôi quyết định nắm lấy cơ hội và cố gắng.

Thời gian trôi qua...

Cuối cùng, sau nhiều lần thất bại, phiên bản hoạt động đầu tiên đã sẵn sàng. Chuyện gì đã xảy ra thế? Đây là những gì đã xảy ra.

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Mỗi nút nhận được bộ số liệu riêng và tích lũy chúng, đồng thời không tổng hợp số liệu cho những loại mà cần có bộ đầy đủ của chúng để tổng hợp cuối cùng. Các nút được kết nối với nhau bằng một số loại giao thức khóa phân tán, cho phép bạn chọn trong số chúng một giao thức duy nhất (ở đây chúng tôi đã kêu gọi) xứng đáng để gửi số liệu đến Great One. Vấn đề này hiện đang được giải quyết bởi Lãnh sự, nhưng trong tương lai tham vọng của tác giả sẽ mở rộng đến riêng thực hiện Raft, tất nhiên, nơi xứng đáng nhất sẽ là nút lãnh đạo đồng thuận. Ngoài sự đồng thuận, các nút khá thường xuyên (một lần mỗi giây theo mặc định) gửi cho các nút lân cận những phần của số liệu được tổng hợp trước mà chúng đã thu thập được trong giây đó. Hóa ra, khả năng mở rộng và khả năng chịu lỗi được giữ nguyên - mỗi nút vẫn giữ một bộ số liệu đầy đủ, nhưng các số liệu được gửi đã được tổng hợp, thông qua TCP và được mã hóa thành giao thức nhị phân, do đó chi phí trùng lặp giảm đáng kể so với UDP. Mặc dù số lượng chỉ số đến khá lớn nhưng việc tích lũy đòi hỏi rất ít bộ nhớ và thậm chí ít CPU hơn. Đối với số liệu có khả năng nén cao của chúng tôi, đây chỉ là vài chục megabyte dữ liệu. Là một phần thưởng bổ sung, chúng tôi không bị ghi lại dữ liệu không cần thiết trong Graphite, như trường hợp của burbeck.

Các gói UDP có số liệu không cân bằng giữa các nút trên thiết bị mạng thông qua Round Robin đơn giản. Tất nhiên, phần cứng mạng không phân tích nội dung của các gói và do đó có thể lấy nhiều hơn 4 triệu gói mỗi giây, chưa kể đến các số liệu mà nó không biết gì cả. Nếu chúng tôi tính đến việc các số liệu không xuất hiện lần lượt trong mỗi gói, thì chúng tôi không thấy trước bất kỳ vấn đề về hiệu suất nào ở nơi này. Nếu máy chủ gặp sự cố, thiết bị mạng sẽ nhanh chóng (trong vòng 1-2 giây) phát hiện thực tế này và loại bỏ máy chủ bị lỗi khỏi vòng quay. Do đó, các nút thụ động (tức là không dẫn đầu) có thể được bật và tắt một cách thực tế mà không nhận thấy sự sụt giảm trên biểu đồ. Số tiền tối đa chúng tôi mất là một phần của số liệu xuất hiện ở giây cuối cùng. Việc mất/tắt/chuyển đổi nút dẫn đầu đột ngột vẫn sẽ tạo ra sự bất thường nhỏ (khoảng thời gian 30 giây vẫn không đồng bộ), nhưng nếu có liên lạc giữa các nút, những vấn đề này có thể được giảm thiểu, chẳng hạn như bằng cách gửi các gói đồng bộ hóa .

Một chút về cấu trúc bên trong. Tất nhiên, ứng dụng này là đa luồng, nhưng kiến ​​trúc phân luồng khác với kiến ​​trúc được sử dụng trong brubeck. Các luồng trong brubeck đều giống nhau - mỗi luồng chịu trách nhiệm thu thập và tổng hợp thông tin. Trong bioyino, công nhân được chia thành hai nhóm: những người chịu trách nhiệm về mạng và những người chịu trách nhiệm tổng hợp. Bộ phận này cho phép bạn quản lý ứng dụng linh hoạt hơn tùy thuộc vào loại số liệu: nơi cần tổng hợp chuyên sâu, bạn có thể thêm bộ tổng hợp, nơi có nhiều lưu lượng mạng, bạn có thể thêm số lượng luồng mạng. Hiện tại, trên các máy chủ của chúng tôi, chúng tôi làm việc theo 8 mạng và 4 luồng tổng hợp.

Phần đếm (chịu trách nhiệm tổng hợp) khá nhàm chán. Bộ đệm được lấp đầy bởi các luồng mạng được phân phối giữa các luồng đếm, sau đó chúng được phân tích cú pháp và tổng hợp. Theo yêu cầu, số liệu được cung cấp để gửi đến các nút khác. Tất cả điều này, bao gồm việc gửi dữ liệu giữa các nút và làm việc với Consul, được thực hiện không đồng bộ, chạy trên framework Tokyo.

Nhiều vấn đề hơn trong quá trình phát triển là do phần mạng chịu trách nhiệm nhận số liệu gây ra. Mục tiêu chính của việc tách các luồng mạng thành các thực thể riêng biệt là mong muốn giảm thời gian mà một luồng sử dụng không để đọc dữ liệu từ socket. Các tùy chọn sử dụng UDP không đồng bộ và recvmsg thông thường nhanh chóng biến mất: tùy chọn đầu tiên tiêu tốn quá nhiều CPU không gian người dùng để xử lý sự kiện, tùy chọn thứ hai yêu cầu quá nhiều chuyển đổi ngữ cảnh. Vì vậy hiện nay nó được sử dụng recvmmsg với những khoảng đệm lớn (và những khoảng đệm, thưa các sĩ quan, chẳng là gì đối với bạn cả!). Hỗ trợ cho UDP thông thường được dành riêng cho các trường hợp nhẹ không cần recvmmsg. Ở chế độ đa tin nhắn, có thể đạt được điều chính: phần lớn thời gian, luồng mạng sẽ quét hàng đợi hệ điều hành - đọc dữ liệu từ ổ cắm và chuyển nó vào bộ đệm không gian người dùng, chỉ thỉnh thoảng chuyển sang cung cấp bộ đệm đã đầy cho các trình tổng hợp. Hàng đợi trong ổ cắm thực tế không tích lũy, số lượng gói bị rơi thực tế không tăng.

Ghi

Trong cài đặt mặc định, kích thước bộ đệm được đặt ở mức khá lớn. Nếu bạn đột nhiên quyết định tự mình dùng thử máy chủ, bạn có thể gặp phải thực tế là sau khi gửi một số lượng nhỏ số liệu, chúng sẽ không đến Graphite mà vẫn nằm trong bộ đệm luồng mạng. Để làm việc với một số lượng nhỏ số liệu, bạn cần đặt bufsize và task-queue-size thành các giá trị nhỏ hơn trong config.

Cuối cùng là một số biểu đồ dành cho những người yêu thích biểu đồ.

Thống kê số lượng số liệu đến cho mỗi máy chủ: hơn 2 triệu MPS.

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Vô hiệu hóa một trong các nút và phân phối lại các số liệu đến.

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Thống kê về số liệu gửi đi: chỉ có một nút luôn gửi - trùm đột kích.

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Thống kê hoạt động của từng nút, có tính đến các lỗi trong các mô-đun hệ thống khác nhau.

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Chi tiết các số liệu đến (tên số liệu bị ẩn).

Bioyino - công cụ tổng hợp số liệu phân tán, có thể mở rộng

Chúng ta dự định làm gì với tất cả những điều này tiếp theo? Tất nhiên là viết mã, chết tiệt...! Dự án ban đầu được lên kế hoạch là nguồn mở và sẽ duy trì như vậy trong suốt vòng đời của nó. Các kế hoạch trước mắt của chúng tôi bao gồm chuyển sang phiên bản Raft của riêng chúng tôi, thay đổi giao thức ngang hàng sang giao thức di động hơn, giới thiệu số liệu thống kê nội bộ bổ sung, các loại số liệu mới, sửa lỗi và các cải tiến khác.

Tất nhiên, mọi người đều được hoan nghênh giúp đỡ trong việc phát triển dự án: tạo PR, Các vấn đề, nếu có thể chúng tôi sẽ phản hồi, cải thiện, v.v.

Như đã nói, đó là tất cả các bạn, hãy mua voi của chúng tôi!



Nguồn: www.habr.com

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