Mở rộng Kubernetes lên 7.500 nút

Chúng tôi đã mở rộng cụm Kubernetes lên 7.500 nút, tạo ra cơ sở hạ tầng có khả năng mở rộng cho các mô hình lớn như  GPT-3 (mở trong cửa sổ mới),  CLIP và  DALL·E , mà còn dành cho nghiên cứu lặp lại quy mô nhỏ nhanh chóng như  Luật tỷ lệ cho Mô hình ngôn ngữ thần kinh(mở trong cửa sổ mới).

Xem thêm: mua tài khoản ChatGPT Plus chính hãng giá rẻ 

Việc mở rộng một cụm Kubernetes duy nhất lên quy mô này hiếm khi được thực hiện và đòi hỏi một số sự quan tâm đặc biệt, nhưng ưu điểm là một cơ sở hạ tầng đơn giản cho phép các nhóm nghiên cứu máy học của chúng tôi di chuyển nhanh hơn và mở rộng quy mô mà không cần thay đổi mã của họ.

Kể từ bài đăng gần đây nhất của chúng tôi về  việc mở rộng quy mô lên 2.500 nút,  chúng tôi đã tiếp tục phát triển cơ sở hạ tầng của mình để đáp ứng nhu cầu của các nhà nghiên cứu, trong quá trình đó, chúng tôi đã học được nhiều bài học bổ sung. Bài đăng này tóm tắt những bài học đó để những người khác trong cộng đồng Kubernetes có thể hưởng lợi từ chúng và kết thúc bằng những vấn đề mà chúng tôi vẫn đang phải đối mặt mà chúng tôi sẽ giải quyết tiếp theo.

Khối lượng công việc của chúng tôi

Trước khi đi sâu hơn, điều quan trọng là phải mô tả khối lượng công việc của chúng tôi. Các ứng dụng và phần cứng chúng tôi chạy với Kubernetes khá khác so với những gì bạn có thể gặp phải ở một công ty thông thường. Các vấn đề và giải pháp tương ứng của chúng tôi có thể phù hợp hoặc không phù hợp với thiết lập của riêng bạn!

Một công việc học máy lớn trải dài trên nhiều nút và chạy hiệu quả nhất khi nó có quyền truy cập vào tất cả các tài nguyên phần cứng trên mỗi nút. Điều này cho phép GPU giao tiếp chéo trực tiếp bằng  NVLink (mở trong cửa sổ mới)hoặc GPU để giao tiếp trực tiếp với NIC bằng  GPUDirect (mở trong cửa sổ mới). Vì vậy, đối với nhiều khối lượng công việc của chúng tôi, một pod duy nhất chiếm toàn bộ nút. Bất kỳ sự tranh chấp tài nguyên NUMA, CPU hoặc PCIE nào cũng không phải là yếu tố để lập lịch. Đóng gói bin hoặc phân mảnh không phải là vấn đề phổ biến. Các cụm hiện tại của chúng tôi có băng thông chia đôi đầy đủ, vì vậy chúng tôi cũng không cân nhắc đến giá đỡ hoặc cấu trúc mạng. Tất cả điều này có nghĩa là, mặc dù chúng tôi có nhiều nút, nhưng trình lập lịch có mức căng thẳng tương đối thấp.

Nói như vậy, áp lực lên kube-scheduler là rất lớn. Một công việc mới có thể bao gồm hàng trăm pod được tạo cùng một lúc, sau đó quay lại với tỷ lệ churn tương đối thấp.

Các công việc lớn nhất của chúng tôi chạy MPI và tất cả các pod trong công việc đều tham gia vào một bộ giao tiếp MPI duy nhất. Nếu bất kỳ pod nào tham gia bị chết, toàn bộ công việc sẽ dừng lại và cần phải khởi động lại. Các điểm kiểm tra công việc thường xuyên và khi được khởi động lại, nó sẽ tiếp tục từ điểm kiểm tra cuối cùng. Do đó, chúng tôi coi các pod là  bán trạng thái —các pod bị chết có thể được thay thế và công việc có thể tiếp tục, nhưng việc làm như vậy sẽ gây gián đoạn và nên được giữ ở mức tối thiểu.

