Tìm kiếm ở tốc độ 1 TB/s

TL;DR: Bốn năm trước, tôi rời Google với ý tưởng về một công cụ giám sát máy chủ mới. Ý tưởng là kết hợp các chức năng thường bị cô lập thành một dịch vụ thu thập và phân tích nhật ký, thu thập số liệu, cảnh báo và bảng điều khiển. Một trong những nguyên tắc là dịch vụ phải thực sự Nhanh, cung cấp cho các nhà phát triển trải nghiệm thú vị, tương tác và dễ dàng. Điều này yêu cầu xử lý các tập dữ liệu nhiều gigabyte theo phân số của giây trong khi vẫn nằm trong ngân sách. Các công cụ quản lý nhật ký hiện tại thường chậm và cồng kềnh, vì vậy chúng tôi đã phải đối mặt với một thách thức lớn: thiết kế một công cụ thông minh để mang đến cho người dùng trải nghiệm mới.

Bài viết này mô tả cách chúng tôi tại Scalyr giải quyết vấn đề này bằng cách áp dụng các phương pháp cũ, phương pháp tiếp cận mạnh mẽ, loại bỏ các lớp không cần thiết và tránh các cấu trúc dữ liệu phức tạp. Bạn có thể áp dụng những bài học này cho các vấn đề kỹ thuật của riêng bạn.

Sức mạnh trường học cũ

Phân tích nhật ký thường bắt đầu bằng việc tìm kiếm: tìm tất cả các tin nhắn khớp với một mẫu nhất định. Trong Scalyr, đây là hàng chục hoặc hàng trăm gigabyte nhật ký từ nhiều máy chủ. Các phương pháp tiếp cận hiện đại, theo quy luật, liên quan đến việc xây dựng một số cấu trúc dữ liệu phức tạp được tối ưu hóa cho tìm kiếm. Tôi chắc chắn đã thấy điều này trên Google, nơi họ khá giỏi về những thứ này. Nhưng chúng tôi đã quyết định bằng một cách tiếp cận thô sơ hơn nhiều: quét tuyến tính các bản ghi. Và nó đã hoạt động - chúng tôi cung cấp một giao diện có thể tìm kiếm nhanh hơn nhiều so với các đối thủ cạnh tranh (xem hoạt ảnh ở cuối).

Cái nhìn sâu sắc quan trọng là các bộ xử lý hiện đại thực sự rất nhanh trong các hoạt động đơn giản, dễ hiểu. Điều này rất dễ bị bỏ sót trong các hệ thống phức tạp, nhiều lớp dựa vào tốc độ I/O và hoạt động mạng và những hệ thống như vậy ngày nay rất phổ biến. Vì vậy, chúng tôi đã phát triển một thiết kế giúp giảm thiểu các lớp và mảnh vụn dư thừa. Với nhiều bộ xử lý và máy chủ song song, tốc độ tìm kiếm đạt 1 TB mỗi giây.

Những điểm chính rút ra từ bài viết này:

  • Tìm kiếm Brute-force là một cách tiếp cận khả thi để giải quyết các vấn đề quy mô lớn, trong thế giới thực.
  • Brute Force là một kỹ thuật thiết kế, không phải là một giải pháp không cần làm việc. Giống như bất kỳ kỹ thuật nào, nó phù hợp với một số vấn đề hơn những vấn đề khác và có thể được thực hiện tốt hoặc kém.
  • Bạo lực đặc biệt tốt để đạt được ổn định năng suất.
  • Việc sử dụng hiệu quả vũ lực đòi hỏi phải tối ưu hóa mã và áp dụng đủ tài nguyên vào đúng thời điểm. Nó phù hợp nếu máy chủ của bạn chịu tải nặng không phải của người dùng và hoạt động của người dùng vẫn được ưu tiên.
  • Hiệu suất phụ thuộc vào thiết kế của toàn bộ hệ thống, không chỉ thuật toán vòng lặp bên trong.

(Bài viết này mô tả việc tìm kiếm dữ liệu trong bộ nhớ. Trong hầu hết các trường hợp, khi người dùng thực hiện tìm kiếm nhật ký, máy chủ Scalyr đã lưu nó vào bộ nhớ đệm. Bài viết tiếp theo sẽ thảo luận về việc tìm kiếm nhật ký không được lưu trong bộ nhớ đệm. Các nguyên tắc tương tự cũng được áp dụng: mã hiệu quả, bạo lực với tài nguyên tính toán lớn).

Phương pháp vũ phu

