- Vào ngày 12 tháng 6 năm 2025, số lượng lỗi 503 trong các yêu cầu API bên ngoài trên các dịch vụ Google Cloud và Google Workspace đã tăng trên phạm vi toàn cầu
- Nguyên nhân lỗi là do thay đổi mã trong hệ thống Service Control và việc áp dụng một chính sách lỗi có chứa trường trống trong dữ liệu chính sách
- Xử lý lỗi chưa đầy đủ trong binary cốt lõi và việc không áp dụng feature flag đã làm sự cố lan rộng hơn
- Quá trình khôi phục mất 2–3 giờ, riêng khu vực us-central-1 mất nhiều thời gian hơn do hạ tầng bị quá tải
- Google đã công bố các biện pháp ngăn ngừa tái diễn như tách biệt kiến trúc, cải thiện xử lý lỗi, tăng cường xác thực dữ liệu
Tổng quan toàn bộ sự cố
Tóm tắt sự cố dịch vụ Google Cloud và Google Workspace
- Từ 10:49 sáng (PDT) ngày 12 tháng 6 năm 2025, nhiều dịch vụ bao gồm Google Cloud, Google Workspace và Google Security Operations đã ghi nhận số lượng lỗi 503 tăng đột biến đối với các yêu cầu API bên ngoài
- Google bày tỏ lời xin lỗi sâu sắc vì đã gây ảnh hưởng nghiêm trọng đến dịch vụ của khách hàng và niềm tin của họ
- Mặt phẳng quản lý và điều khiển API của Google chịu trách nhiệm kiểm tra chính sách và quota cho từng yêu cầu, và hệ thống kiểm tra cốt lõi hoạt động dưới dạng một binary có tên là
Service Control
Phân tích nguyên nhân sự cố
Cấu trúc hệ thống đã thay đổi – Service Control
- Vào ngày 29 tháng 5 năm 2025, một tính năng mới nhằm tăng cường kiểm tra chính sách quota đã được thêm vào Service Control
- Dù đã được triển khai theo từng giai đoạn theo khu vực, đoạn mã có vấn đề chỉ hoạt động khi chính sách thực sự được áp dụng, nên trước đó không bị kích hoạt và việc kiểm thử trước triển khai là chưa đầy đủ
- Đường chạy của tính năng mới này thiếu xử lý lỗi phù hợp và feature flag, khiến binary bị crash dây chuyền trong tình huống null pointer
Diễn biến phát sinh sự cố
- Vào 10:45 sáng (PDT) ngày 12 tháng 6 năm 2025, một thay đổi chính sách đã được chèn vào bảng Regional Spanner
- Dữ liệu chính sách này có chứa một trường trống (Blank Field) ngoài ý muốn, và nó đã được sao chép gần như theo thời gian thực trên toàn cầu
- Khi Service Control xử lý chính sách này, crash do null pointer đã xảy ra, khiến các instance ở mỗi khu vực rơi vào Crash Loop trên phạm vi toàn cầu
- Trong vòng 2 phút, đội SRE bắt đầu nhận diện sự cố; trong vòng 10 phút đã xác định được nguyên nhân và tạm thời chặn đường chạy của binary bằng red-button; trong vòng 40 phút, phần lớn khu vực đã được khôi phục
Các vấn đề khôi phục bổ sung
- Một số khu vực lớn như us-central-1 đã gặp tình trạng hạ tầng (bảng Spanner) bị quá tải do herd effect khi các tác vụ Service Control khởi động lại
- Service Control không áp dụng randomized exponential backoff, khiến gánh nặng lên hạ tầng càng tăng
- Khu vực này bị chậm khôi phục tới 2 giờ 40 phút; tác động được giảm thiểu bằng cách chuyển hướng lưu lượng, và nhìn chung toàn bộ dịch vụ cuối cùng đã được khôi phục
Ảnh hưởng tới khách hàng và phạm vi sự cố
- Khách hàng gặp sự cố truy cập API và giao diện người dùng, nhưng không ảnh hưởng đến dịch vụ streaming và tài nguyên IaaS
- Ảnh hưởng do độ trễ và backlog tiếp tục kéo dài hơn 1 giờ ở một số dịch vụ
- Danh sách các sản phẩm Google Cloud và Google Workspace bị ảnh hưởng được nêu ra rất rộng
- Ví dụ: IAM, Cloud Build, Cloud Storage, BigQuery, AppSheet, Gmail, Google Drive cùng hàng chục dịch vụ khác
Hướng cải thiện trong tương lai
- Mô-đun hóa kiến trúc dịch vụ để tách biệt từng chức năng và áp dụng cơ chế fail open khi có sự cố
- Triển khai lan truyền dữ liệu toàn cầu theo từng bước và tăng cường quy trình xác thực thực chất
- Cải tổ chính sách để mọi thay đổi đối với binary quan trọng đều được đưa sau feature flag và mặc định vô hiệu hóa
- Xem xét thiết kế cho phép phát hiện lỗi và fail open khi có sự cố thông qua cải thiện phân tích tĩnh và kiểm thử
- Dự kiến tăng cường chính sách randomized exponential backoff cùng độ tin cậy của hệ thống giám sát/giao tiếp
- Bổ sung hạ tầng dự phòng và tự động hóa giao tiếp để khách hàng vẫn có thể nhanh chóng nhận được thông tin giám sát và cập nhật ngay cả khi xảy ra sự cố
Thông báo sự cố và giao tiếp
- Trong vòng 1 giờ sau sự cố, thông báo đã được đăng trên Cloud Service Health, nhưng chính hạ tầng giám sát cũng gặp lỗi
- Một số khách hàng gặp khó khăn trong việc phát hiện tín hiệu sự cố và xác định mức độ ảnh hưởng do hệ thống giám sát chạy trên Google Cloud của họ không hoạt động bình thường
- Google cam kết trong tương lai sẽ tăng cường hạ tầng giám sát và giao tiếp với khách hàng
Dòng thời gian chính của sự cố (tóm tắt mini report)
- Bắt đầu sự cố: 10:49 (PDT), ngày 12 tháng 6 năm 2025
- Phần lớn khu vực được khôi phục: 12:48 (PDT), ngày 12 tháng 6 năm 2025
- Kết thúc sự cố: 13:49 (PDT), ngày 12 tháng 6 năm 2025
- Tổng thời gian: khoảng 3 giờ
- Khu vực bị ảnh hưởng: toàn cầu
Tóm tắt biện pháp hậu kiểm
- Dự kiến bổ sung cơ chế ngăn lỗi khi dữ liệu của nền tảng quản lý API bị sai hoặc hư hỏng
- Tăng cường xác thực, kiểm thử và giám sát trước khi siêu dữ liệu toàn cầu được phát tán
- Mở rộng xử lý lỗi hệ thống và kiểm thử tổng hợp đối với dữ liệu không hợp lệ
Danh sách dịch vụ bị ảnh hưởng (trích)
Các dịch vụ chính của Google Cloud
- Identity and Access Management, Cloud Build, Google Cloud Storage, Cloud Monitoring, BigQuery, Vertex Gemini API, Cloud Firestore, Looker, Cloud Run, Compute Engine
Các dịch vụ chính của Google Workspace
- AppSheet, Gmail, Google Drive, Google Meet, Docs, Chat, Calendar
Kết luận
- Sự cố lần này là kết quả của tác động kết hợp giữa cấu trúc hệ thống quản lý chính sách/quota, thiếu xác thực tính toàn vẹn dữ liệu, và thiếu cơ chế xử lý lỗi
- Google cam kết cải thiện ở cấp độ kiến trúc và tăng cường năng lực ứng phó sự cố
2 bình luận
Đây là liên kết đến bài viết phiên bản không phải GN+.
Ý kiến trên Hacker News
Tôi là người trong cuộc nên đang dùng tài khoản tạm; nguyên nhân gốc rễ của sự cố này là ban lãnh đạo đã phớt lờ các nguyên tắc để đẩy nhanh tốc độ, và kiểu làm việc này đã kéo dài nhiều năm nên cuối cùng chạm giới hạn. “query of death” lần này là một dạng thất bại điển hình, gần như không tránh khỏi ở các máy chủ C++ cũ khi một truy vấn cụ thể có thể làm server crash. Service Control được viết bằng C++ và đã cố gắng giảm thiểu kiểu lỗi này bằng nhiều hướng dẫn kỹ thuật khác nhau. Hệ thống đã vận hành 10 năm mà không có sự cố lớn, nhưng chính chính sách quota toàn cầu được làm vội dưới áp lực từ lãnh đạo gần đây mới là vấn đề. Những tính năng mới như vậy lẽ ra phải được phát triển thành dịch vụ riêng, hoặc ít nhất phải tuân thủ các hướng dẫn sẵn có. Tiêu chuẩn mà đội ngũ vốn duy trì còn cao hơn nhiều so với các biện pháp khắc phục được nêu trong báo cáo chính thức, và cả đội vẫn đang cố giữ các tiêu chuẩn cũ trong khả năng có thể.
Tôi thấy báo cáo sự cố khá thú vị. Đội SRE đã phản ứng rất nhanh chỉ trong 2 phút và bắt đầu rollout kiểu “red button”. Vấn đề là khi các tác vụ Service Control khởi động lại ở những vùng lớn như us-central-1 thì xuất hiện “herd effect”, làm hạ tầng bên dưới (bảng Spanner) bị quá tải. Vì Service Control không triển khai random exponential backoff nên việc khôi phục hoàn toàn bị kéo dài tới 2 giờ 40 phút. Trong tình huống như vậy, quota bình thường sẽ nhanh chóng bị vượt quá và kéo theo thêm sự cố mới. Tôi nghĩ trong các trường hợp như thế, nếu hạ tầng chịu được thì cũng nên tạm ngưng quota hoặc chủ động giới hạn tốc độ phục hồi cho chậm lại.
Đây thực sự là một lỗi rất nghiệp dư: NPE, không có xử lý lỗi, không có exponential backoff, không có test coverage, không test trong môi trường staging, không rollout dần dần — tất cả đều là những thất bại nghiêm trọng. Tất cả những điều này đều đã có trong sách SRE: Google SRE Book mục lục, Building Secure and Reliable Systems TOC. Tôi tự hỏi là tiêu chuẩn đã xuống quá thấp hay mấy cuốn sách đó thực chất chỉ là tài liệu marketing.
Theo tôi, dù là con người hay tự động hóa thì cũng không có lớp phòng vệ nào hoàn hảo; rốt cuộc tất cả chỉ là một chuỗi đánh đổi. Dù bạn có bao nhiêu unit test, integration test, static analysis hay rollout tuần tự đi nữa, khi hệ thống đủ lớn thì vẫn sẽ luôn có những khe hở bất ngờ. Đây cũng chính là lý do như trong sách nói rằng “để thêm một số 9 nữa thì phải bỏ ra nỗ lực lớn hơn rất nhiều”. Trong trường hợp tệ nhất, có khi bạn phải sao chép toàn bộ stack rồi phát lại toàn bộ lưu lượng của nhiều tháng, mà mức chi phí/lợi ích như thế thì chẳng ai gánh nổi. Tôi từng gặp chuyện tương tự khi làm OpenZFS: bản thân code nhìn hoàn toàn ổn, nhưng lỗi chỉ lộ ra ở một edge case dữ liệu được ghi từ 10 năm trước. Khi hệ thống đủ phức tạp thì việc test mọi biến thể là bất khả thi, nên trên thực tế chỉ có thể quyết định dựa trên hiệu quả so với chi phí. Nói thêm là tôi làm SRE ở Google nhưng thuộc đội không liên quan đến sự cố này; đây là ý kiến cá nhân.
Gần như mọi sự cố toàn cầu của Google đều diễn ra theo kiểu này: một hệ thống tùy biến được triển khai rất nhanh trên phạm vi toàn cầu rồi nhận phải cấu hình sai. Với rollout binary hay push cấu hình thông thường thì rollout dần dần gần như luôn được áp dụng. Ở Google Cloud trước đây cũng có nhiều hệ thống bị buộc toàn cầu với nhau, nhưng giờ đã được bản địa hóa nhiều hơn và độ tin cậy cao hơn đáng kể. Trước kia cũng thường có sự cố toàn cầu, nhưng không được công khai nên đa số người dùng chỉ tưởng là lỗi từ ISP của họ. Tôi không nghĩ tình hình hiện nay đặc biệt tệ hơn. Nói thêm là tôi cũng có kinh nghiệm SRE.
Nếu nhìn từ bên ngoài, có cảm giác rằng sau các đợt sa thải quy mô lớn và phát biểu kiểu “lười biếng” của CEO, mọi người đều bị đẩy sang ưu tiên tốc độ và thành tích dễ nhìn thấy hơn là chất lượng. Dần dần môi trường cũng thay đổi theo hướng ai nêu vấn đề về văn hóa này lại bị gạt ra ngoài.
Tôi mong có thêm thông tin chi tiết được công bố. Theo tôi thì vấn đề không phải là hoàn toàn không có test như đã nói ở đây, mà là không có test cho trường hợp trường rỗng trong policy, tức chính đầu vào gây lỗi. Cũng không phải là không có test ở môi trường staging; ý ở đây là nếu có flag guard thì có lẽ đã chặn được. Đây là ý kiến cá nhân.
Tôi chợt nhớ tới một báo cáo kho thuốc súng năm 1864: “Ngay cả công cụ nguy hiểm nhất, một khi đã quá quen thuộc, con người cũng sẽ đánh mất sự thận trọng và bắt đầu xem các quy định là nghiêm ngặt một cách không cần thiết.”
Tôi thuộc một đội khác trong Cloud. Nhìn chung, mọi code đều có unit test và integration test. Các thay đổi binary hoặc cấu hình thường được rollout dần theo tác vụ và theo vùng trong nhiều ngày, kèm cả phân tích canary. Ngay cả rollback nếu làm quá gấp cũng có thể khiến tình hình tệ hơn nên thường cũng làm từ từ. Ví dụ, người ta có thể đánh giá rằng mất điện 40 phút còn tốt hơn là gây quá tải toàn bộ cơ sở dữ liệu toàn cầu và biến thành sự cố kéo dài 4 giờ. Tôi không trực tiếp tham gia sự cố này, nhưng theo PM thì code đã được test, chỉ là edge case này bị sót. Vấn đề là cấu hình quota policy không được áp dụng qua binary hay file cấu hình mà qua cập nhật cơ sở dữ liệu, nên thay đổi đã lan tới mọi cơ sở dữ liệu toàn cầu chỉ trong vài giây. Vấn đề null pointer cũng có thể đã xảy ra ở ngôn ngữ khác thông qua
assert(). So với rủi ro của việc viết lại dịch vụ cốt lõi này bằng ngôn ngữ khác, có vẻ hợp lý hơn nếu áp dụng flag guard cho mọi bước kiểm tra policy, để kiểm tra quota policy theo hướng fail-open, và làm cho các thay đổi DB được lan truyền chậm theo từng vùng. Đây là ý kiến cá nhân.assertlà kiểu cấu trúc mà việc cấm theo chính sách sẽ dễ hơn rất nhiều.Nếu nói rằng code đã được test nhưng edge case này bị sót, thì phản biện lại vẫn là: như thế tức là rốt cuộc chưa test trường hợp đó.
Việc thay đổi DB không phải là thay đổi binary hay cấu hình không làm vấn đề khác đi. Bất kỳ thay đổi nào mà lan ra toàn cầu cùng lúc đều là mầm mống của thảm họa. Luồng diễn biến này giống hệt vụ Crowdstrike.
Nếu quan điểm là “viết lại bằng ngôn ngữ khác có rủi ro quá lớn”, thì tôi tự hỏi có phải là vì yêu cầu dịch vụ chưa thực sự được hiểu đầy đủ, hoặc dịch vụ này chưa đủ quan trọng để xứng đáng với một cuộc di trú thận trọng hay không.
Nội dung nói rằng binary đã crash vì null pointer mà không có xử lý lỗi thích hợp. Đến mức này thì trò đùa “lỗi nghìn tỷ đô” cũng có đất diễn thật.
Tò mò không biết sự cố này đã làm bay mất bao nhiêu SLA của cả năm.
Giá như có một ngôn ngữ nào đó có thể ngăn được kiểu lỗi này. /s
Service Control (Chemist) là một dịch vụ đã khá cũ, đóng vai trò cốt lõi cho nhiều GCP API như xác thực, phân quyền, giám sát, quota... Trong luồng request, phần lớn các GCP API đều đi qua Chemist, nên tôi không nghĩ biện pháp giảm nhẹ fail-open có hiệu quả thực tế. Cả Chemist lẫn proxy đều được viết bằng C++ và đã tích lũy rất nhiều mã legacy qua nhiều năm. Mỗi đội đều có static analysis, test, rollout dần dần, feature flag, red button, cùng hệ thống giám sát và cảnh báo mạnh; đặc biệt đội SRE rất giỏi. Vì Chemist phải xác minh nhiều loại policy như IAM, quota..., rất nhiều đội đã cùng đóng góp vào codebase. Để tránh phải qua quy trình phê duyệt của Chemist mỗi lần thay đổi, ngày càng có nhiều phần được phát triển bằng lối tắt. Gần đây lại có nhiều tái cơ cấu tổ chức và offshore, nên trọng tâm nghiêng về các dự án mới hào nhoáng do cấp L8/L9 dẫn dắt, còn chất lượng, bảo trì và độ tin cậy bị đẩy xuống sau. Tôi đã rời Cloud cũng vì sự thay đổi văn hóa này. Các best practice chung cho server/service ở Google nhiều khi không được tuân thủ ở đây. Vấn đề lần này gần với chuyện code và code review kém chất lượng hơn; đoạn code lỗi đã được phê duyệt, rồi việc dùng Spanner để phản ánh thay đổi cấu hình ngay lập tức đã khiến vấn đề nghiêm trọng hơn.
Dữ liệu policy của dịch vụ có chứa một trường rỗng ngoài ý muốn, và khi Service Control đọc trường rỗng đó (null) trong quá trình kiểm tra quota theo từng vùng thì đã phát sinh ngoại lệ. Đây là một ví dụ nữa cho “lỗi tỷ đô” của Hoare lặp lại trong nhiều hệ thống của Google. Vấn đề ngay từ đầu là việc cho phép tồn tại một “trường rỗng” (null) như vậy; lẽ ra phải khai báo không cho null (
NOT NULL) trong schema. Đáng tiếc là Spanner mặc định cho phép nullable nên phải chỉ định riêng. Ở tầng code ứng dụng, lẽ ra cũng đã có thêm cơ hội thiết kế sao cho trạng thái không hợp lệ là bất khả thi thông qua type system hoặc schema language. Cũng có thể thêm bước kiểm tra ép buộc schema khi deserialization từ datastore sang đối tượng ứng dụng. Vì vấn đề trong bài nổ ra ở một code path mới, tôi đoán rằng dữ liệu chưa được chặn lọc ở tầng dữ liệu. Bản thân việc chương trình Service Control được viết bằng một ngôn ngữ cho phép dereference null pointer cũng là vấn đề. Nếu tôi là người chịu trách nhiệm, tôi sẽ nghĩ tới một kế hoạch can thiệp tối thiểu để đổi policy trong code ứng dụng sang cấu trúc như “tagged enum type”, nơi không thể biểu diễn null. Proto3 không có ràng buộc đó, nhưng có ví dụ như thế này.Multi-region thường được nhắc tới như một công cụ để đạt khả năng chống chịu và tính sẵn sàng, nhưng điều thú vị là trong tình huống sự cố, ngay cả các nhà cung cấp cloud lớn cũng thực tế bị ràng buộc rất chặt giữa các vùng.
Điều này đặc biệt rõ ở GCP, vì GCP xử lý region theo cách khác với các bên khác. Nếu nhìn từ góc độ khả năng phục hồi, nên xem GCP giống như một region đơn lẻ với nhiều zone được bó lại với nhau.
Dù vậy, vẫn có thể tồn tại những sự cố “mà chúng ta không biết”, nên cũng không nên đánh giá thấp quá mức hiệu quả của việc sharding theo region/zone.
Cũng đã có nhiều trường hợp triển khai multi-region giúp ngăn ngừa sự cố, nên tốt hơn là tìm hiểu các ca như vậy rồi mới kết luận.
Tôi luôn ngạc nhiên trước mức độ chi tiết trong các postmortem của Google, cả từ bên trong lẫn bên ngoài công ty. Họ học để không lặp lại sai lầm, củng cố protocol và xử lý lỗi để hệ thống tiến hóa ngày càng vững chắc hơn. Ở một nơi có quy mô như Google, lúc nào đó cũng sẽ có thứ gì đó trục trặc, nhưng điều quan trọng là khoanh vùng để không ảnh hưởng tới khách hàng/người dùng và các hệ thống khác. Ngay cả khi ở bên trong, tùy đội mà cũng có rất nhiều vấn đề bạn không nhìn thấy. Tôi xem đây là một trong những hệ thống phức tạp nhất do con người tạo ra. Trừ khi đã có AGI, tôi không nghĩ con người có thể làm tốt hơn nhiều.
Nhưng trong sự cố lần này, đã có một chuỗi sai lầm rất mức nhập môn: không xử lý được dữ liệu null, test không đủ, không có test coverage cho tính năng mới, và không xác minh trên quy mô production nhỏ trước khi rollout toàn diện — tất cả đều là vấn đề. Tôi dám chắc rằng ở Google của 10 năm trước, ai cũng sẽ cười nhạo những lỗi như vậy.
Theo cách tôi hiểu thì nguyên nhân của sự cố lần này là: 1) một tính năng toàn cục được triển khai cho toàn bộ hệ thống cùng lúc; 2) xảy ra null pointer dereference; 3) thiếu chính sách retry phù hợp nên gây ra “thundering herd”. Tất cả đều là những lỗi rất quen thuộc với người trong ngành. Đây không phải là logic phân tán phức tạp hay điều gì kỳ lạ, mà là nhiều “lỗi người mới” điển hình cùng bùng lên một lúc.
Người ta hay nói “sẽ không lặp lại cùng một sai lầm nữa”, nhưng thực tế thì thay đổi đã được rollout mà không có feature flag, client không có exponential backoff, còn server thì không có load shedding. Tất cả những thứ này đều đã có trong google SRE book từ nhiều năm trước.
Đây là lỗi null pointer bị bỏ sót. Việc một công ty có quy mô và tiêu chuẩn chất lượng như Google lại để lỗi kiểu này đánh sập phần lớn stack là tín hiệu cho thấy các biện pháp ngăn tái diễn vấn đề nghiêm trọng vẫn chưa đủ.
Đây là đúng một kiểu sai lầm đã lặp đi lặp lại vô số lần. “Tính năng mới được rollout cẩn thận, nhưng bug chỉ lộ ra khi có dữ liệu mới đi vào” là câu mô tả tóm gọn phần lớn các sự cố toàn cầu. Không tồn tại hệ thống hoàn hảo. Trong các cuộc tranh luận về outage của FAANG, thứ duy nhất hoàn hảo tuyệt đối chỉ có các “chuyên gia ghế bành” trên HN.
Thông thường, khi nhìn downtime của người khác thì ai cũng dễ phê là “lỗi trình độ junior”, nhưng đến khi chính mình gặp chuyện lại viện cớ rằng nó là bất khả tránh, không thể dự đoán. Sai lầm của con người là điều không thể tránh khỏi, và kỳ vọng hiện nay vốn đã quá cao. Một cửa hàng ngoài đời đột nhiên đóng cửa cũng chỉ cần một câu “xin lỗi” là xong; chỉ riêng ngành IT là tự tạo cho mình mức căng thẳng quá mức vì một sự cố kéo dài vài giờ. Tôi mong mọi người có thể bớt căng thẳng hơn một chút.