Chúng tôi không phụ thuộc nhiều vào cân bằng tải Kubernetes. Chúng tôi có rất ít lưu lượng HTTPS, không cần thử nghiệm A/B, blue/green hoặc canaries. Các pod giao tiếp trực tiếp với nhau trên địa chỉ IP pod của chúng với MPI qua SSH, không phải điểm cuối dịch vụ. "Khám phá" dịch vụ bị giới hạn; chúng tôi chỉ thực hiện tra cứu một lần để biết pod nào đang tham gia MPI tại thời điểm khởi động công việc.

Hầu hết các công việc đều tương tác với một số dạng lưu trữ blob. Chúng thường truyền trực tuyến một số phân đoạn của tập dữ liệu hoặc điểm kiểm tra trực tiếp từ lưu trữ blob hoặc lưu trữ đệm vào đĩa cục bộ nhanh. Chúng tôi có một số PersistentVolume cho các trường hợp mà ngữ nghĩa POSIX hữu ích, nhưng lưu trữ blob có khả năng mở rộng hơn nhiều và không yêu cầu các hoạt động tách/gắn chậm.

Cuối cùng, bản chất công việc của chúng tôi về cơ bản là nghiên cứu, có nghĩa là khối lượng công việc luôn thay đổi. Trong khi nhóm Supercomputing nỗ lực cung cấp những gì chúng tôi coi là mức chất lượng "sản xuất" của cơ sở hạ tầng điện toán, thì các ứng dụng chạy trên cụm đó lại tồn tại trong thời gian ngắn và các nhà phát triển của chúng lặp lại nhanh chóng. Các mô hình sử dụng mới có thể xuất hiện bất cứ lúc nào thách thức các giả định của chúng tôi về xu hướng và sự đánh đổi phù hợp. Chúng tôi cần một hệ thống bền vững cũng cho phép chúng tôi phản ứng nhanh khi mọi thứ thay đổi.

Mạng lưới

Khi số lượng nút và nhóm trong cụm của chúng tôi tăng lên, chúng tôi thấy rằng Flannel gặp khó khăn trong việc mở rộng thông lượng cần thiết. Chúng tôi chuyển sang sử dụng các công nghệ mạng nhóm gốc cho Cấu hình IP của chúng tôi cho Azure VMSS và các plugin CNI có liên quan. Điều này cho phép chúng tôi có được thông lượng mạng cấp máy chủ trên các nhóm của mình.

Một lý do khác khiến chúng tôi chuyển sang sử dụng địa chỉ IP dựa trên bí danh là vì trên các cụm lớn nhất của chúng tôi, chúng tôi có thể có khoảng 200.000 địa chỉ IP được sử dụng tại bất kỳ thời điểm nào. Khi chúng tôi thử nghiệm mạng pod dựa trên tuyến đường, chúng tôi thấy có những hạn chế đáng kể về số lượng tuyến đường mà chúng tôi có thể sử dụng hiệu quả.

Tránh đóng gói làm tăng nhu cầu về SDN hoặc công cụ định tuyến cơ bản, nhưng nó giúp thiết lập mạng của chúng ta đơn giản. Có thể thêm VPN hoặc đường hầm mà không cần bất kỳ bộ điều hợp bổ sung nào. Chúng ta không cần lo lắng về việc phân mảnh gói tin do một số phần của mạng có MTU thấp hơn. Chính sách mạng và giám sát lưu lượng truy cập rất đơn giản; không có sự mơ hồ về nguồn và đích của các gói tin.

Chúng tôi sử dụng gắn thẻ iptables trên máy chủ để theo dõi việc sử dụng tài nguyên mạng theo Không gian tên và nhóm. Điều này cho phép các nhà nghiên cứu hình dung các mẫu sử dụng mạng của họ. Đặc biệt, vì nhiều thí nghiệm của chúng tôi có các mẫu giao tiếp Internet và nội bộ nhóm riêng biệt, nên thường hữu ích khi có thể điều tra xem có bất kỳ nút thắt nào có thể xảy ra.

