- Nền tảng dữ liệu của Slack vận hành hơn 700 Operator dựa trên SSH cho các pipeline dữ liệu cốt lõi như lập chỉ mục tìm kiếm hằng ngày và tác vụ phân tích, trong đó mọi công việc đều yêu cầu kết nối SSH trực tiếp tới các cụm AWS EMR production, tạo ra bề mặt tấn công bảo mật rất lớn
- Sự phụ thuộc vào SSH này không chỉ gây rủi ro bảo mật mà còn trở thành rào cản chính đối với việc hiện đại hóa hạ tầng như chuyển sang Spark on Kubernetes, EMR on EKS, và hoàn tất sáng kiến Whitecastle
- Để giải quyết, Slack tận dụng YARN Distributed Shell nhằm cho phép chạy cả các lệnh shell tùy ý trong container YARN, đồng thời hợp nhất toàn bộ việc gửi job thông qua cổng REST nội bộ Quarry
- Di chuyển hơn 700 job trên 8 vùng dữ liệu mà không có downtime (zero downtime), và hoàn tất loại bỏ SSH 100% trong vòng 3 quý
- Kết quả là thu hẹp bề mặt tấn công, tăng độ tin cậy của job, cải thiện khả năng quan sát, đồng thời tạo nền tảng cho hoàn tất Whitecastle và các hạ tầng thế hệ tiếp theo như Spark on Kubernetes
Bối cảnh: hình thành nền tảng dữ liệu dựa trên SSH
- Nền tảng dữ liệu Slack được xây dựng khoảng năm 2017 đã chọn cách làm qua SSH như con đường trực tiếp nhất để Airflow chạy job trên các cụm EMR
- Dùng
SSHOperator để kết nối vào node master của EMR rồi chạy các lệnh như spark-submit
- Sau đó, các nhóm đã tự xây dựng các Operator tùy chỉnh dựa trên SSH cho nhiều mục đích khác nhau (không chỉ Spark mà còn MapReduce, AWS CLI, script Python tùy chỉnh)
- Kết quả là tích lũy hơn 700 job dựa trên SSH trong môi trường production
Chi phí thực tế của cách làm bằng SSH
-
Rủi ro bảo mật tiềm ẩn
- SSH trực tiếp vào các cụm compute làm mở rộng bề mặt tấn công
- Phân phối và xoay vòng khóa trên toàn bộ các worker orchestration làm tăng gánh nặng vận hành
- Muốn audit chi tiết phải đối chiếu log từ nhiều hệ thống
- Việc quản lý quyền trở nên phức tạp với security group chuyên biệt và cấu hình tùy chỉnh
-
Vấn đề về vận hành
- Job không được phân tán mà chạy trực tiếp trên node master của EMR, gây ra tranh chấp tài nguyên
- Khi Pod Kubernetes khởi động lại, kết nối SSH bị ngắt khiến job thất bại
- Các job chạy dài có thể tiếp tục chạy sau khi kết nối đóng, trở thành tiến trình zombie
- Khi mất kết nối thì không thể xác định job đã thành công hay thất bại
-
Các yếu tố cản trở hiện đại hóa
- Không thể tiến tới Spark on Kubernetes và EMR on EKS (cần loại bỏ phụ thuộc SSH trước)
- Không thể chuyển cụm EMR cuối cùng trong tài khoản chính sang tài khoản con, khiến sáng kiến Whitecastle chưa hoàn tất
- Whitecastle là sáng kiến của Slack nhằm chuyển hạ tầng AWS sang các tài khoản con để tăng cường bảo mật và cô lập mạng
- Không thể triển khai giám sát job và khả năng quan sát phù hợp
-
Trường hợp tiêu biểu — đội Search Infrastructure
- Một pipeline xây dựng chỉ mục tìm kiếm Solr hằng ngày từ dữ liệu ở quy mô terabyte, là thành phần cốt lõi của tính năng tìm kiếm của Slack
- Vì phụ thuộc vào việc gửi job qua SSH nên phải đối mặt với toàn bộ các vấn đề về độ tin cậy nêu trên
Khái niệm cơ bản của việc gửi job dựa trên REST
-
Giới hạn bản chất của SSH
- Kết nối SSH là kết nối trực tiếp có trạng thái; nếu kết nối bị ngắt do Pod khởi động lại hoặc nguyên nhân khác, lệnh có thể vẫn tiếp tục chạy, thất bại, hoặc để lại tiến trình mồ côi
- Không có cách đáng tin cậy để kết nối lại và kiểm tra trạng thái
-
Phương án thay thế bằng REST
- Các engine compute hiện đại như YARN, Trino, Snowflake đều hỗ trợ gửi job qua HTTP API
- POST yêu cầu job → trả về job ID
- GET trạng thái job → kiểm tra đang chạy/đã hoàn tất/thất bại
- DELETE job → hủy đúng cách
- Vòng đời job được quản lý ở phía server, nên ngay cả khi client khởi động lại thì job vẫn tiếp tục chạy và có thể truy vấn trạng thái
-
Vai trò và giới hạn của YARN
- Với workload Hadoop (MapReduce, Spark, Hive), YARN là trình quản lý tài nguyên và cũng cung cấp REST API
- Tuy nhiên, với hơn 300 job dựa trên CLI chạy các lệnh tùy ý như
aws s3 sync, hadoop distcp, lại không có REST API sẵn dùng ngay
- Mấu chốt để giải quyết bài toán này là YARN Distributed Shell
Bước đột phá: YARN Distributed Shell
- Spark có Livy REST API, Hive có HiveServer2 nên việc di chuyển tương đối đơn giản
- Ngược lại, các job MapReduce và hơn 300 job dựa trên CLI là bài toán khó vì không có REST API sẵn dùng ngay
-
Yêu cầu
- Một giải pháp REST đơn giản phù hợp tự nhiên với kiến trúc hiện có
- Tận dụng cơ chế xác thực/phân quyền sẵn có (không cần lớp bảo mật tùy chỉnh)
- Sử dụng giao thức mã nguồn mở (API YARN tiêu chuẩn), không phải giải pháp độc quyền
- Độ phức tạp tối thiểu, tránh phải xây dựng và vận hành hạ tầng thực thi job tùy chỉnh
-
Các phương án đã xem xét rồi loại bỏ
- Xây dựng dịch vụ wrapper tùy chỉnh để chạy lệnh từ xa
- Dùng các framework thực thi từ xa như Ansible, Salt
- Tự thêm một loại job mới vào YARN từ đầu
- Tất cả đều không phù hợp vì quá phức tạp, cần tự triển khai bảo mật, hoặc tạo thêm phụ thuộc mới
-
Phát hiện ra YARN Distributed Shell
- Với
org.apache.hadoop.yarn.applications.distributedshell.ApplicationMaster, có thể chạy script shell tùy ý bên trong container YARN
- Đây là tính năng đã có sẵn trong YARN, dùng cùng REST API và không cần lớp bảo mật tùy chỉnh
-
Cách hoạt động
- 1. Upload script lệnh lên S3 (ví dụ:
aws s3 sync /tmp/data/ s3://bucket/output/)
- 2. Gửi lên YARN với cấu hình Distributed Shell
- Đặt
application-type là MAPREDUCE, và đưa các biến môi trường như DISTRIBUTEDSHELLSCRIPTLOCATION, DISTRIBUTEDSHELLSCRIPTLEN, DISTRIBUTEDSHELLSCRIPTTIMESTAMP vào am-container-spec
- 3. YARN cấp phát container, tải script xuống rồi chạy
- YARN quản lý giới hạn tài nguyên như memory/vCore, cô lập container, retry và tolerance khi lỗi, hủy đúng cách, cũng như logging qua YARN UI
- Quyết định này giúp không chỉ workload Hadoop mà cả
aws s3 sync, hadoop distcp, và các script Python tùy chỉnh đều có thể chạy trong container YARN
Giải pháp: Quarry
- Quarry là cổng gửi job dựa trên REST của Slack, được tạo ra để gửi job tới nhiều compute engine như EMR/YARN, Trino, Snowflake
- Nó vốn đã giải quyết các bài toán về xác thực, độ tin cậy và khả năng quan sát, nên phù hợp chính xác với mục tiêu loại bỏ SSH
-
Chức năng của Quarry
- Xác thực: dùng token giữa các dịch vụ thay cho khóa SSH
- Gửi job: chuyển tới YARN, Trino, Snowflake qua REST API
- Theo dõi trạng thái: giám sát trạng thái job ở phía server
- Quản lý vòng đời: hủy và dọn dẹp đúng cách qua REST API
- Khả năng quan sát: cung cấp log có cấu trúc, metric và tracing cho toàn bộ việc gửi job
-
Thay đổi về kiến trúc
- Trước đây:
Airflow → SSH Connection → EMR Master Node → Execute Command
- Sau này:
Airflow → Quarry REST API → YARN ResourceManager → EMR Container
- Airflow Operator gửi yêu cầu HTTP tới Quarry thay vì mở kết nối SSH; Quarry gửi lên YARN rồi polling trạng thái
- Ngay cả khi Airflow Pod khởi động lại thì job vẫn được giữ nguyên, còn Quarry bảo toàn kết nối logic đó
-
Điểm mạnh của Quarry
- Nhờ hỗ trợ YARN Distributed Shell, nó trở thành cổng gửi job đa dụng
- Job Spark, truy vấn Hive, script shell đều đi qua cùng một REST API
- Loại bỏ hoàn toàn thông tin xác thực SSH và truy cập trực tiếp vào cụm; chỉ còn các lời gọi REST có xác thực và theo dõi job ở phía server
Hành trình di chuyển
- Với hơn 700 job production trên 8 vùng dữ liệu độc lập, mỗi nơi có cấu hình mạng và yêu cầu chủ quyền dữ liệu khác nhau, lại còn có các workload bắt buộc không được gián đoạn như lập chỉ mục tìm kiếm, nên cần một kế hoạch có hệ thống
-
Cách tiếp cận theo từng giai đoạn
- Phase 1 – chứng minh khái niệm (PoC): xác thực cách tiếp cận dựa trên Quarry bằng các job pilot, phát triển Operator Quarry đầu tiên rồi kiểm thử trong môi trường dev
- Phase 2 – rà soát bảo mật: phối hợp với đội bảo mật để lập kế hoạch loại bỏ thông tin xác thực, đồng thời xác minh cách tiếp cận REST đáp ứng yêu cầu bảo mật
- Phase 3 – thực thi theo OKR: đưa vào Key Result để có khả năng hiển thị ở cấp quản lý; trong giai đoạn này đã đạt cột mốc 80% di chuyển
- Phase 4 – di chuyển quy mô lớn: nhiều nhóm như Search Infrastructure, Data Engineering & Analytics, ML Services cùng di chuyển song song các workload còn lại trên mọi vùng
- Phase 5 – dọn dẹp cuối cùng: hoàn tất các DAG còn sót, loại bỏ toàn bộ SSH Operator legacy, đạt 100%
-
Các con số di chuyển
- Hơn 700 job được di chuyển trên 7 loại Operator
- Triển khai trên 8 vùng dữ liệu độc lập bằng một rollout được điều phối
- 5 đội đã chuyển sang Operator mới
- Không gián đoạn các dịch vụ cốt lõi của doanh nghiệp
- Từ pilot ban đầu tới loại bỏ SSH 100% chỉ mất 3 quý
Những thách thức gặp phải trong quá trình di chuyển
-
Thách thức 1 — lỗi Virtual Memory Check
- Trong lúc di chuyển DAG export dữ liệu, các job vốn chạy bình thường qua SSH lại thất bại do lỗi kiểm tra vmem
- Nguyên nhân: với SSH, job chạy trực tiếp trên node master nên né được cơ chế ép buộc tài nguyên của YARN; còn Quarry gửi job đúng cách vào YARN nên các container vượt giới hạn bộ nhớ ảo bị từ chối
- Cách giải quyết: tắt kiểm tra vmem trên toàn bộ cụm theo best practice của AWS —
"yarn.nodemanager.vmem-check-enabled": "false"
- Điều này phù hợp với khuyến nghị của AWS rằng việc hạch toán virtual memory trên Linux không đáng tin cậy, và giới hạn physical memory là đủ
- Bài học: SSH đã che giấu nhiều vấn đề; khi chuyển sang gửi job chuẩn qua YARN thì cần lường trước các vấn đề giới hạn tài nguyên vốn trước đây không nhìn thấy, và phải kiểm thử kỹ trong môi trường dev
-
Thách thức 2 — phân tách mạng và sự cố kết nối EKM
- Khi chuyển các job search infrastructure ở dev từ cụm dev sang cụm phân tích staging, đã xảy ra timeout kết nối tới EKM (Enterprise Key Management)
- Lỗi:
Unable to execute HTTP request: Connect to sts.amazonaws.com:443 failed: connect timed out
- Nguyên nhân: cụm ban đầu có sẵn routing mạng tới endpoint quản lý khóa, nhưng cụm phân tích staging nằm trong phân đoạn mạng chặt chẽ hơn lại không có mức kết nối tương đương, làm lộ ra phụ thuộc vào topology mạng vốn không được ghi rõ trong cấu hình job
- Cách giải quyết: chuyển các workload search infrastructure sang cụm dev ETL có thể định tuyến tới dịch vụ dev; giữ lại staging cho các workload cần production Hive catalog; đồng thời scale up cụm dev ETL để tiếp nhận thêm workload
- Bài học: topology mạng là yếu tố cực kỳ quan trọng; trước khi quyết định job nào chạy trên cụm nào, phải hiểu rõ sự phân tách mạng và ranh giới tài khoản
-
Thách thức 3 — độ phức tạp đa vùng
- Do yêu cầu chủ quyền dữ liệu, Slack vận hành các cụm EMR ở 8 vùng dữ liệu độc lập, nên việc loại bỏ SSH trên thực tế tương đương với 8 cuộc di chuyển song song
-
Các yếu tố phức tạp
- Quản lý cấu hình: mỗi vùng cần cấu hình Quarry, endpoint cụm và quy tắc routing mạng riêng
- Gánh nặng kiểm thử: mọi thay đổi mã đều phải được xác minh trên cả 8 vùng
- Triển khai tuần tự: không thể triển khai đồng thời, phải rollout dần theo từng vùng
- Sự cố riêng theo vùng: cấu hình mạng, quy định chủ quyền dữ liệu, khác biệt phiên bản cụm
-
Cách ứng phó
- Xác thực trước ở một vùng pilot duy nhất (chủ yếu tại Mỹ)
- Tài liệu hóa các yêu cầu cấu hình theo từng vùng
- Xây dựng Quarry Operator có nhận thức theo vùng
- Rollout dần dần và áp dụng bài học theo từng vùng
- Theo dõi tiến độ di chuyển riêng cho từng vùng
- Bài học: hạ tầng đa vùng không chỉ khó hơn gấp N lần mà còn khó hơn vì mỗi vùng có các mode lỗi riêng, nên cần dành đủ thời gian cho điều phối liên vùng và debug theo từng vùng
Kết quả
- Đạt loại bỏ SSH 100%, toàn bộ job production đã chuyển sang gửi qua REST thông qua Quarry
-
Thành quả về bảo mật
- Loại bỏ truy cập SSH khỏi các cụm EMR production trên cả 8 vùng dữ liệu độc lập, giúp thu hẹp đáng kể bề mặt tấn công
- Thay việc phân phối khóa SSH bằng xác thực token giữa các dịch vụ, đồng thời có đầy đủ audit trail nhờ logging của REST API
- Mọi lần gửi job đều có log có cấu trúc thông qua Quarry
- Chuyển cụm EMR cuối cùng trong tài khoản AWS chính sang tài khoản con, hoàn tất sáng kiến Whitecastle
- Loại bỏ security group đặc thù và mô hình quản lý quyền phức tạp, từ đó đơn giản hóa tuân thủ
-
Cải thiện về vận hành
- Loại bỏ tranh chấp tài nguyên trên node master; mọi job không thuộc Hadoop đều chạy trong container YARN phân tán với phân bổ tài nguyên phù hợp
- Ngay cả khi Kubernetes Pod phía client khởi động lại, job vẫn tiếp tục, giúp độ tin cậy của job tăng mạnh; tiến trình zombie biến mất và có thể kết thúc đúng cách qua REST API
- Quarry API cung cấp trạng thái job/log/metric có cấu trúc, cho phép theo dõi toàn bộ vòng đời job và xem log container YARN để debug bằng công cụ phù hợp
-
Tạo nền tảng cho tương lai
- Việc loại bỏ phụ thuộc SSH giúp mở đường cho di chuyển sang Spark on Kubernetes
- Kiến trúc dựa trên REST phù hợp với thực hành cloud-native
- So với cấu hình SSH phức tạp, Quarry Operator đơn giản và dễ bảo trì hơn, giúp onboarding đội ngũ thuận lợi
- Tách rời Airflow khỏi các chi tiết hạ tầng EMR
- Chuẩn hóa toàn bộ việc gửi job qua Quarry, giúp các thay đổi trong tương lai trở nên dễ dàng hơn
- Sau 2 năm vận hành production kể từ khi hoàn tất, quyết định kiến trúc này đã được kiểm chứng là đúng đắn, với các cải thiện đồng thời về bảo mật, độ ổn định vận hành và tính linh hoạt của hạ tầng
Bài học rút ra
-
Những gì đã hoạt động tốt
- Di chuyển dần từng bước: rollout tuần tự Dev → GovDev/CommDev → Prod và di chuyển theo từng loại Operator giúp tích lũy bài học theo từng giai đoạn
- Phối hợp nhóm chặt chẽ: sự hợp tác đa lĩnh vực giữa Search, Analytics, Data Engineering, ML, Marketing cùng với code review nhanh và trao đổi qua kênh chung
- Theo dõi tiến độ dựa trên phân tích: xây dựng dashboard theo dõi tiến độ di chuyển trên mọi vùng, dùng truy vấn cơ sở dữ liệu Airflow để xác định các tác vụ còn lại dựa trên SSH
-
Nếu làm lại sẽ thay đổi điều gì
- Cần lập bản đồ topology mạng từ sớm: các vấn đề phân tách mạng như kết nối EKM chỉ được phát hiện ở giai đoạn sau; cần tài liệu hóa ranh giới tài khoản Whitecastle và routing mạng trước khi di chuyển cụm
- Cần kiểm thử giới hạn tài nguyên sớm hơn: vấn đề vmem check xuất hiện khá muộn; nên đưa kiểm thử giới hạn tài nguyên của YARN so với SSH ngay từ giai đoạn pilot đầu tiên
- Tăng cường truyền thông sớm về các giới hạn của Operator: khi hạn chế việc dùng mới
SSHOperator ở giai đoạn cuối, một số nhóm không nắm được; cần thông báo sớm hơn tới toàn bộ người dùng Airflow
-
Best practice cho các đợt di chuyển quy mô lớn
- Xây dựng giám sát trước khi di chuyển: chuẩn bị sớm dashboard để luôn biết còn lại những workload nào, tận dụng truy vấn Airflow DB
- Kiểm thử trên nhiều môi trường: test ở Dev, CommDev, GovDev để phát hiện các vấn đề riêng theo môi trường trước khi lên production, đặc biệt kiểm thử qua ranh giới tài khoản để phát hiện sớm các vấn đề phân tách mạng
- Loại bỏ Operator theo từng bước: với CrunchExecOperator, S3SyncOperator và các loại khác, loại bỏ từng cái một, biến mỗi giai đoạn thành một mini project có kiểm thử và xác minh riêng; chậm hơn nhưng giảm rủi ro đáng kể
Chưa có bình luận nào.