Theo truyền thống, một tập dữ liệu lớn được tìm kiếm bằng chỉ mục từ khóa. Khi áp dụng cho nhật ký máy chủ, điều này có nghĩa là tìm kiếm mọi từ duy nhất trong nhật ký. Đối với mỗi từ, bạn cần lập danh sách tất cả các từ bao gồm. Điều này giúp bạn dễ dàng tìm thấy tất cả thư có từ này, ví dụ: 'error', 'firefox' hoặc "transaction_16851951" - chỉ cần tìm trong chỉ mục.

Tôi đã sử dụng phương pháp này tại Google và nó hoạt động rất tốt. Nhưng trong Scalyr, chúng tôi tìm kiếm nhật ký theo byte.

Tại sao? Từ quan điểm thuật toán trừu tượng, chỉ mục từ khóa hiệu quả hơn nhiều so với tìm kiếm vũ phu. Tuy nhiên, chúng tôi không bán thuật toán, chúng tôi bán hiệu suất. Và hiệu suất không chỉ liên quan đến thuật toán mà còn liên quan đến kỹ thuật hệ thống. Chúng ta phải xem xét mọi thứ: khối lượng dữ liệu, loại tìm kiếm, bối cảnh phần cứng và phần mềm có sẵn. Chúng tôi quyết định rằng đối với vấn đề cụ thể của mình, thứ gì đó như 'grep' phù hợp hơn chỉ mục.

Các chỉ mục rất tuyệt vời nhưng chúng có những hạn chế. Một từ rất dễ tìm. Nhưng việc tìm kiếm thư có nhiều từ, chẳng hạn như 'googlebot' và '404', khó khăn hơn nhiều. Việc tìm kiếm một cụm từ như 'ngoại lệ chưa được phát hiện' yêu cầu một chỉ mục phức tạp hơn, ghi lại không chỉ tất cả các tin nhắn có từ đó mà còn cả vị trí cụ thể của từ đó.

Khó khăn thực sự đến khi bạn không tìm kiếm từ ngữ. Giả sử bạn muốn xem lưu lượng truy cập đến từ bot là bao nhiêu. Ý nghĩ đầu tiên là tìm kiếm từ 'bot' trong nhật ký. Đây là cách bạn sẽ tìm thấy một số bot: Googlebot, Bingbot và nhiều bot khác. Nhưng ở đây 'bot' không phải là một từ mà là một phần của nó. Nếu chúng tôi tìm kiếm 'bot' trong chỉ mục, chúng tôi sẽ không tìm thấy bất kỳ bài đăng nào có từ 'Googlebot'. Nếu bạn kiểm tra từng từ trong chỉ mục rồi quét chỉ mục để tìm các từ khóa tìm thấy thì quá trình tìm kiếm sẽ chậm lại rất nhiều. Kết quả là, một số chương trình ghi nhật ký không cho phép tìm kiếm từng phần từ hoặc (tốt nhất) cho phép cú pháp đặc biệt với hiệu suất thấp hơn. Chúng tôi muốn tránh điều này.

Một vấn đề khác là dấu câu. Bạn có muốn tìm tất cả các yêu cầu từ 50.168.29.7? Còn nhật ký gỡ lỗi có chứa [error]? Chỉ số dưới thường bỏ qua dấu câu.

Cuối cùng, các kỹ sư yêu thích các công cụ mạnh mẽ và đôi khi một vấn đề chỉ có thể được giải quyết bằng biểu thức chính quy. Chỉ mục từ khóa không phù hợp lắm cho việc này.

Ngoài ra, các chỉ số tổ hợp. Mỗi tin nhắn cần được thêm vào một số danh sách từ khóa. Các danh sách này phải luôn được giữ ở định dạng dễ tìm kiếm. Các truy vấn có cụm từ, đoạn từ hoặc cụm từ thông dụng cần được dịch sang các thao tác nhiều danh sách, đồng thời quét và kết hợp các kết quả để tạo ra tập kết quả. Trong bối cảnh dịch vụ có quy mô lớn, nhiều người thuê, sự phức tạp này tạo ra các vấn đề về hiệu suất mà không thể thấy được khi phân tích các thuật toán.

Các chỉ mục từ khóa cũng chiếm nhiều dung lượng và việc lưu trữ là một chi phí lớn trong hệ thống quản lý nhật ký.

