Bugsnag gần đây đã thêm hỗ trợ xử lý các sự cố nhỏ để khách hàng có thể theo dõi các sự cố gốc trên Electron hoặc các sự cố được tạo ra khi sử dụng Breakpad hoặc Crashpad .
Việc thêm hỗ trợ minidump đi kèm với một số thách thức kỹ thuật mà chúng tôi phải giải quyết để đảm bảo rằng chúng tôi có thể xử lý tệp theo cách hiệu quả, có thể mở rộng mà không ảnh hưởng đến thông lượng xử lý sự kiện lỗi thông thường của chúng tôi.
Một minidump là một tệp được tạo ra bởi một số quy trình khi chúng gặp sự cố. Chúng nhỏ hơn bãi chứa lõi và chỉ cung cấp dữ liệu cần thiết để thực hiện các hoạt động gỡ lỗi cơ bản.
Định dạng tệp minidump được phát minh để sử dụng trong Windows khi hệ điều hành gặp lỗi không mong muốn. Sau đó, các công cụ như Breakpad và Crashpad của Google đã áp dụng cùng một định dạng để tạo ra các kết quả lỗi ứng dụng trên nhiều nền tảng. Các ứng dụng được xây dựng bằng Electron cũng tạo ra các tệp minidump cho các sự cố gốc (vì Electron sử dụng Crashpad).
Tệp thu nhỏ chứa thông tin về quy trình tại thời điểm xảy ra sự cố và bao gồm các chi tiết như:
Trong minidump có một ngăn xếp thời gian chạy của mỗi luồng đang hoạt động (tại thời điểm xảy ra lỗi) và các giá trị đăng ký cho các luồng đó.
Những chi tiết này có thể được sử dụng để đi lại ngăn xếp và tạo ra một dấu vết ngăn xếp cho mỗi luồng. Trong một số trường hợp, có thể lấy dấu vết ngăn xếp hợp lệ (mặc dù không được hỗ trợ) chỉ bằng phương pháp này nhưng trong các trường hợp khác, chúng tôi cần thêm Thông tin khung cuộc gọi (CFI) được cung cấp trong tệp gỡ lỗi.
Bản ghi Thông tin Khung cuộc gọi (CFI) mô tả cách khôi phục các giá trị thanh ghi tại một địa chỉ máy cụ thể. Dữ liệu này thường được cung cấp trong tệp gỡ lỗi và cho phép tạo dấu vết ngăn xếp đáng tin cậy hơn khi đi bộ ngăn xếp.
Nếu không có thông tin CFI, bộ đi bộ ngăn xếp có thể cần quét ngăn xếp để cố gắng tìm khung gọi nhưng điều này có thể kém tin cậy hơn và có thể tạo ra các dấu vết ngăn xếp không hợp lệ.
Khi đã lấy được dấu vết ngăn xếp, nó sẽ chỉ chứa địa chỉ của mỗi khung. Để tạo ra một dấu vết ngăn xếp có ý nghĩa (với tên hàm, tệp nguồn và số dòng nguồn cho mỗi khung), chúng ta cần phải "ký hiệu hóa" nó, tức là áp dụng các ký hiệu gỡ lỗi cho chúng.
Tệp gỡ lỗi có liên quan từ trình biên dịch (ví dụ: dSYM cho macOS) có thể được sử dụng cho việc này, nhưng Breakpad đã xác định định dạng tệp ký hiệu của riêng họ có thể được sử dụng thay thế.
Tệp ký hiệu Breakpad đơn giản hơn hầu hết các tệp gỡ lỗi do trình biên dịch tạo (nó không chứa các chi tiết như cây cú pháp trừu tượng) nhưng cung cấp các chi tiết bắt buộc, ở định dạng có thể đọc được, để biểu thị dấu vết ngăn xếp.
Breakpad cung cấp một số công cụ để giúp xử lý thủ công một minidump hoặc tải chúng lên một máy chủ / dịch vụ chuyên dụng để xử lý:
minidump_stackwalk Đưa vào một tệp minidump và các tệp ký hiệu Breakpad tùy chọn và xuất ra dấu vết ngăn xếp cho mỗi luồng cùng với thông tin khác (chẳng hạn như lý do gây ra sự cố, đăng ký giá trị cho mỗi khung, chi tiết của hệ điều hành, v.v.). Đây là một công cụ hữu ích để phân tích cú pháp minidump và nhận các dấu vết ngăn xếp có ý nghĩa từ chúng.
minidump_dump Cung cấp thông tin chi tiết hơn về minidump (chẳng hạn như chi tiết của từng luồng trong minidump).
minidump_upload Tải lên các tệp minidump lên một máy chủ chuyên dụng để xử lý (chẳng hạn như Bugsnag).
dump_syms Tạo tệp ký hiệu Breakpad từ tệp nhị phân và tệp gỡ lỗi của ứng dụng.
symupload Tải các tệp biểu tượng Breakpad lên một máy chủ chuyên dụng để xử lý (chẳng hạn như Bugsnag).
Có thể xem ví dụ về kết quả đầu ra của công cụ minidump_stackwalk với các tệp ký hiệu có liên quan dưới đây:
- Ngôn ngữ-bản rõ CODE - Hệ thống hoạt động: Windows NT 10.0.19041 1151CPU: amd64 family 23 kiểu 24 bước 1 8 CPU
GPU: UNKNOWN
Lý do sự cố: Ngoại lệ C ++ chưa được xử lý Địa chỉ sự cố: 0x7ff887f54ed9 Thời gian hoạt động xử lý: 4 giây
Chủ đề 0 (bị lỗi) 0 KERNELBASE.dll + 0x34ed9
rax = 0x655c67616e736775 rdx = 0x6f6d2d6576697461 rcx = 0x6e2d7070635c656d rbx = 0x00007ff87f731600 rsi = 0x000000b80f3fcb70 rdi = 0x000000b80f3fca40 rbp = 0x000000b80f3fca10 rsp = 0x000000b80f3fc8d0 r8 = 0xaaaaaaaa0065646f r9 = 0xaaaaaaaaaaaaaaaa r10 = 0xaaaaaaaaaaaaaaaa r11 = 0xaaaaaaaaaaaaaaaa r12 = 0x00007ff87f6f1ba0 r13 = 0x000010ff084af60d r14 = 0xffffffff00000000 r15 = 0x0000000000000420 rip = 0x00007ff887f54ed9 Found by: given as instruction pointer in context 1 KERNELBASE.dll + 0x34ed9 rbp = 0x000000b80f3fca10 rsp = 0x000000b80f3fc908 rip = 0x00007ff887f54ed9 Found by: stack scanning 2 ntdll.dll + 0x34a5f rbp = 0x000000b80f3fca10 rsp = 0x000000b80f3fc960 rip = 0x00007ff88a6a4a5f Found by: stack scanning 3 my_example.node! CxxThrowException [throw.cpp: 131 + 0x14] rbp = 0x000000b80f3fca10 rsp = 0x000000b80f3fc9b0 rip = 0x00007ff87f6fab75 Tìm thấy bởi: quét ngăn xếp 4 my_example.node Function RunExample (I Nan :: nfo v8 :: Giá trị const &) [my_example.cpp: 26 + 0x22] rbp = 0x000000b80f3fca10 rsp = 0x000000b80f3fca20 rip = 0x00007ff87f6f1ec2 Tìm thấy bởi: call frame info ...
Chúng tôi đã phải đối mặt với một số thách thức kỹ thuật khi thêm hỗ trợ thu nhỏ cho Bugsnag.
Minidumps thay đổi khá nhiều so với tải trọng JSON sự kiện lỗi thông thường của chúng tôi, vì vậy chúng tôi phải đảm bảo rằng chúng tôi có thể xử lý chúng theo cách hiệu quả, linh hoạt và có thể mở rộng.
Tệp thu nhỏ có thể lớn hơn nhiều so với tải trọng bình thường mà chúng tôi nhận được; tải trọng bình thường của chúng tôi trung bình ~ 20KB trong khi các bộ tiêu chuẩn nhỏ thường có kích thước hàng trăm kilobyte. Ngoài ra, các minidumps có thể nhận được khá lớn (hàng chục megabyte) nếu có nhiều luồng đang hoạt động hoặc luồng có ngăn xếp lớn.
Thông thường, khi chúng tôi nhận được tải trọng của sự kiện lỗi, chúng tôi thêm chúng vào hàng đợi Kafka để xử lý không đồng bộ để chúng tôi có thể xử lý mọi tồn đọng có tải lên.
Chúng tôi cần đảm bảo rằng cơ chế xếp hàng sẽ đáng tin cậy nếu chúng tôi xếp hàng các tệp minidump lớn hơn. Các tệp minidump nén tốt (thường là khoảng 10% kích thước ban đầu của chúng) nhưng vẫn có nguy cơ tệp nén quá lớn.
Chúng tôi đã thực hiện một số thử nghiệm tải với các thông báo có kích thước khác nhau trên một phiên bản Kafka nội bộ và nhận thấy rằng:
Thông lượng dữ liệu và độ trễ sao chép không thực sự bị ảnh hưởng bởi kích thước của tệp.
Số lượng thư có thể được xử lý mỗi giây giảm khi kích thước tệp trung bình tăng lên.
Thông lượng thư giảm này chỉ đáng kể khi xếp hàng đồng thời nhiều tệp đặc biệt lớn nhưng chúng tôi dự đoán rằng những tệp này sẽ rất hiếm và do đó Kafka sẽ phù hợp với mục đích này.
Khi ký hiệu một minidump bằng công cụ minidump_stackwalk của Breakpad, có thể mất nhiều thời gian hơn để xử lý minidump khi các tệp ký hiệu Breakpad được cung cấp (do mất thời gian để tải các tệp ký hiệu, phân tích cú pháp chúng và tra cứu dữ liệu ký hiệu có liên quan).
Trên một minidump Electron mẫu, mất 20ms nếu không có tệp ký hiệu Breakpad và 14 giây với chúng!
Thời gian xử lý chậm hơn không phải là vấn đề quá đáng lo ngại khi ký hiệu thủ công một minidump duy nhất nhưng chúng tôi cần đảm bảo rằng chúng tôi có thể xử lý và ký hiệu các minidump hiệu quả nhất có thể để chúng tôi có thể duy trì thông lượng xử lý minidump cao.
Để đạt được điều này, chúng tôi đã thực hiện logic ký hiệu của riêng mình. Định dạng tệp biểu tượng Breakpad rất đơn giản và được ghi chép đầy đủ có nghĩa là chúng ta có thể phân tích cú pháp tệp để tạo ra tệp ánh xạ riêng cho phép tra cứu địa chỉ dễ dàng.
Tệp bespoke lớn hơn rất nhiều so với tệp ký hiệu Breakpad nhưng cũng hiệu quả hơn rất nhiều để thực hiện tra cứu. Việc xử lý trước tệp ký hiệu Breakpad này có nghĩa là thời gian cần thiết để xử lý một minidump giảm đáng kể (với chi phí tăng yêu cầu lưu trữ đối với tệp ký hiệu).
Trong thiết kế ban đầu của xử lý minidump, chúng tôi đã bỏ qua hoàn toàn việc sử dụng các tệp biểu tượng Breakpad khi di chuyển ngăn xếp (để cải thiện hiệu quả) nhưng chúng tôi sớm nhận ra rằng điều này đôi khi dẫn đến dấu vết ngăn xếp không hợp lệ do thiếu dữ liệu Thông tin Khung cuộc gọi.
Chúng tôi biết rằng nếu chúng tôi chuyển toàn bộ tệp ký hiệu Breakpad cho việc di chuyển ngăn xếp thì nó sẽ chậm (do nó cũng cố gắng biểu thị dấu vết ngăn xếp) vì vậy thay vào đó chúng tôi đã chọn tạo một phiên bản rút gọn của tệp chỉ chứa thông tin cần thiết để di chuyển ngăn xếp.
Điều này đã làm giảm đáng kể kích thước của tệp biểu tượng Breakpad cũng như thời gian xử lý minidump nhưng nó vẫn không hiệu quả lắm (mất 1,5 giây cho ví dụ như Electron minidump).
Do đó, chúng tôi đã khám phá tùy chọn tuần tự hóa tệp ký hiệu Breakpad đã được cắt bớt để nó có thể được đọc hiệu quả hơn (thay vì phải phân tích cú pháp tệp mỗi lần). Sử dụng phiên bản tuần tự của tệp đã giảm thời gian xử lý từ 1,5 giây xuống 200 mili giây.
Sự cải thiện hiệu suất này có nghĩa là chúng tôi sẽ có khả năng hỗ trợ thông lượng cao hơn của các sự cố nhỏ trên mỗi trường hợp của dịch vụ, nghĩa là chúng tôi có thể giảm chi phí cơ sở hạ tầng.
Khi việc áp dụng tính năng mới phát triển, chúng tôi sẽ giám sát chặt chẽ việc sử dụng cơ sở hạ tầng của mình để đảm bảo rằng chúng tôi tiếp tục xử lý các lỗi nhỏ một cách hiệu quả và xem liệu có bất kỳ cải tiến hiệu suất nào khác được thực hiện hay không.
Bugsnag giúp bạn ưu tiên và sửa lỗi phần mềm đồng thời cải thiện tính ổn định của ứng dụng.