Inside the Driver Container: A First Look
Tớ tò mò mở Web Terminal trên một Dedicated all-purpose compute và lục lọi xem mình đang đứng ở đâu, filesystem được tổ chức thành những vùng nào, mỗi vùng phục vụ việc gì.
What I Actually Did
Trước đây, tớ từng có thời gian xây dựng Data Platform as a Service và Notebook Interactive Service, khi đó tớ gặp không ít vấn đề mà tớ đã ghi lại trong các note về Stack Integration. Chính khoảng thời gian đó khiến tớ bắt đầu tò mò về Databricks. Có những thứ Databricks làm được mà lúc ấy tớ thực sự không hình dung nổi họ đã làm như thế nào. Cùng là Spark, notebook và những thành phần quen thuộc trong một data platform, nhưng khi ghép chúng lại, Databricks lại mang đến một trải nghiệm rất khác. Đôi lúc tớ còn nghĩ không biết phía sau họ có thứ “ma thuật đen” gì không :)).
Sự tò mò ấy cũng là một trong những lý do khiến tớ muốn tìm một môi trường làm việc có sử dụng Databricks, để có cơ hội trực tiếp trải nghiệm và tìm hiểu cách họ giải quyết những bài toán mà trước đây tớ từng loay hoay. Rồi công việc cứ cuốn đi, những câu hỏi ban đầu cũng dần bị bỏ quên. Cho đến khi tớ có cơ hội thực sự sử dụng Databricks.
Trong một lần chuyển sang Dedicated access mode trên All-purpose compute, tớ tình cờ mở Web Terminal. Ban đầu cũng chẳng kỳ vọng gì nhiều, chỉ nghĩ đây là một cái shell để thao tác trên driver. Nhưng càng nhìn quanh filesystem, những script, log và process đang chạy, tớ càng nhớ lại những câu hỏi ngày trước. Hóa ra, có lẽ mình đã có một chỗ để bắt đầu tìm câu trả lời.
Và đó cũng là lý do tớ bắt đầu tìm hiểu kỹ hơn cách Databricks tổ chức runtime phía sau notebook, cũng như sự khác biệt giữa các access mode mà tớ có nhắc đến trong Databricks Interactive Runtime.
Để tìm hiểu, tớ thực hiện một số thao tác quan sát trên một All-purpose compute ở Dedicated access mode:
- Khởi tạo compute và start như bình thường.
- Attach notebook, chạy một số cell PySpark hoặc Scala để runtime thực sự đi vào trạng thái hoạt động, với
SparkContextvà language session đã được khởi tạo. - Mở Web Terminal của compute và chỉ quan sát: liệt kê thư mục, đọc cấu hình, script, log, kiểm tra process và các port đang mở.
Tớ không gọi API control plane, không decompile bất cứ thứ gì, không sửa đổi runtime và không thực sự mở connection tới bất cứ đâu. Note này là nơi cá nhân tớ lưu lại những gì tớ quan sát được qua những command cơ bản như ls, cùng các giả thuyết về môi trường thực thi mà Spark application và JVM driver đang hoạt động bên trong. Mục tiêu là trả lời cho sự tò mò của bản thân, học hỏi sâu hơn và cụ thể hơn nhận diện cấu trúc của driver container, các process, file cấu hình, script, log và những thành phần runtime có thể quan sát được từ môi trường này.
Đây chưa phải là phần giải thích toàn bộ về kiến trúc, vòng đời của một interactive session hay cơ chế thực thi command trên Databricks, những phần đó tớ sẽ thực hiện tìm hiểu ở các note khác. Thay vì thế, tớ muốn bắt đầu từ một câu hỏi cơ bản hơn trước khi đọc process tree hay cố gắng hiểu tên một class: tớ thực sự đang đứng ở đâu và nơi tớ đứng đang thực sự có những gì?
Where Am I Standing?
Web Terminal là một product surface được Databricks document chính thức: shell chạy với quyền root bên trong container của driver node, và được proxy qua port 7681 trên Spark driver. Đây là điểm quan sát của cả note, không phải góc nhìn từ host hay từ toàn bộ cluster.
Từ chỗ đứng này, có mấy giới hạn tớ cần rõ ràng:
- Quyền root chỉ có hiệu lực trong container. Nó không cho tớ thấy host, các container khác có thể đang chạy cùng node, worker node hay control plane.
- Worker và control plane chỉ thấy gián tiếp, qua Spark hoặc qua proxy. Web Terminal không đủ để xác minh topology hay request flow của chúng.
- Một port hay một client call không tự nói lên owner của service. Nó có thể thuộc cùng runtime, một sidecar, hoặc một service ở nơi khác.
Vì vậy, diagram này chỉ là simplified observation boundary: nó đặt terminal, driver container, worker và control plane vào đúng mức nhìn thấy được; không phải sơ đồ kiến trúc chính thức của Databricks.
What Makes Up This Runtime?
Từ những gì nhìn thấy được, tớ nghĩ driver container không chỉ chứa Spark driver. Thực ra, nó là một runtime được đóng gói, trong đó chứa service quản lý lifecycle, language execution environment, runtime dependency, filesystem integration, config và log. Những thành phần này phối hợp để tạo ra trải nghiệm interactive notebook mà người dùng nhìn thấy.
Ban đầu nhìn đâu cũng thấy file, script với process. Tớ thử gom chúng lại thành sáu nhóm cho dễ hình dung:
- Environment & bootstrap — entry point, start script, init script, mount và local disk: những thứ dựng runtime lên trước khi notebook dùng được.
- Long-lived services — service giữ driver và Spark application sống qua nhiều cell, nhiều notebook; khác với một lần
spark-submitrồi thoát. Tớ sẽ tìm hiểu kỹ hơn về vòng đời của chúng trong Runtime Lifecycle and Session Boundaries. - Language sessions — Scala REPL, Python kernel và phần language-specific execution: nơi code notebook thực sự chạy, với vòng đời tách biệt khỏi Spark Applicattion.
- Code & config — JAR, native asset và config theo scope: runtime bundle được chuẩn bị sẵn quanh Spark.
- Storage & credential path — filesystem wrapper, FUSE mount và filesystem config: bề mặt mà Spark API, SQL table hoặc
open()của Python có thể đi qua. - Health, load & observability — log, health endpoint và signal runtime để quan sát readiness hoặc trạng thái vận hành.
Thử bắt đầu từ những gì có trên filesystem trước.
What's on Disk?
Mỗi khi mở terminal ở một môi trường lạ, tớ thường có thói quen gõ ls trước tiên, đơn giản là để xem xung quanh có những gì. Lần này cũng vậy, và dưới đây là những gì tớ ghi lại được từ filesystem của driver container.
/databricks/
├─ spark/
│ ├─ scripts/nimbus/dbr_entry_point.py
│ ├─ dbconf/hadoop/core-site.xml
│ └─ logs/
├─ driver/
│ ├─ conf/dynamicSparkConfig.conf.json
│ └─ preload_class.lst
├─ chauffeur/
│ └─ logs/
├─ jars/
├─ hadoop-safety-jars/
└─ common/conf/deploy.conf
/dbfs /Volumes /Workspace| Vùng | Artifact đã thấy | Nó giúp định vị điều gì |
|---|---|---|
| Bootstrap | spark/scripts/nimbus/, các start_*.sh | Runtime có startup phase riêng trước khi Spark và các service dài hạn chạy. dbr_entry_point.py là một phần của boot contract quan sát được. |
| Runtime bundle | jars/, hadoop-safety-jars/, preload_class.lst | Spark nằm trong một bundle rộng hơn, gồm class và asset bổ sung quanh Hadoop/filesystem. |
| Config | core-site.xml, dynamicSparkConfig.conf.json, deploy.conf | Config được rải theo boundary: Hadoop filesystem, driver/session và deploy/runtime chung; không chỉ là một spark-defaults.conf. |
| Service state | chauffeur/logs/, spark/logs/ | Nhiều service sống lâu cùng ghi log; đây là dấu hiệu để đọc tiếp phần process thay vì coi driver là một process duy nhất. |
| Filesystem surface | /dbfs, /Volumes, /Workspace | Các path local quen dùng là bề mặt vào filesystem integration, không nên mặc định chúng chỉ là disk local. |
Có một thứ khiến tớ khá chú ý là core-site.xml. Ban đầu tớ chỉ nghĩ đây là file cấu hình Hadoop quen thuộc, nhưng nhìn kỹ hơn thì thấy Databricks đã map một số filesystem scheme sang implementation riêng của họ. Điều này khiến tớ tò mò hơn về cách Databricks xử lý việc truy cập dữ liệu. Chẳng hạn, khi đọc một file bằng Spark, Pandas hay đơn giản là open() trong Python, liệu chúng có thực sự đi qua cùng một cơ chế không? Và phần xác thực, phân quyền được xử lý ở đâu?
What's Running?
Filesystem cho biết runtime được cài những gì. Process tree cho biết, ở thời điểm quan sát, phần nào đang sống. Tớ bắt đầu từ port đang listen, tìm PID đứng sau từng port, rồi dùng ps, jps và /proc/<pid>/cmdline để lần ngược quan hệ parent–child.
Lược bớt process phụ, mental model của cây process là:
dbr_entry_point.py
├─ ChauffeurDaemon supervisor + health/control API (:6060)
│ └─ start_driver.sh
│ └─ DriverDaemon JVM giữ Spark driver sống lâu, nhận notebook command
│ └─ Python kernel (ipykernel, chạy dưới user spark-<uuid>)
└─ Spark Master :7077, để worker đăng ký và executor được launchNhìn vào cây process này, tớ mới thấy thứ mình vẫn quen gọi là "driver" trên runtime này không đơn giản chỉ là một JVM chạy Spark. Bên cạnh nó còn có khá nhiều process khác, mỗi thằng đảm nhận một công việc riêng:
- ChauffeurDaemon: có vẻ đảm nhận việc quản lý driver, đồng thời cung cấp health/control API.
- DriverDaemon: JVM chạy Spark driver, giữ
SparkContextvà xử lý các command từ notebook. - Python kernel: hạy code Python của notebook trong một process riêng, dưới Linux user
spark-<uuid>. - Spark Master: lắng nghe ở port
7077, nơi các worker đăng ký để tham gia Spark cluster.
Tớ sẽ tìm hiểu kỹ hơn về vai trò và cách các process này tương tác với nhau ở Runtime Architecture from Process Signals.
What This Terminal Cannot Show
Dù có quyền root trong driver container, tớ vẫn chỉ nhìn được một phần của hệ thống. Những thứ như process, port, script hay config thì có thể kiểm tra trực tiếp, nhưng cách Databricks quản lý cluster từ control plane, cấp phát tài nguyên hay vận hành các worker thì không đơn giản như vậy.
| Những gì tớ có thể quan sát | Những gì vẫn chưa rõ |
|---|---|
| Process, port, startup script, config và log trong driver container | Control plane điều phối và giao tiếp với runtime như thế nào |
| Spark Master và các thông tin liên quan đến worker | Worker được khởi tạo và quản lý ra sao |
| Các process liên quan đến notebook session | Session được tạo, chia sẻ và kết thúc như thế nào |
| Filesystem config, mount và một số endpoint | Databricks xử lý credential và phân quyền truy cập dữ liệu ra sao |
| Health endpoint và một số thông tin về tải hệ thống | Những thông tin này được dùng để quyết định readiness hay autoscaling như thế nào |
My Summary
Trước đây, tớ vẫn thường hình dung một Spark cluster đơn giản là driver và các executor, còn notebook thì bằng cách nào đó attach vào để chạy code. Nhưng sau lần nhìn quanh này, tớ mới thấy phía sau một notebook trên Databricks còn có khá nhiều thứ mà trước giờ mình chẳng mấy khi để ý đến.
Tất nhiên, chỉ nhìn vào filesystem và vài process thì chưa thể hiểu được Databricks đã làm những gì để mọi thứ hoạt động cùng nhau. Nhưng ít nhất, tớ cũng bắt đầu biết nên tìm câu trả lời cho những thắc mắc ngày trước từ đâu.
Databricks Interactive Runtime
Tìm hiểu cơ chế Databricks Interactive Cluster: vì sao notebook không phải Driver, và Databricks đã giải quyết bài toán client-server Spark runtime từ rất sớm.
Runtime Architecture from Process Signals
Dựng overview architecture của Databricks interactive runtime từ port, PID, process tree và các process thật trong driver container.