Mặt khác, mỗi lần tìm kiếm có thể tiêu tốn rất nhiều sức mạnh tính toán. Người dùng của chúng tôi đánh giá cao các tìm kiếm tốc độ cao cho các truy vấn độc đáo, nhưng các truy vấn như vậy tương đối hiếm khi được thực hiện. Đối với các truy vấn tìm kiếm thông thường, chẳng hạn như đối với trang tổng quan, chúng tôi sử dụng các kỹ thuật đặc biệt (chúng tôi sẽ mô tả chúng trong bài viết tiếp theo). Các yêu cầu khác không thường xuyên nên bạn hiếm khi phải xử lý nhiều yêu cầu cùng một lúc. Nhưng điều này không có nghĩa là máy chủ của chúng tôi không bận: chúng bận với công việc nhận, phân tích và nén tin nhắn mới, đánh giá cảnh báo, nén dữ liệu cũ, v.v. Vì vậy, chúng tôi có một nguồn cung cấp bộ xử lý khá đáng kể có thể được sử dụng để thực hiện các truy vấn.

Bạo lực có tác dụng nếu bạn gặp vấn đề về bạo lực (và nhiều sức mạnh)

Lực lượng vũ phu hoạt động tốt nhất trên các vấn đề đơn giản với các vòng lặp bên trong nhỏ. Thường thì bạn có thể tối ưu hóa vòng lặp bên trong để chạy ở tốc độ rất cao. Nếu mã phức tạp thì việc tối ưu hóa nó sẽ khó khăn hơn nhiều.

Mã tìm kiếm của chúng tôi ban đầu có vòng lặp bên trong khá lớn. Chúng tôi lưu trữ tin nhắn trên các trang ở độ phân giải 4K; mỗi trang chứa một số tin nhắn (ở dạng UTF-8) và siêu dữ liệu cho mỗi tin nhắn. Siêu dữ liệu là cấu trúc mã hóa độ dài của giá trị, ID thông báo nội bộ và các trường khác. Chu trình tìm kiếm trông như thế này:

Tìm kiếm ở tốc độ 1 TB/s

Đây là phiên bản đơn giản của mã thực tế. Nhưng ngay cả ở đây, nhiều vị trí đối tượng, bản sao dữ liệu và lệnh gọi hàm vẫn hiển thị. JVM khá giỏi trong việc tối ưu hóa các lệnh gọi hàm và phân bổ các đối tượng tạm thời, vì vậy mã này hoạt động tốt hơn mức chúng tôi mong đợi. Trong quá trình thử nghiệm, khách hàng đã sử dụng khá thành công. Nhưng cuối cùng chúng tôi đã đưa nó lên một tầm cao mới.

(Bạn có thể hỏi tại sao chúng tôi lưu trữ tin nhắn ở định dạng này với các trang 4K, văn bản và siêu dữ liệu thay vì làm việc trực tiếp với nhật ký. Có nhiều lý do dẫn đến thực tế là bên trong công cụ Scalyr giống một cơ sở dữ liệu phân tán hơn là một cơ sở dữ liệu phân tán. tìm kiếm văn bản thường được kết hợp với các bộ lọc kiểu DBMS ở lề sau khi phân tích nhật ký. Chúng tôi có thể tìm kiếm đồng thời nhiều nghìn nhật ký cùng một lúc và các tệp văn bản đơn giản không phù hợp cho việc quản lý dữ liệu phân tán, sao chép, giao dịch của chúng tôi).

Ban đầu, có vẻ như mã như vậy không phù hợp lắm cho việc tối ưu hóa vũ lực. "Công việc thực sự" ở String.indexOf() thậm chí còn không chiếm ưu thế trong hồ sơ CPU. Nghĩa là, chỉ tối ưu hóa phương pháp này sẽ không mang lại hiệu quả đáng kể.

Điều đó xảy ra là chúng tôi lưu trữ siêu dữ liệu ở đầu mỗi trang và văn bản của tất cả thư bằng UTF-8 được đóng gói ở đầu bên kia. Lợi dụng điều này, chúng tôi viết lại vòng lặp để tìm kiếm toàn bộ trang cùng một lúc:

Tìm kiếm ở tốc độ 1 TB/s

Phiên bản này hoạt động trực tiếp trên chế độ xem raw byte[] và tìm kiếm tất cả tin nhắn cùng một lúc trên toàn bộ trang 4K.