Các quy tắc iptables  mangle có thể được sử dụng để đánh dấu tùy ý các gói tin khớp với các tiêu chí cụ thể. Sau đây là các quy tắc của chúng tôi để phát hiện xem lưu lượng truy cập là nội bộ hay kết nối internet. Các  FORWARD quy tắc bao gồm lưu lượng truy cập từ pod, vs  INPUT và  OUTPUT lưu lượng truy cập từ máy chủ:

văn bản thuần túy
1234
1
iptables -t mangle -A INPUT ! -s 10.0.0.0/8 -m comment --comment "iptables-exporter openai traffic=internet-in"
2
iptables -t mangle -A FORWARD ! -s 10.0.0.0/8 -m comment --comment "iptables-exporter openai traffic=internet-in"
3
iptables -t mangle -A OUTPUT ! -d 10.0.0.0/8 -m comment --comment "iptables-exporter openai traffic=internet-out"
4
iptables -t mangle -A FORWARD ! -d 10.0.0.0/8 -m comment --comment "iptables-exporter openai traffic=internet-out"

Sau khi đánh dấu, iptables sẽ bắt đầu đếm để theo dõi số byte và gói tin khớp với quy tắc này. Bạn có thể ước lượng các bộ đếm này bằng cách sử dụng  iptables chính nó:

văn bản thuần túy
 
123456
1
% iptables -t mangle -L -v
2
Chain FORWARD (policy ACCEPT 50M packets, 334G bytes)
3
pkts bytes target prot opt in out source destination
4
....
5
1253K 555M all -- any any anywhere !10.0.0.0/8 /* iptables-exporter openai traffic=internet-out */
6
1161K 7937M all -- any any !10.0.0.0/8 anywhere /* iptables-exporter openai traffic=internet-in */

Chúng tôi sử dụng một trình xuất Prometheus mã nguồn mở có tên là  iptables-exporter (mở trong cửa sổ mới) để sau đó theo dõi chúng vào hệ thống giám sát của chúng tôi. Đây là một cách đơn giản để theo dõi các gói tin phù hợp với nhiều loại điều kiện khác nhau.

Một khía cạnh khá độc đáo của mô hình mạng của chúng tôi là chúng tôi cung cấp đầy đủ các phạm vi CIDR của nút, pod và mạng dịch vụ cho các nhà nghiên cứu của mình. Chúng tôi có mô hình mạng hub và spoke, và sử dụng các phạm vi CIDR của nút và pod gốc để định tuyến lưu lượng đó. Các nhà nghiên cứu kết nối với hub và từ đó có thể truy cập vào bất kỳ cụm riêng lẻ nào (các spoke). Nhưng bản thân các cụm không thể giao tiếp với nhau. Điều này đảm bảo rằng các cụm vẫn được cô lập mà không có sự phụ thuộc giữa các cụm có thể phá vỡ sự cô lập lỗi.

Chúng tôi sử dụng máy chủ “NAT” để dịch phạm vi CIDR của mạng dịch vụ cho lưu lượng truy cập đến từ bên ngoài cụm. Thiết lập này cho phép các nhà nghiên cứu của chúng tôi có sự linh hoạt đáng kể trong việc lựa chọn cách thức và loại cấu hình mạng mà họ có thể lựa chọn cho các thí nghiệm của mình.

Máy chủ API

Kubernetes API Servers và etcd là những thành phần quan trọng đối với một cụm làm việc lành mạnh, vì vậy chúng tôi đặc biệt chú ý đến áp lực trên các hệ thống này. Chúng tôi sử dụng bảng điều khiển Grafana do  kube-prometheus cung cấp (mở trong cửa sổ mới), cũng như các bảng điều khiển nội bộ bổ sung. Chúng tôi thấy hữu ích khi cảnh báo về tỷ lệ trạng thái HTTP 429 (Quá nhiều yêu cầu) và 5xx (Lỗi máy chủ) trên Máy chủ API như một tín hiệu cấp cao về sự cố.

