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:

  1. Khởi tạo compute và start như bình thường.
  2. 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 SparkContext và language session đã được khởi tạo.
  3. 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:

  1. 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.
  2. 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-submit rồ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.
  3. 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.
  4. Code & config — JAR, native asset và config theo scope: runtime bundle được chuẩn bị sẵn quanh Spark.
  5. 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.
  6. 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ùngArtifact đã thấyNó giúp định vị điều gì
Bootstrapspark/scripts/nimbus/, các start_*.shRuntime 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 bundlejars/, hadoop-safety-jars/, preload_class.lstSpark nằm trong một bundle rộng hơn, gồm class và asset bổ sung quanh Hadoop/filesystem.
Configcore-site.xml, dynamicSparkConfig.conf.json, deploy.confConfig được rải theo boundary: Hadoop filesystem, driver/session và deploy/runtime chung; không chỉ là một spark-defaults.conf.
Service statechauffeur/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, /WorkspaceCá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 launch

Nhì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ữ SparkContext và 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átNhững gì vẫn chưa rõ
Process, port, startup script, config và log trong driver containerControl 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 workerWorker được khởi tạo và quản lý ra sao
Các process liên quan đến notebook sessionSession được tạo, chia sẻ và kết thúc như thế nào
Filesystem config, mount và một số endpointDatabricks 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ốngNhữ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.

On this page