Điều này dễ dàng hơn nhiều để tối ưu hóa cho phương pháp vũ phu. Vòng tìm kiếm nội bộ được gọi đồng thời cho toàn bộ trang 4K, thay vì riêng biệt trên mỗi bài đăng. Không có sự sao chép dữ liệu, không có sự phân bổ đối tượng. Và các thao tác siêu dữ liệu phức tạp hơn chỉ được gọi khi kết quả dương tính chứ không phải trên mọi tin nhắn. Bằng cách này, chúng tôi đã loại bỏ rất nhiều chi phí và phần tải còn lại được tập trung vào một vòng tìm kiếm nội bộ nhỏ, rất phù hợp để tối ưu hóa thêm.

Thuật toán tìm kiếm thực tế của chúng tôi dựa trên ý tưởng tuyệt vời của Leonid Volnitsky. Nó tương tự như thuật toán Boyer-Moore, bỏ qua độ dài của chuỗi tìm kiếm ở mỗi bước. Sự khác biệt chính là nó kiểm tra hai byte cùng một lúc để giảm thiểu các kết quả khớp sai.

Việc triển khai của chúng tôi yêu cầu tạo bảng tra cứu 64K cho mỗi tìm kiếm, nhưng điều đó không là gì so với hàng gigabyte dữ liệu mà chúng tôi đang tìm kiếm. Vòng lặp bên trong xử lý vài gigabyte mỗi giây trên một lõi. Trong thực tế, hiệu suất ổn định là khoảng 1,25 GB mỗi giây trên mỗi lõi và vẫn còn chỗ để cải thiện. Có thể loại bỏ một số chi phí bên ngoài vòng lặp bên trong và chúng tôi dự định thử nghiệm vòng lặp bên trong trong C thay vì Java.

Chúng tôi sử dụng vũ lực

Chúng ta đã thảo luận rằng việc tìm kiếm nhật ký có thể được thực hiện một cách "đại khái", nhưng chúng ta có bao nhiêu "sức mạnh"? Khá nhiều.

1 lõi: Khi được sử dụng đúng cách, lõi đơn của bộ xử lý hiện đại sẽ khá mạnh mẽ theo đúng nghĩa của nó.

8 lõi: Chúng tôi hiện đang chạy trên các máy chủ SSD Amazon hi1.4xlarge và i2.4xlarge, mỗi máy chủ có 8 lõi (16 luồng). Như đã đề cập ở trên, các lõi này thường bận rộn với các hoạt động ở chế độ nền. Khi người dùng thực hiện tìm kiếm, các thao tác nền sẽ bị tạm dừng, giải phóng toàn bộ 8 lõi cho tìm kiếm. Việc tìm kiếm thường hoàn thành trong tích tắc, sau đó công việc nền sẽ tiếp tục lại (chương trình điều chỉnh đảm bảo rằng hàng loạt truy vấn tìm kiếm không ảnh hưởng đến công việc nền quan trọng).

16 lõi: để đảm bảo độ tin cậy, chúng tôi tổ chức các máy chủ thành các nhóm chính/phụ. Mỗi chủ có một ổ SSD và một máy chủ EBS dưới quyền chỉ huy của mình. Nếu máy chủ chính gặp sự cố, máy chủ SSD sẽ ngay lập tức thay thế. Hầu như mọi lúc, chủ và phụ đều hoạt động tốt, do đó mỗi khối dữ liệu có thể tìm kiếm được trên hai máy chủ khác nhau (máy chủ phụ EBS có bộ xử lý yếu nên chúng tôi không xem xét điều đó). Chúng tôi phân chia nhiệm vụ giữa chúng để có tổng cộng 16 lõi.

Nhiều lõi: Trong tương lai gần, chúng tôi sẽ phân phối dữ liệu trên các máy chủ theo cách mà tất cả chúng đều tham gia xử lý mọi yêu cầu không hề nhỏ. Mọi lõi sẽ hoạt động. [Ghi chú: chúng tôi đã triển khai kế hoạch và tăng tốc độ tìm kiếm lên 1 TB/s, xem ghi chú cuối bài].

Sự đơn giản đảm bảo độ tin cậy

Một ưu điểm khác của phương pháp vũ lực là hiệu suất khá ổn định của nó. Thông thường, tìm kiếm không nhạy cảm lắm với các chi tiết của vấn đề và tập dữ liệu (tôi đoán đó là lý do tại sao nó được gọi là "thô").

Chỉ mục từ khóa đôi khi tạo ra kết quả cực kỳ nhanh và đôi khi thì không. Giả sử bạn có 50 GB nhật ký trong đó cụm từ 'customer_5987235982' xuất hiện đúng ba lần. Việc tìm kiếm cụm từ này sẽ tính ba vị trí trực tiếp từ chỉ mục và sẽ hoàn tất ngay lập tức. Nhưng các tìm kiếm ký tự đại diện phức tạp có thể quét hàng nghìn từ khóa và mất nhiều thời gian.

