CADS từ khi làm giấy khai sinh đến nay mới hơn 6 tuổi. Tính ra thì cũng chỉ mới vào lớp 1. Nhưng mà khoan, trong thế giới công nghệ, chỉ cần 1 ngày thôi mọi thứ đã có thể thay đổi hoàn toàn rồi, bài viết này sẽ nói về sự tiến hóa của một công cụ mà có thể xem nó là cánh cổng để các bạn Data Scientist bắt đầu tiến vào và đào xới dữ liệu. Chặng đường này có 4 thời kì chính, mà đến nay thì chúng tôi vẫn đang ở đâu đó thời kì thứ 3, chưa biết đến bao giờ mới kích được lên đời 4.
Đó-là-Jupyter. Jupyter là sự kết hợp giữa Julia-Python-R, nhưng cũng có thể xem là một cách viết biến tấu từ Jupiter, nghĩa là mộc tinh (vì vậy mà bài này mới có tên như vậy). Jupyter có thể xem như là một web based IDE, nhưng được xây dựng hướng đến việc xử lý dữ liệu. User có thể code trực tiếp trên web và chạy luôn từng block code một, kết quả sẽ được trả ra in-line, thậm chí là vẽ graph luôn cũng được. Nó hỗ trợ rất nhiều ngôn ngữ lập trình khác nhau, với mỗi ngôn ngữ như vậy được gọi là những kernel. Tuy nhiên, ở CADS chúng tôi vẫn sử dụng chính là Python. Vì ngôn ngữ này được xây dựng theo hướng thông dịch, nó rất hợp với Jupyter, nhờ có chức năng tạo môi trường ảo, nhiều người có thể làm cùng lúc nhiều dự án khác nhau trên cùng một máy chủ. Nhưng cũng từ đó mà có lắm chuyện bi hài xảy ra, theo từng thời kì.
1. Thời kì tăm tối
Hệ thống của CADS sử dụng công cụ quản lý credentials tập trung là FreeIPA (bản miễn phí của Redhat Satellite), mục tiêu để kiểm soát quyền truy cập vào từng thành phần hệ thống của user. FreeIPA hoạt động qua service SSSD, việc chứng thực hoàn toàn thông qua service này mà không dựa vào local authen. Do đó mà trên server cũng không tồn tại local user nào. Và câu chuyện bắt đầu từ đây.
Jupyter – thời kì tăm tối
Ngày đấy, chúng tôi có vài server khác nhau, cấu hình cũng khá mạnh. Nhưng vấn đề là dự án của chúng tôi thì cũng không nhẹ nhàng gì. Mỗi lần user chạy job 1 phát thì chuyện CPU load lên vài trăm, RAM hết dăm bảy trăm GB cũng không còn lạ lẫm gì nữa. Được đến ngày thứ 10 mà server chưa phải reboot đã là điều kì diệu. 😕
Mà, lúc đó thì Jupyter vẫn đăng nhập thông qua PAM, hay chính là dùng SSSD đấy, vậy nên ông bà nào được cấp quyền vào server nào chạy thì chỉ được vào mỗi chỗ đó, nhìn server khác có khi đang trống mà cũng chẳng thể vào. Việc cấp phép cho đăng nhập thì cũng dễ thôi, nhưng rồi môi trường đâu mà làm việc? Vì lúc đấy, các môi trường được quản lý bằng conda, lại cài độc lập trên từng server một, nên xem như ai ở đâu đứng nguyên ở đấy, hàng đợi có dài thì cũng phải chịu, muốn qua hàng khác cũng không có cách nào. Việc quản lý cấp phát tài nguyên cho từng user cũng không khả thi, vì đơn giản là dùng SSSD nên các user không tồn tại ở local, các kiểu cấu hình truyền thống hầu như không có tác dụng, document của Jupyter cũng nói luôn là dùng kiểu local user này thì việc quản lý resource xem như là giấc mơ.
Việc quản lý môi trường ảo lúc đấy cũng cực khổ không kém, do tất cả được cài đặt chung với nhau, cũng chưa biết cách phân quyền nên tất cả việc cài đặt phải do admin thực hiện, mà admin cũng đâu nắm hết được mã nguồn của các bạn, cài xong cho người này thì người kia không chạy được do conflict cái gì đấy cũng đã là chuyện không còn xa lạ gì.
Rồi đến câu chuyện monitor. Chúng tôi dùng Prometheus, monitor cũng được hầu hết các metrics của hệ thống, nhưng mà lại không có cách nào monitor tài nguyên mà từng user đang sử dụng, chỉ nhìn được mỗi số tổng. Chúng tôi cũng cài atop để theo dõi và lưu lại history, nhưng chính atop cũng hay chết vì Out of Memory. Chán!
Mỗi lần server treo, ngoài reboot ra thì cũng chẳng có phương án gì khác, vì có cách nào biết được là user nào đang dùng tài nguyên nhiều ít thế nào đâu, cũng làm tư tưởng, cũng hướng dẫn đủ thứ, thì cũng có cải thiện, trước 3 ngày reboot 1 lần nay lên được 5 ngày mới treo 😕 . Tội nhất là mấy bạn, có trường hợp chạy đến 95% rồi thì server tạch, phải chạy lại từ đầu. Còn vì ai mà nên nỗi? Không ai biết 😥
Ngoài chuyện treo và không thể cân bằng tài nguyên thừa, thời điểm này Jupyter vẫn còn là Jupyter Notebook, với giao diện không hỗ trợ tab, user muốn làm việc với nhiều file code cùng lúc thì phải mở nhiều tab trình duyệt. Mở chừng chục tab thì bắt đầu bye bye trình duyệt luôn, quên save thì xem như khóc.
Giao diện mỗi lần mở chỉ 1 notebook
2. Thời kì phong kiến
Những năm sau đó, chúng tôi bắt đầu chuyển đổi dần hệ thống sau hướng containerlized và sau là microservice. Lúc này, Jupyter cũng nằm trong nhóm cần phải cải tiến. Phần là để phù hợp với định hướng xây dựng hệ thống, phần khác cũng là để giải quyết những pain point đã tồn tại quá lâu mà không có cách nào xử lý được. Chúng tôi quyết định nghiên cứu để chuyển Jupyter lên môi trường container.
Đâu tiên, chúng tôi quyết định mang JupyterLab đến thay cho Jupyter Notebook đã cũ kỹ và sắp hết niên hạn. Về chức năng mặc dù không có quá nhiều cải tiến, tuy nhiên JupyterLab đã làm được một thứ là hỗ trợ multi tab, cho phép người dùng làm việc với nhiều notebook cùng lúc mà không phải mở quá nhiều tab trình duyệt. Thứ hai, chúng tôi cũng cấu hình docker để giới hạn tài nguyên của từng container được tạo ra, không còn tình trạng một user có thể chiếm trọn tài nguyên của cả server nữa, mọi thứ có vẻ đẹp. Nhưng, nỗi đau lại xuất hiện 🙁
Do dùng ở môi trường docker, nghĩa là stateless, chúng tôi đã xác định, userdata và dữ liệu phân tích sẽ phải được volume để đảm bảo tính toàn vẹn. Ngay từ khi xây dựng, hệ thống của CADS đã sử dụng SSSD để làm dịch vụ chứng thực trung tâm. Trước đây, khi sử dụng PAM, Jupyter có thể đọc được các phân quyền này thông qua SSSD, nhưng giờ vào trong container, môi trường trong đấy thì không có SSSD, cũng chẳng có local user trong các file hệ thống của Linux để mà mount vào. Kết quả là user không đọc được data, kể cả là của chính mình.
JupyterLab nay đã đẹp và mạnh hơn nhiều
Sau một thời gian nghiên cứu, chúng tôi cũng tìm ra hướng giải quyết cho vấn đề này bằng cách sử dụng chính dịch vụ LDAP của FreeIPA, chúng tôi đã tạo ra thêm 1 lớp tương thích nữa đứng giữa Jupyter và volumes, nhiệm vụ chính của nó là thêm các phân quyền cần thiết vào container mỗi khi được khởi tạo. Vấn đề xem như tạm ổn.
Song song với đó, việc monitor cũng được cải thiện rất nhiều nhờ có cAdvisor, cho phép chúng tôi monitor đến từng container, vì vậy việc theo dõi việc sử dụng tài nguyên của từng user trở nên hiệu quả. Chúng tôi cũng xây dựng Dashboard trên Grafana để các bạn tự theo dõi được việc sử dụng tài nguyên ra sao, từ đó mà sắp xếp sử dụng server nào cho hợp lý. Khoan, “sắp xếp sử dụng server nào cho hợp lý” nghĩa là user vẫn phải chọn? Đúng vậy, nhờ tách riêng các môi trường ảo, user data ra một storage độc lập, lúc này user có thể đăng nhập trên bất kỳ server nào mà vẫn bảo toàn được môi trường làm việc của mình, nhưng do chưa có cơ chế load balacing tự động, việc quyết định sẽ login vào đâu vẫn do user quyết định, và vẫn xảy ra câu chuyện server cái thì quá tải, cái thì trống không.
Và chính câu chuyện này đã dẫn chúng tôi tiến đến thời kì tiếp theo.
3. Thời kì lâu đài
Đến đây, câu chuyện về việc cấp phát tài nguyên cũng như theo dõi tài nguyên sử dụng xem như đã giải quyết xong. Lúc này chúng tôi cũng chỉ mới có 3 server chuyên dụng cho Machine Learning, việc chuyển đổi còn chấp nhận được. Sau đó, chúng tôi được đầu tư thêm 6 server nữa, tất cả là 9 server. Lúc này, việc chuyển đổi server thủ công đã trở nên cồng kềnh, bất tiện cho user và kém hiệu quả trong việc quản trị. May mắn thay, thế giới này còn có k8s.
K8s là gì, chúng tôi đã giới thiệu ở đây, nên xin phép không bàn sâu về khái niệm nữa.
Do đã triển khai trên docker trước đó, việc chuyển đổi lên dùng k8s chúng tôi không gặp quá nhiều khó khăn vì dù sao cũng đều là container cả. Cơ mà, như bao lần, vấn đề lại xuất hiện. Như đã nói, để đảm bảo toàn vẹn dữ liệu, chúng tôi đã tách user data bao gồm home dir và các conda environment của user đó sang một hệ thống storage độc lập với các server chạy Jupyter. Vì sử dụng volume, mỗi khi có user mới, chúng tôi lại phải tạo thủ công path để chứa dữ liệu cho user. Trước đây, với chỉ vài con người, việc này không phải là vấn đề, nhưng với quy mô và sự phát triển của CADS trong thời gian sau này, số lượng user tăng vọt lên và cách này xem ra không còn phù hợp nữa. Chúng tôi lại đi tìm phương hướng giải quyết cho vấn đề này.
Muốn không xuất hiện vấn đề, cách duy nhất là đừng làm gì cả. Còn không, hãy dự phòng ít nhất 50% thời gian để xử lý sự cố
Jupyter đã tiến hóa lên thời đại k8s
Đầu tiên, chúng tôi nghĩ đến PersistentVolumeClaim, khi user đăng nhập lần đầu hệ thống sẽ tự tạo thư mục chứ data cho user. Nhưng lúc này lại xảy ra lỗi khi container tạo ra volume, nó lại gán luôn volume đó sang chính worker đã claim nó, vì vậy lúc này việc cân bằng tải không thực hiện được vì user nếu được tạo container trên các node khác sẽ không đọc được data. Ngoài ra, trong thời gian này, chúng tôi đã đầu tư thêm cụm server sử dụng GPU để xử lý các bài toán cần đến năng lực tính toán của GPU (Tesla A100 hẳn hoi), do đó vấn đề càng nghiêm trọng hơn, vì user không còn chuyển đổi được giữa 2 cụm worker này theo nhu cầu sử dụng nựa. Kế hoạch xem như thất bại.
Tiếp theo, chúng tôi nghĩ ra cách sử dụng NFS Gateway để mount data vào cho user, thay cho sử dụng PVC. Mọi thứ diễn ra tốt đẹp trong quá trình thử nghiệm, cho đến khi đưa vào sử dụng production, NFS gateway chết ngay lập tức vì không chịu nổi tải từ hệ thống. Sau nhiều lần cố gắng tuning và thử nghiệm, chúng tôi thất bại lần 2. Với mỗi lần thử nghiệm và thất bại, đi kèm với đó luôn là gương mặt đáng thương, những quả claim chí mạng và cả những pha tự nhục của chúng tôi trước đội Data Scientist 😥
Với 2 lần thất bại, chúng tôi cuối cùng cũng quay lại như ban đầu, volumes từ storage vào container và chấp nhận tạo home dir thủ công cho các user mới, nhưng đây chưa phải là kết thúc câu chuyện, vì sau đó là thời kì 4
4. Thời kì đế quốc
À, thì như đã nói từ đầu, chúng tôi đang ở thời kì 3 và đang cố gắng để bước sang thời kì Imperial Age này. Với 2 lần thất bại ở trên, chúng tôi vẫn chưa tìm ra cách hiệu quả để giải quyết nỗi đau còn lại này, và vẫn đang rộng cửa chào đón các bạn có tinh thần chiến đấu và học hỏi để cùng chúng tôi kích đời 4.
Nếu bạn cảm thấy những gì vừa được đọc gây hứng thú cho mình, còn ngần ngại gì nữa mà hãy tham gia cùng CADS, chúng ta sẽ cùng nhau lên đời, tạo lính và đi chiến đấu với các phe khác. Nhé!
Đây đây, apply ở đây này