Trong khi một số người chạy Máy chủ API trong kube, chúng tôi luôn chạy chúng bên ngoài cụm. Cả máy chủ etcd và API đều chạy trên các nút chuyên dụng của riêng chúng. Các cụm lớn nhất của chúng tôi chạy 5 máy chủ API và 5 nút etcd để phân tán tải và giảm thiểu tác động nếu một trong số chúng bị sập. Chúng tôi không gặp sự cố đáng chú ý nào với etcd kể từ khi tách Sự kiện Kubernetes thành cụm etcd riêng của chúng trong  bài đăng trên blog gần đây nhất của chúng tôi . Máy chủ API không có trạng thái và thường dễ chạy trong nhóm phiên bản tự phục hồi hoặc tập hợp quy mô. Chúng tôi vẫn chưa thử xây dựng bất kỳ chức năng tự động hóa tự phục hồi nào của các cụm etcd vì sự cố rất hiếm khi xảy ra.

Máy chủ API có thể chiếm khá nhiều bộ nhớ và có xu hướng mở rộng tuyến tính theo số lượng nút trong cụm. Đối với cụm của chúng tôi với 7.500 nút, chúng tôi quan sát thấy có tới 70GB heap được sử dụng cho mỗi Máy chủ API, vì vậy may mắn thay, điều này sẽ tiếp tục nằm trong khả năng phần cứng trong tương lai

Một áp lực lớn đối với Máy chủ API là WATCH trên Điểm cuối. Có một số dịch vụ, chẳng hạn như 'kubelet' và 'node-exporter' mà mọi nút trong cụm đều là thành viên. Khi một nút được thêm vào hoặc xóa khỏi cụm, WATCH này sẽ kích hoạt. Và vì thông thường mỗi nút tự theo dõi dịch  kubelet vụ thông qua kube-proxy, nên # và băng thông cần thiết trong các phản hồi này sẽ là N2N2 và rất lớn, đôi khi là 1GB/giây hoặc hơn.  EndpointSlices (mở trong cửa sổ mới), được ra mắt trong Kubernetes 1.17, là một lợi ích to lớn giúp giảm tải xuống 1000 lần.

Nhìn chung, chúng tôi rất lưu ý đến bất kỳ yêu cầu nào của API Server có quy mô theo kích thước của cụm. Chúng tôi cố gắng tránh để bất kỳ DaemonSet nào tương tác với API Server. Trong trường hợp bạn cần mỗi nút để theo dõi các thay đổi, hãy giới thiệu một dịch vụ lưu trữ đệm trung gian, chẳng hạn như  Datadog Cluster Agent (mở trong cửa sổ mới), có vẻ như là một mô hình tốt để tránh tình trạng tắc nghẽn trên toàn cụm.

Khi các cụm của chúng tôi phát triển, chúng tôi ít tự động mở rộng quy mô thực tế của các cụm. Nhưng đôi khi chúng tôi gặp sự cố khi tự động mở rộng quy mô quá nhiều cùng một lúc. Có nhiều yêu cầu được tạo ra khi một nút mới tham gia vào cụm và việc thêm hàng trăm nút cùng một lúc có thể làm quá tải dung lượng máy chủ API. Làm mịn điều này, thậm chí chỉ trong vài giây, đã giúp tránh được tình trạng ngừng hoạt động.

Số liệu chuỗi thời gian với Prometheus và Grafana

Chúng tôi sử dụng Prometheus để thu thập số liệu chuỗi thời gian và Grafana cho biểu đồ, bảng thông tin và cảnh báo. Chúng tôi bắt đầu bằng việc triển khai  kube-prometheus (mở trong cửa sổ mới) thu thập nhiều loại số liệu và bảng thông tin tốt để trực quan hóa. Theo thời gian, chúng tôi đã thêm nhiều bảng thông tin, số liệu và cảnh báo của riêng mình.