Mặt khác, các tìm kiếm mạnh mẽ thực hiện ở tốc độ ít nhiều giống nhau cho bất kỳ truy vấn nào. Tìm kiếm các từ dài thì tốt hơn, nhưng ngay cả việc tìm kiếm một ký tự cũng khá nhanh.

Sự đơn giản của phương pháp vũ lực có nghĩa là hiệu suất của nó gần đạt mức tối đa về mặt lý thuyết. Có ít tùy chọn hơn cho tình trạng quá tải ổ đĩa không mong muốn, tranh chấp khóa, đuổi theo con trỏ và hàng nghìn lý do dẫn đến lỗi khác. Tôi vừa xem xét các yêu cầu do người dùng Scalyr đưa ra vào tuần trước trên máy chủ bận rộn nhất của chúng tôi. Đã có 14 yêu cầu. Chính xác tám trong số đó mất hơn một giây; Hoàn thành 000% trong vòng 99 mili giây (nếu bạn chưa sử dụng các công cụ phân tích nhật ký, hãy tin tôi: nó nhanh).

Hiệu suất ổn định, đáng tin cậy là điều quan trọng để dễ dàng sử dụng dịch vụ. Nếu nó bị lag định kỳ, người dùng sẽ cho rằng nó không đáng tin cậy và không muốn sử dụng nó.

Đăng nhập tìm kiếm đang hoạt động

Đây là một đoạn phim hoạt hình ngắn thể hiện hoạt động tìm kiếm Scalyr. Chúng tôi có một tài khoản demo nơi chúng tôi nhập mọi sự kiện vào mọi kho lưu trữ Github công khai. Trong bản demo này, tôi kiểm tra giá trị dữ liệu của một tuần: khoảng 600 MB nhật ký thô.

Video được ghi trực tiếp mà không cần chuẩn bị đặc biệt trên máy tính để bàn của tôi (cách máy chủ khoảng 5000 km). Hiệu suất bạn sẽ thấy phần lớn là do tối ưu hóa máy khách web, cũng như một chương trình phụ trợ nhanh chóng và đáng tin cậy. Bất cứ khi nào có phần tạm dừng mà không có chỉ báo 'đang tải', đó là tôi tạm dừng để bạn có thể đọc nội dung tôi sắp nhấn.

Tìm kiếm ở tốc độ 1 TB/s

Kết luận

Khi xử lý lượng lớn dữ liệu, điều quan trọng là phải chọn thuật toán tốt, nhưng “tốt” không có nghĩa là “sang trọng”. Hãy suy nghĩ về cách mã của bạn sẽ hoạt động trong thực tế. Việc phân tích lý thuyết các thuật toán đã loại bỏ một số yếu tố có thể có tầm quan trọng lớn trong thế giới thực. Các thuật toán đơn giản hơn sẽ dễ tối ưu hóa hơn và ổn định hơn trong các tình huống khó khăn.

Ngoài ra, hãy suy nghĩ về bối cảnh mà mã sẽ được thực thi. Trong trường hợp của chúng tôi, chúng tôi cần các máy chủ đủ mạnh để quản lý các tác vụ nền. Người dùng bắt đầu tìm kiếm tương đối không thường xuyên, vì vậy chúng tôi có thể mượn toàn bộ nhóm máy chủ trong khoảng thời gian ngắn cần thiết để hoàn thành mỗi tìm kiếm.

Bằng cách sử dụng phương pháp bạo lực, chúng tôi đã triển khai tìm kiếm nhanh chóng, đáng tin cậy, linh hoạt trên một tập hợp nhật ký. Chúng tôi hy vọng những ý tưởng này hữu ích cho dự án của bạn.

Biên tập: Tiêu đề và văn bản đã thay đổi từ "Tìm kiếm ở tốc độ 20 GB mỗi giây" thành "Tìm kiếm ở tốc độ 1 TB mỗi giây" để phản ánh hiệu suất tăng lên trong vài năm qua. Sự gia tăng tốc độ này chủ yếu là do những thay đổi về loại và số lượng máy chủ EC2 mà chúng tôi đang triển khai hiện nay để phục vụ lượng khách hàng ngày càng tăng của mình. Sắp có những thay đổi sẽ mang lại sự gia tăng đáng kể khác về hiệu quả hoạt động và chúng tôi rất nóng lòng được chia sẻ chúng.

Nguồn: www.habr.com

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