Khi chúng tôi thêm ngày càng nhiều nút, chúng tôi gặp khó khăn với số lượng lớn các số liệu được Prometheus thu thập. Trong khi kube-prometheus phơi bày rất nhiều dữ liệu hữu ích, một số trong số đó chúng tôi thực sự không bao giờ xem xét và một số chỉ quá chi tiết để thu thập, lưu trữ và truy vấn hiệu quả. Chúng tôi sử dụng  các quy tắc Prometheus (mở trong cửa sổ mới) để “loại bỏ” một số số liệu này khỏi quá trình thu thập.

Trong một thời gian, chúng tôi đã vật lộn với một vấn đề mà Prometheus sẽ tiêu thụ ngày càng nhiều bộ nhớ cho đến khi cuối cùng làm hỏng container trong lỗi Out-Of-Memory (OOM). Điều này dường như xảy ra ngay cả sau khi ném một lượng lớn dung lượng bộ nhớ vào ứng dụng. Tệ hơn nữa là, khi nó bị sập, phải mất nhiều giờ để khởi động lại các tệp nhật ký ghi trước khi có thể sử dụng lại.

Cuối cùng chúng tôi  đã tìm ra nguồn gốc của những OOM này (mở trong cửa sổ mới) là tương tác giữa Grafana và Prometheus, trong đó Grafana sẽ sử dụng API  /api/v1/series trên Prometheus với truy vấn  {le!=""} (Về cơ bản, "cho tôi tất cả các số liệu biểu đồ"). Việc triển khai  /api/v1/series không bị giới hạn về cả thời gian và không gian—đối với một truy vấn có nhiều kết quả, điều này sẽ tiếp tục tiêu tốn nhiều bộ nhớ và thời gian hơn. Nó cũng tiếp tục phát triển ngay cả sau khi người yêu cầu đã từ bỏ và đóng kết nối. Đối với chúng tôi, không bao giờ có đủ bộ nhớ và Prometheus cuối cùng sẽ bị sập. Chúng tôi  đã vá (mở trong cửa sổ mới) Prometheus sẽ đưa API này vào trong một Context để áp dụng lệnh tạm dừng, điều này đã khắc phục được hoàn toàn vấn đề.

Mặc dù Prometheus ít bị sập hơn, nhưng vào những lúc chúng tôi cần khởi động lại, việc phát lại WAL vẫn là một vấn đề. Thường mất nhiều giờ để phát lại tất cả các nhật ký WAL trước khi Prometheus bắt đầu thu thập số liệu mới và phục vụ các truy vấn. Với sự trợ giúp của  Robust Perception (mở trong cửa sổ mới), chúng tôi thấy rằng việc áp dụng a  GOMAXPROCS=24 có cải thiện lớn. Prometheus cố gắng sử dụng tất cả các lõi khi phát lại WAL và đối với các máy chủ có nhiều lõi, sự tranh chấp sẽ làm giảm hiệu suất.

Chúng tôi đang khám phá các tùy chọn mới để tăng khả năng giám sát của mình, được mô tả trong phần “ Các vấn đề chưa được giải quyết ” bên dưới.

Kiểm tra sức khỏe

Với một cụm lớn như vậy, tất nhiên chúng tôi dựa vào tự động hóa để phát hiện và loại bỏ các nút hoạt động không bình thường khỏi cụm. Theo thời gian, chúng tôi đã xây dựng một số hệ thống kiểm tra sức khỏe.

Kiểm tra sức khỏe thụ động

Một số kiểm tra sức khỏe là thụ động, luôn chạy trên tất cả các nút. Những kiểm tra này giám sát các tài nguyên hệ thống cơ bản như khả năng tiếp cận mạng, đĩa bị lỗi hoặc đầy hoặc lỗi GPU. GPU thể hiện các vấn đề theo nhiều cách khác nhau, nhưng một lỗi phổ biến dễ gặp là "Lỗi ECC không thể sửa". Các công cụ Quản lý GPU Trung tâm dữ liệu (DCGM) của Nvidia giúp dễ dàng truy vấn lỗi này và một số lỗi "Xid" khác. Một cách chúng tôi theo dõi các lỗi này là thông qua  dcgm-exporter (mở trong cửa sổ mới) để nhập số liệu vào Prometheus, hệ thống giám sát của chúng tôi. Số liệu này sẽ xuất hiện dưới dạng số  DCGM_FI_DEV_XID_ERRORS liệu và được đặt thành mã lỗi xảy ra gần đây nhất. Ngoài ra,  NVML Device Query API (mở trong cửa sổ mới) cung cấp thông tin chi tiết hơn về tình trạng hoạt động và sức khỏe của GPU.

Khi phát hiện ra lỗi, chúng ta thường có thể khắc phục bằng cách đặt lại GPU hoặc hệ thống, mặc dù trong một số trường hợp, điều này có thể dẫn đến việc phải thay thế GPU cơ bản.

Một dạng kiểm tra sức khỏe khác theo dõi các sự kiện bảo trì từ nhà cung cấp đám mây thượng nguồn. Mỗi nhà cung cấp đám mây lớn đều có cách để biết liệu VM hiện tại có phải là sự kiện bảo trì sắp tới hay không, sự kiện này cuối cùng sẽ gây ra sự gián đoạn. VM có thể cần được khởi động lại để có thể áp dụng bản vá hypervisor cơ bản hoặc hoán đổi nút vật lý cho phần cứng khác.

Các kiểm tra sức khỏe thụ động này chạy liên tục ở chế độ nền trên tất cả các nút. Nếu kiểm tra sức khỏe bắt đầu không thành công, nút sẽ tự động được cô lập để không có pod mới nào được lên lịch trên nút. Đối với các lỗi kiểm tra sức khỏe nghiêm trọng hơn, chúng tôi cũng sẽ thử loại bỏ pod để yêu cầu tất cả các pod đang chạy thoát ngay lập tức. Bản thân pod vẫn có thể quyết định xem có muốn cho phép loại bỏ này xảy ra hay không, có thể cấu hình thông qua Ngân sách gián đoạn Pod. Cuối cùng, sau khi tất cả các pod đã chấm dứt hoặc đã trôi qua 7 ngày (một phần trong SLA của chúng tôi), chúng tôi sẽ buộc chấm dứt VM.

Kiểm tra GPU đang hoạt động

Thật không may, không phải tất cả các vấn đề về GPU đều biểu hiện dưới dạng mã lỗi có thể nhìn thấy thông qua DCGM. Chúng tôi đã xây dựng thư viện thử nghiệm riêng của mình để kiểm tra GPU nhằm phát hiện thêm các vấn đề và đảm bảo rằng phần cứng và trình điều khiển hoạt động như mong đợi. Các thử nghiệm này không thể chạy ở chế độ nền—chúng yêu cầu sử dụng riêng GPU trong vài giây hoặc vài phút để chạy.

Đầu tiên, chúng tôi chạy các thử nghiệm này trên các nút khi khởi động, trong một hệ thống mà chúng tôi gọi là "preflight". Tất cả các nút tham gia cụm với một "preflight" taint và nhãn được áp dụng. Taint này ngăn các pod thông thường được lên lịch trên nút. Một DaemonSet được cấu hình để chạy các pod thử nghiệm preflight trên tất cả các nút có nhãn này. Sau khi hoàn thành thành công thử nghiệm, bản thân thử nghiệm sẽ xóa taint và nhãn và sau đó nút có thể sử dụng chung.

Sau đó, chúng tôi cũng chạy các bài kiểm tra này theo định kỳ trong suốt vòng đời của một nút. Chúng tôi chạy bài kiểm tra này dưới dạng CronJob, cho phép nó hạ cánh trên bất kỳ nút nào có sẵn trong cụm. Phải thừa nhận rằng điều này hơi ngẫu nhiên và không được kiểm soát về việc các nút nào được kiểm tra, nhưng chúng tôi thấy rằng theo thời gian, nó cung cấp phạm vi bao phủ đủ với sự phối hợp hoặc gián đoạn tối thiểu.

Hạn ngạch và sử dụng tài nguyên

Khi chúng tôi mở rộng các cụm của mình, các nhà nghiên cứu bắt đầu thấy mình gặp khó khăn trong việc khai thác toàn bộ năng lực được phân bổ. Các hệ thống lập lịch công việc truyền thống có nhiều tính năng khác nhau để chạy công việc một cách công bằng giữa các nhóm cạnh tranh, trong khi Kubernetes không có. Theo thời gian, chúng tôi lấy cảm hứng từ các hệ thống lập lịch công việc đó và xây dựng một số khả năng theo cách gốc Kubernetes.

Đội bị ô nhiễm

Chúng tôi có một dịch vụ trong mỗi cụm, “team-resource-manager” có nhiều chức năng. Nguồn dữ liệu của nó là một ConfigMap chỉ định các bộ (bộ chọn nút, nhãn nhóm để áp dụng, số lượng phân bổ) cho tất cả các nhóm nghiên cứu có năng lực trong một cụm nhất định. Nó điều hòa điều này với các nút hiện tại trong cụm, làm hỏng số lượng nút thích hợp bằng  openai.com/team=teamname:NoSchedule.

team-resource-manager” cũng có dịch vụ webhook chấp nhận, theo đó khi mỗi công việc được gửi, một sự khoan dung tương ứng sẽ được áp dụng dựa trên tư cách thành viên nhóm của người gửi. Sử dụng taints cho phép chúng ta hạn chế trình lập lịch pod Kubernetes một cách linh hoạt, chẳng hạn như cho phép khoan dung “bất kỳ” đối với các pod có mức độ ưu tiên thấp hơn, cho phép các nhóm mượn năng lực của nhau mà không cần sự phối hợp chặt chẽ.

Bóng bay CPU & GPU

Ngoài việc sử dụng cluster-autoscaler để mở rộng quy mô động các cụm được VM hỗ trợ, chúng tôi sử dụng nó để khắc phục (xóa và thêm lại) các thành viên không lành mạnh trong cụm. Chúng tôi thực hiện điều này bằng cách đặt "kích thước tối thiểu" của cụm thành 0 và "kích thước tối đa" của cụm thành dung lượng khả dụng. Tuy nhiên, cluster-autoscaler, nếu thấy các nút nhàn rỗi, sẽ cố gắng thu hẹp quy mô xuống chỉ còn dung lượng cần thiết. Vì nhiều lý do (độ trễ quay vòng VM, chi phí được phân bổ trước, tác động đến máy chủ API đã đề cập ở trên), việc mở rộng quy mô nhàn rỗi này không lý tưởng.

Vì vậy, chúng tôi đã giới thiệu một Triển khai bóng bay cho cả máy chủ chỉ có CPU và GPU của chúng tôi. Triển khai này chứa một ReplicaSet với số lượng pod có mức độ ưu tiên thấp "kích thước tối đa". Các pod này chiếm tài nguyên trong một nút, do đó trình tự động điều chỉnh không coi chúng là nhàn rỗi. Tuy nhiên, vì chúng có mức độ ưu tiên thấp, nên trình lập lịch có thể loại bỏ chúng ngay lập tức để dành chỗ cho công việc thực tế. (Chúng tôi đã chọn sử dụng Triển khai thay vì DaemonSet, để tránh DaemonSet bị coi là khối lượng công việc nhàn rỗi trên một nút.)

Một điều cần lưu ý, chúng tôi sử dụng pod anti-affinity để đảm bảo các pod sẽ phân bổ đều trên các nút. Các phiên bản trước của trình lập lịch Kubernetes có Ồ(N2) TRÊN2) vấn đề về hiệu suất với pod anti-affinity. Vấn đề này đã được khắc phục kể từ Kubernetes 1.18.

Lịch trình của băng đảng

Các thí nghiệm của chúng tôi thường liên quan đến một hoặc nhiều StatefulSet, mỗi StatefulSet vận hành một phần khác nhau của nỗ lực đào tạo. Đối với Optimizers, các nhà nghiên cứu cần tất cả các thành viên của StatefulSet được lên lịch trước khi có thể thực hiện bất kỳ quá trình đào tạo nào (vì chúng tôi thường sử dụng MPI để phối hợp giữa các thành viên optimizer và MPI nhạy cảm với các thay đổi về thành viên nhóm).

Tuy nhiên, Kubernetes theo mặc định sẽ không nhất thiết ưu tiên thực hiện tất cả các yêu cầu từ một StatefulSet hơn một StatefulSet khác. Ví dụ, nếu hai thí nghiệm đều yêu cầu 100% dung lượng của cụm, thay vì lên lịch cho tất cả một thí nghiệm hoặc thí nghiệm kia, Kubernetes có thể chỉ lên lịch một nửa số pod của mỗi thí nghiệm, dẫn đến bế tắc khi không thí nghiệm nào có thể tiến triển.

Chúng tôi đã thử một vài thứ cần một trình lập lịch tùy chỉnh, nhưng gặp phải các trường hợp ngoại lệ gây ra xung đột với cách các pod thông thường được lập lịch. Kubernetes 1.18 đã giới thiệu một kiến ​​trúc plugin cho trình lập lịch Kubernetes cốt lõi, giúp việc thêm các tính năng như thế này dễ dàng hơn nhiều. Gần đây chúng tôi đã đưa vào  plugin Coscheduling (mở trong cửa sổ mới) như một cách tốt để giải quyết vấn đề này.

Những vấn đề chưa được giải quyết

Vẫn còn nhiều vấn đề cần giải quyết khi chúng tôi mở rộng cụm Kubernetes của mình. Một số trong số đó bao gồm:

Số liệu

Ở quy mô của chúng tôi, chúng tôi đã gặp nhiều khó khăn với công cụ lưu trữ TSDB tích hợp của Prometheus chậm để nén và cần nhiều thời gian để phát lại WAL (Write-Ahead-Log) bất cứ khi nào nó khởi động lại. Các truy vấn cũng có xu hướng dẫn đến lỗi "xử lý truy vấn sẽ tải quá nhiều mẫu". Chúng tôi đang trong quá trình di chuyển sang một công cụ lưu trữ và truy vấn tương thích với Prometheus khác. Mong chờ bài đăng trên blog trong tương lai về cách thức thực hiện!

Định hình lưu lượng mạng Pod

Khi chúng tôi mở rộng các cụm của mình, mỗi nhóm được tính toán để có một lượng băng thông Internet nhất định. Tổng nhu cầu băng thông Internet cho mỗi người đã trở nên đáng kể và các nhà nghiên cứu của chúng tôi hiện có khả năng vô tình gây áp lực tài nguyên đáng kể lên các vị trí khác trên Internet, chẳng hạn như các tập dữ liệu để tải xuống và các gói phần mềm để cài đặt.

Kết luận

Chúng tôi thấy Kubernetes là một nền tảng cực kỳ linh hoạt cho nhu cầu nghiên cứu của chúng tôi. Nó có khả năng mở rộng quy mô để đáp ứng khối lượng công việc đòi hỏi khắt khe nhất mà chúng tôi đã đưa vào. Tuy nhiên, vẫn còn nhiều lĩnh vực cần cải thiện và nhóm Supercomputing tại OpenAI sẽ tiếp tục khám phá cách Kubernetes có thể mở rộng quy mô. Nếu loại công việc này có vẻ thú vị, bạn nên cân nhắc nộp đơn  tại OpenAI!

Hot Deal

Họ tên (*)

Số điện thoại (*)

Email (*)

Dịch vụ

Đăng ký để nhận bản tin mới nhất !