{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bd06-title",
   "metadata": {},
   "source": [
    "# 🗓️ 06 · 数据平台与调度：DAG 编排 / 依赖 / 重跑\n",
    "\n",
    "> 数据平台 = 调度（Airflow/DolphinScheduler）+ 血缘 + 质量 + 权限。\n",
    "> 本节手写**任务 DAG、依赖调度、失败重试、血缘追踪**（设 mini 调度器）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-q",
   "metadata": {},
   "source": [
    "## 📋 本节要解决的问题\n",
    "\n",
    "| # | 问题 | 方法 |\n",
    "|---|---|---|\n",
    "| 1 | 数据平台有哪些组件？ | 调度/血缘/质量/权限 |\n",
    "| 2 | 任务依赖怎么表达？ | DAG（有向无环图） |\n",
    "| 3 | 失败怎么处理？ | 重试/告警/上游阻断 |\n",
    "| 4 | 血缘怎么维护？ | 表级依赖记录 |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bd06-setup",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:32.635285Z",
     "iopub.status.busy": "2026-10-08T09:44:32.634662Z",
     "iopub.status.idle": "2026-10-08T09:44:50.184220Z",
     "shell.execute_reply": "2026-10-08T09:44:50.171014Z"
    }
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "matplotlib.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'PingFang SC', 'Noto Sans CJK SC', 'Arial Unicode MS']\n",
    "matplotlib.rcParams['axes.unicode_minus'] = False\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import sqlite3\n",
    "import os\n",
    "rng = np.random.default_rng(42)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-1",
   "metadata": {},
   "source": [
    "## 1️⃣ 数据平台全景（必背）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bd06-pano",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:50.220992Z",
     "iopub.status.busy": "2026-10-08T09:44:50.198192Z",
     "iopub.status.idle": "2026-10-08T09:44:50.341707Z",
     "shell.execute_reply": "2026-10-08T09:44:50.329308Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数据平台三大块：\n",
      "  1) 开发平台：SQL 编辑器/任务发布/版本管理（如 DataWorks/LH）；\n",
      "  2) 调度系统：DAG 编排、定时、依赖、重跑（Airflow/DolphinScheduler）；\n",
      "  3) 治理体系：血缘、质量（规则稽核）、元数据、权限审计。\n",
      "\n",
      "面试常问：\"你们调度任务失败怎么处理？血缘有什么用？质量怎么保证？\"\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''数据平台三大块：\n",
    "  1) 开发平台：SQL 编辑器/任务发布/版本管理（如 DataWorks/LH）；\n",
    "  2) 调度系统：DAG 编排、定时、依赖、重跑（Airflow/DolphinScheduler）；\n",
    "  3) 治理体系：血缘、质量（规则稽核）、元数据、权限审计。\n",
    "\n",
    "面试常问：\"你们调度任务失败怎么处理？血缘有什么用？质量怎么保证？\"\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-2",
   "metadata": {},
   "source": [
    "## 2️⃣ 构造任务 DAG（字典表示）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bd06-dag",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:50.380648Z",
     "iopub.status.busy": "2026-10-08T09:44:50.364285Z",
     "iopub.status.idle": "2026-10-08T09:44:50.619613Z",
     "shell.execute_reply": "2026-10-08T09:44:50.601750Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  ods_sync     依赖: 无（源任务）\n",
      "  dwd_clean    依赖: ['ods_sync']\n",
      "  dws_agg      依赖: ['dwd_clean']\n",
      "  ads_report   依赖: ['dws_agg']\n",
      "  ads_feature  依赖: ['dws_agg']\n",
      "\n",
      "➡️ DAG 保证：ads_report 和 ads_feature 都等 dws_agg 完成\n"
     ]
    }
   ],
   "source": [
    "# 任务 DAG：每个任务依赖前序任务的产出\n",
    "tasks = {\n",
    "    'ods_sync':   [],\n",
    "    'dwd_clean':  ['ods_sync'],\n",
    "    'dws_agg':    ['dwd_clean'],\n",
    "    'ads_report': ['dws_agg'],\n",
    "    'ads_feature': ['dws_agg'],\n",
    "}\n",
    "for t, deps in tasks.items():\n",
    "    print(f'  {t:<12} 依赖: {deps or \"无（源任务）\"}')\n",
    "print('\\n➡️ DAG 保证：ads_report 和 ads_feature 都等 dws_agg 完成')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-3",
   "metadata": {},
   "source": [
    "## 3️⃣ 拓扑排序：找出可执行顺序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bd06-topo",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:50.635465Z",
     "iopub.status.busy": "2026-10-08T09:44:50.634753Z",
     "iopub.status.idle": "2026-10-08T09:44:50.909586Z",
     "shell.execute_reply": "2026-10-08T09:44:50.884693Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "拓扑顺序: ['ods_sync', 'dwd_clean', 'dws_agg', 'ads_report', 'ads_feature']\n",
      "DAG 无环: True\n",
      "✅ DAG 合法，调度顺序确定\n"
     ]
    }
   ],
   "source": [
    "from collections import deque\n",
    "\n",
    "def topo_sort(deps):\n",
    "    indeg = {t: len(d) for t, d in deps.items()}\n",
    "    adj = {t: [] for t in deps}\n",
    "    for t, ds in deps.items():\n",
    "        for d in ds:\n",
    "            adj[d].append(t)\n",
    "    q = deque([t for t, i in indeg.items() if i == 0])\n",
    "    order = []\n",
    "    while q:\n",
    "        cur = q.popleft(); order.append(cur)\n",
    "        for nxt in adj[cur]:\n",
    "            indeg[nxt] -= 1\n",
    "            if indeg[nxt] == 0:\n",
    "                q.append(nxt)\n",
    "    return order, len(order) == len(deps)\n",
    "\n",
    "order, ok = topo_sort(tasks)\n",
    "print('拓扑顺序:', order)\n",
    "print('DAG 无环:', ok)\n",
    "assert ok and order[0] == 'ods_sync'\n",
    "print('✅ DAG 合法，调度顺序确定')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-4",
   "metadata": {},
   "source": [
    "## 4️⃣ 失败重试与依赖阻断（模拟调度器）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "bd06-retry",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:50.928140Z",
     "iopub.status.busy": "2026-10-08T09:44:50.927242Z",
     "iopub.status.idle": "2026-10-08T09:44:51.163729Z",
     "shell.execute_reply": "2026-10-08T09:44:51.139993Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ ods_sync 第 1 次成功\n",
      "✅ dwd_clean 第 2 次成功\n",
      "✅ dws_agg 第 1 次成功\n",
      "✅ ads_report 第 1 次成功\n",
      "\n",
      "➡️ 调度策略：指数退避重试 + 依赖失败阻断下游 + 告警通知\n"
     ]
    }
   ],
   "source": [
    "# 模拟：dwd_clean 第一次失败，重试 2 次成功；观察下游被阻断\n",
    "def run_task(name, fail_first, state):\n",
    "    if fail_first and state.get(name, 0) == 0:\n",
    "        state[name] = state.get(name, 0) + 1\n",
    "        return False\n",
    "    state[name] = state.get(name, 0) + 1\n",
    "    return True\n",
    "\n",
    "state = {}\n",
    "plan = ['ods_sync', 'dwd_clean', 'dws_agg', 'ads_report']\n",
    "fails = {'dwd_clean': 1}   # 第一次失败\n",
    "log = []\n",
    "for t in plan:\n",
    "    attempt = 0\n",
    "    success = False\n",
    "    while attempt < 3 and not success:\n",
    "        attempt += 1\n",
    "        success = run_task(t, fails.get(t, 0) >= attempt, state)\n",
    "        log.append((t, attempt, success))\n",
    "    if not success:\n",
    "        print(f'❌ {t} 重试 3 次仍失败 -> 阻断下游')\n",
    "        break\n",
    "    print(f'✅ {t} 第 {attempt} 次成功')\n",
    "print('\\n➡️ 调度策略：指数退避重试 + 依赖失败阻断下游 + 告警通知')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "257ead5a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:51.170119Z",
     "iopub.status.busy": "2026-10-08T09:44:51.169313Z",
     "iopub.status.idle": "2026-10-08T09:44:53.041207Z",
     "shell.execute_reply": "2026-10-08T09:44:53.027015Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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iy+yZMkSq7Dx119/cebMGT766CMMBgP9+/fns88+49ixY1SuXNmy3dy5czEajTzzzDM3fO6xY8fy5ptvMmbMGN55551b8nwgJ7xFRETw6quv5ruNi4sLUVFRwD/dPH766ac8W0JWrVrF/Pnz+fXXX3N18bie4OBgduzYYfVNurOz8zUH/l+e/So0NJTixYtbQkFaWhpPPfWUpetJfoPWAY4cOWLpspKcnJzn78yVF4nVqlXj+++/Z+DAgURGRvLCCy8wbNgwUlNT87ygy0uvXr1uekKDa/n444/58ccfmTFjBgMGDLBa16pVK6pWrcr333//r48/fvx4atWqZfVtfUREBK6urrm6t82dO5dp06bRokULq+VJSUn8/fffhIWFWS1bvHixZeD+ypUr+f777wkLC6NTp07Mnj0735o8PDzsMivYt99+m+9sU+PGjePixYtkZGSwb98+6tevD+R8QXH69GlLuAB49NFHeeutt3BycuLHH39kx44dTJo0iSFDhuDq6krp0qVxd3cHoGzZsnz00Ufs27ePv//+m4YNG1qO89dff2E0GunYsaNl2bFjx6y6w112uYXvSufPn2fJkiVAThcud3d3xo4dC2AZ93Fly+aVbP17LXKnU9gQuUlxcXF88MEH+Q7wLIjSpUtbgkZERASLFy9mzpw5/PXXXzRu3JiuXbuyevVqZs2axaJFi6hVqxZVq1albNmyFClShEaNGll9MN8IHx8fihcvnmt8yLRp03B3d+fBBx8Ecr4h/+yzz5g2bRofffSRZbsDBw5QpkwZAgMDrfZfuXIlCQkJlsflypWjQYMGVtvcd999bNiw4ZYMHI+KiiIkJIR69erxzjvv0LJlS/788888t+3Ro8cNjSEZPHgwPj4+tG/fnnHjxuVqEclrNp6rRUZG0qdPH2JiYgrcbaNPnz5kZ2czffp0PD096dmzJ4cOHeKHH37I1R0vNTWVv//+G8gJDklJSZZpOyMjI3N9e3v1wHkXFxcGDhyIyWTi4YcfxsvLi//9739MmjTJ6ud9WVJSEtnZ2VbdwG70db1R3bp1o2LFivTp0yfXuuTk5H/1N3j5IjI0NJSjR48yduxYZs6caVl/8uTJfLuSBQcH5wqnq1evpnHjxlYtG2FhYSxevNjy+KWXXuKll15i2LBhJCUlATljZfK6uPfx8clz4gBbOnfuHO+/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kZCQYHl/vZEB4t9//z3h4eGsW7eO9evX4+Pjw59//sm3336Ln5+f5WaOInLrKWyI3KQbmX72Wq6+adpPP/3EkCFD2L59e66B5+vWraNNmzY3PYtKTEwMo0aNws/PjyeeeALIGXS5efNmHnnkEd57771c+/Tt25dFixYRGxuLn58fw4YNY/r06bz66qusXr36X09LeSNq1arFhg0baNy4MdOmTePUqVM88cQTtG7dmrfffrtAYaNmzZr069ePOnXqUKNGDZo0acJTTz1VoHn2r7xvx/nz5wt0r5PLXbPykp6eTmRkJOXKlbPqenbZ5Vmm/vzzT8sF4759+6hXr9516504cSIBAQH88ccf7N27l3379uHo6IirqytJSUkcP36cOnXqcPToUX777Tc6duxok7BhK/Hx8YwePZrXXnuN3bt3M3bs2GsOnG/RogXly5fn5MmTFClShJMnT1KzZk2rv6WHH36YJ598kg0bNtCnT588J36oXr06hw8fzvXlQV4DxM1mM7169cq3BTI6OpqRI0cyderUXOsqVKiAi4sL+/fvp2TJkkRHR2M2m3ONkbKVpKQkmjZtSqVKlViwYEGuWbbee+89atWqxYIFC+jZs6fVuueff57Fixdbvoj5888/eeyxx3K9Z17uYprXDfqudLlFJCYmBrixAeLdunWjb9++VK9enfXr1wPg6urKyJEjWbduHQaDIc8xKiJy8xQ2RAqh5ORkPv3003wvdMLDw3F2dv7XrRpZWVksX76cESNGcPbsWZYsWWL5IL/cqjFkyJA87547ePBgnnnmGWbPns3w4cNp0aIFTz75JN999x2dOnVi3Lhx1KpVy7L9tfo9JyQkMG/ePHr16nXNu5hfrXbt2pbnAVCmTBnGjBnDI488kudsMnmpVKmS5Q7HBd0nL2fPns13GuLg4GDLlKvz58/HxcWFhIQES/eNy6/5kSNHyM7OznMa3PyMGjWK2rVrX/OGhUeOHGH8+PGMHj0aJycnGjZsaOla5uvrS1hYGCdOnMDV1ZUKFSpQsWLFAp+/MEhOTqZnz54ULVqUl19+mdDQUBo3bkytWrW4//7789znchB56qmn8PLyonHjxqxatcrqbtO9e/fmjTfeYNu2bXnOFJWQkIDRaMxzoHpeA8Qv27Vrl1XrH2C5N8/Vg58vc3BwsNz5ulOnTmzatInBgwdbLrhtzdPTk9GjRzNw4MBcY4pMJhP+/v6MGTOGQYMGUbZsWcvMVJDT8vP000/zzTff0KdPHyZNmsSsWbNYunQpvr6+9OzZk4CAAFavXk3ZsmUt72c9e/a0ej1OnjzJ7NmzLS0al0P7jQwQL126dL5/X8uXL6dmzZpq2RCxEYUNkUImPT2d/v37ExMTk+839P9mmt1OnTrh6OhIamoqZ86cITk5mapVq7Ju3TrLOAaTycRPP/1EiRIl8r1pWP/+/RkxYgRTp061TJV7+c7i48aNo3bt2hQrVgx/f3/Cw8OJjo7G0dHRcrO9K33xxReMGTOGkydPWt2k70YZjUZLLf/1zD27du3ihRdeyHNd06ZNadq0KYsXL2bNmjXUqVOH+vXrM3v2bKvuHytXrqR48eJUqlSpwOd9/PHHCQwMtOrHf7l/vsFgIDY2lp49e1K5cmVGjBiRa//SpUuzd+9eAgICqFOnzn86taeLi8sNB8yrHTp0iIEDB2I2m1mxYgXOzs6UL1+exYsXc//99zNmzBief/75PJ/XxYsXmTVrFmvXrmXatGm0b9+e9evXW35HJ0yYwNmzZ3FxceHjjz/m22+/tRpPcDkk5yUpKclqgPaV7rnnnlxh4/fff6dYsWK5ul5GRERw7tw53Nzc6NChAwsXLuS9994jOjqaEiVKFPh1uhWv9eDBg3Mt27RpE8899xz33Xcfn376KUeOHKFt27bMnDmT+++/n4SEBO6//36aN29uaX2bOXMm7733Hvfddx+rV69m5syZJCYm8v7773PhwgV69OjB1KlTrWYDg5y/76effhoPDw/ef//9PN9Lrmf37t2Wn9nu3buJjo5m3rx5NGnShClTptzSqbdFxJrChogN7N27l+PHj1sty282qhYtWlhuFrdr1y4GDRpEQkICf/75J8WLF7fcAfiy8PBwPv/8c8sMKtdTr149q7v/uru70717d9q0aUO7du2sLqJCQkJo2rRpruVX8vf3580332T//v3ExMTg7++Pg4MD//vf/xg+fDgLFy7k4MGDpKSk4O/vT926dXnggQcoXrx4rmP169ePM2fO5LpnQkFdeXF9tb/++ovTp09bLbv6Z3LZ5TscF2QK2yvt37+f6OhoGjVqRHx8fJ7bzJs3j8GDB/PVV18xdOhQ3nnnHVq0aMEXX3zB008/bQl4Dz/8cL7nv9wH/crneWWXlaNHj7Jjxw7Wrl2Lm5sbmZmZtG3blvj4eDZu3JhnX/hOnTrx3XffsW3btn814PZyiPw3vLy8CnzvjqudPXuWzz77jO+++46BAwfyzTffWH2T3bx5c1asWMEjjzzCL7/8wujRo+ncubPltY2Pj6dnz54MHDiQevXqUa1aNVasWMGIESOYMWMGzz//PMuWLePXX3/F19eXBx98kBMnTjBhwgQqVqzI0aNH2b9/f77jONatW2cJmXlZvny5pbUrNDSUzMxM5syZw8svv8zRo0cJCQnh4sWLli8TXnrpJYYPH86HH37Ib7/9xqlTp24olN7Ma52X1NRUJk6cyOuvv07Xrl0t00D/8MMPvPrqq3Tt2pXHHnuM6tWr4+joaBn4Djkzf82ePZsJEybg7u7O2bNn6devH1WqVGH9+vU88cQTNGjQgF9//dWqhaRs2bKW7mobN25k3rx5nDx5kpiYmHzHbGzbtg13d3e6detGjRo12Lt3L3v37rVs4+Pjw9ixY3FwcMDX1zffyQdE5OYpbIjYwPz58/O9udizzz5r9XjGjBmWb/ZXr17NkCFD+Pjjjy19yJ2cnBg8eLDVoOGGDRtaZmK6nqFDhzJ06NACbVupUqUCXZjk9y1guXLl8pwmNT/VqlXLs5/69Rw7doydO3daphjNa+zKnDlzcnUzu/K+HwA///wzjo6OHDhwAOC6fcavNnfuXBo2bEhQUBDZ2dn06tULo9FI586dSU9Pp2fPnqxevZpJkybx8MMPA/DRRx/RokULHnroIXbt2kWjRo04ffo0zz33nNWxT506ZZnSeO7cuQD5jg2Jiori5Zdfxmg08vrrr+Pp6cnzzz9Pu3bt8r37d/fu3fnf//7HuXPnGDly5HWf68aNGxk5ciTe3t5kZWWxdu3aAv9e3QpHjx5l5MiRLF++nAYNGrBy5UratGmT57ZNmjRhz549jBkzhgEDBuDr68vQoUPp27cvPXv2pEyZMpYxUq6urkyfPp3p06dTpUoVGjZsyJ49eyxddbZt28agQYOoXr06Q4YM4b777rN0NcxLgwYNOHLkiGU2qasVLVqUzp07k5iYyNq1a3nvvfdo2LAhFSpUICAggP79+1OqVClKlSpFyZIlCQoKwmAw8OKLLzJw4EBcXV3zbKn6L+zdu5dTp05RsWJFli1bZnVXdmdnZ7788kvuvfdeAgIC8Pf3Z+DAgXh6elp1U3R0dKRbt2689NJLTJ8+nccff5xPPvkER0dHfvvtN7755htat27N2LFjrW5yetn06dPZsGGD5fHVk2dATrfK5cuXs2nTJrp168Z3332X73NavXo1gYGBVjOwFStWLNdMdCJyE8wickvMmDHD/Prrr/+rfY8cOWJ+++23zadOncpzfWpqqjkjI8McExNjTkhIuIkq7wxr1qwxOzk5mV1dXc3333+/OTMz07IuOTnZ3KtXL3NISEiu/Y4dO2bu1auXOTU11Ww2m82dOnUye3l5mYOCgszPPvtsnud64oknzAsXLsxzXXR0tPnPP//Md93o0aPNFy5cyHP90aNHzT///LM5MjLSvGjRolzrV65cafb19TV7eXmZixQpYn7rrbfyPI4tPP/88+YZM2ZYLTt37py5Z8+e5h49eph79OhhHjlypDkqKuo/qyk7O9v8wQcfmFevXn1D+8XHx5s///xz89atW82JiYnmsWPHWv2+XDZnzpw8fw6Xzz1jxgzzqlWr/lXt+VmwYEGeteRXw9ixY81PP/20OS4u7pbWkZ8pU6aYv/32W8vjzMxM89ixY81JSUk3dJzs7Gxzr169zOfPnzebzTk/kzfffNN89OjRPLdfv3695Wfx8ccfm6dOnfrvnoCIFAoGs/mKO3mJiIiIiIjcIjfWQVlERERERKSAFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmFDZERERERMQmHO1dgIiIiMidJDI+jMSUOHuXITbk5e5LkE8xe5dxW1DYEBEREblFIuPDeHFiXzIy0+xditiQs5MrXw6fq8BRAAobIiIiIrdIYkocGZlpDOzwNEX9Sti7HLGB8NgL/LJyAokpcQobBaCwISIiInKLFfUrQXCRcvYuQ8TuNEBcRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERERERsQmFDRERE5A62b88BLoRetHcZcpdS2BARERG5gz3z2IvMm73Q3mXcUuFhEfYuQQpIYUNEREREbhszps6mS5se9i5DCkhhQ0REROQ2EhsTy/69Bwm7EJbn+szMTA7sO8S5s6H5HiM8LIKD+w+Rlpp2zXNlZWXx95YdJMQnEhsTy6b1WyzrUlNS2bfnQK5Whvj4BP7esgOTyURKcgr79hzg4vm8a83KyuLwgSPs33uQtLT0fI9z/twFdu/Yy9FDxzh+9ASZGZn8vWUHhw8cuWb9Yn+O9i5ARERERArmmcdeZNlvKwgqGkhkeBS9+ndn7LcfW9Zv3rCV5x5/mfjYOJxdnBnwaF+r/TMyMnjxqVf48481eHl7YTaZWPDHbMqWL5Pn+RLiE+jd5SFeGz2Sr8dOwGQycezCPhbMWczbr4zB3dOduNh4Wt/bgm8mf4Gbuxu7t+/h0T7D+GbyF7z1yhgA4uPiGTCoL59++YHl2L/N/513Rr1PSkoqRqMRB6ORdz99iz4DegJYjvPuJ2/x/psf06BxPUoGl+CvVetITEjkxSdfoUbtakyeMeFWv8xyC6llQ8TOzo0dy7Gnnsq1PP38eXbUrUv6hQu39HwRc+YQ8vLL/2rf1JMn2VaxIpkxMfluE710KdsqVsz1X9yGDQCc+eADImbP/lfnFxG529WuV4u9IX/z98ENzP19BnN/mc/2rTsBSE5K5tmhI2jVtjkHz+7mwOmdGI0OXDz/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0LM0qNKciV9P5tsfxlGmbOkbqqNB43qMm/g/Vi1fTav67enZqT+eXp40aFyvQHUCvPrWCDau3UKTmq05uO8w1WpW5Z0PX2fm9Dm0btCB9Ws2MfiJR65by6PDBvL0iCf48n/f0qRmK54e8iKdu3bE3UPdqAojg9lsNl9/MxERERG5npMXjzBqyqO81O8DgouUu2XHNZvNGAwGzOacu4O7uDjnGuRtMpkwGo35bnP5GAWRnp6Bo6NDrpsZQs64ibyW32idee13eUzG5TEaJpOJzMwsy+MbqcVWQiNO8cWct/h02E+UL171Pz337UgDxEVEREQKucsX7AaDAVdXlzy3uXwBn982NzIDVX4X98A1L+5vpM689nNwsA44RqPxX9cihYO6UYmIiIiIiE2oZUNERETkLvPtF5OYP3thruWNmjXkf199aIeK5E6lsCEiIiJyl3nq+WEMe3pIruUODur0IreWwoaIiIjIXcbR0fGGbuon8m8pvoqIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE0obIiIiIiIiE042rsAERERkTtNeOwFe5cgNqKf7Y1R2BARERG5RbzcfXF2cuWXlRPsXYrYkLOTK17uvvYu47ZgMJvNZnsXISIiInKniIwPIzElzt5liA15ufsS5FPM3mXcFhQ2RERERETEJjRAXEREREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbEJhQ0REREREbOL/Zwg8xJI1cdsAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 1000x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 可视化：调度 DAG 与失败重试位置\n",
    "fig, ax = plt.subplots(figsize=(10, 4))\n",
    "pos = {'ods_sync': (8, 50), 'dwd_clean': (32, 50), 'dws_agg': (56, 50),\n",
    "       'ads_report': (80, 72), 'ads_feature': (80, 28)}\n",
    "for t, (x, y) in pos.items():\n",
    "    fc, ec = ('#F8CBAD', '#C00000') if t == 'dwd_clean' else ('#E2EFDA', '#548235')\n",
    "    ax.add_patch(plt.Rectangle((x - 7, y - 7), 15, 14, fc=fc, ec=ec))\n",
    "    ax.text(x, y, t, ha='center', va='center', fontsize=10)\n",
    "for a, b in [('ods_sync', 'dwd_clean'), ('dwd_clean', 'dws_agg'),\n",
    "             ('dws_agg', 'ads_report'), ('dws_agg', 'ads_feature')]:\n",
    "    ax.annotate('', xy=(pos[b][0] - 7.5, pos[b][1]), xytext=(pos[a][0] + 8, pos[a][1]),\n",
    "                arrowprops=dict(arrowstyle='-|>', color='#7F7F7F', lw=1.8))\n",
    "ax.annotate('第1次失败\\n重试成功', (32, 57), textcoords='offset points', xytext=(-8, 22),\n",
    "            fontsize=10.5, color='#C00000', ha='center',\n",
    "            arrowprops=dict(arrowstyle='->', color='#C00000'))\n",
    "ax.text(56, 40, '重试成功前\\n下游全部阻断', ha='center', fontsize=10, color='#C00000')\n",
    "ax.set_xlim(0, 96); ax.set_ylim(10, 92); ax.axis('off')\n",
    "ax.set_title('任务 DAG：拓扑顺序执行 + 失败重试 + 依赖阻断', fontsize=12)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5cf48d9",
   "metadata": {},
   "source": [
    "### 数据时间 vs 运行时间（T-1 详解）\n",
    "\n",
    "- **运行时间**：任务真实被调度执行的时刻。如\"每天 01:30 跑\"；\n",
    "- **数据时间**：这批数据对应的**业务日期**。01:30 跑的是\"昨天（T-1）\"的数据。\n",
    "\n",
    "为什么是 T-1？白天产生的数据要等当天结束才完整，凌晨汇总昨天的全量——\n",
    "所以\"今天的调度产出昨天的数\"。排查数据问题时先问三件事：\n",
    "**任务跑到几点？处理的数据时间（ds 分区）是哪天？是全量还是增量？**\n",
    "\n",
    "**补数/回刷（backfill）**：历史分区数据错了或逻辑变更时，按分区批量重跑——\n",
    "这正是\"表按日期分区\"的最大好处之一：**重跑粒度=天级分区，互不影响**。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "434ba1b3",
   "metadata": {},
   "source": [
    "### Airflow vs DolphinScheduler（选型对比）\n",
    "\n",
    "| 维度 | Airflow | DolphinScheduler |\n",
    "|---|---|---|\n",
    "| 定位 | Python 生态编排 | 国产可视化大数据调度 |\n",
    "| 定义任务 | Python 代码（DAG as code） | 界面拖拽 + 代码均可 |\n",
    "| 依赖/重试 | 代码配置 | 界面配置 |\n",
    "| 生态 | 插件丰富、社区大 | 对国产组件/大数据栈友好 |\n",
    "| 适用 | 算法/工程团队代码化 | 数据平台多人协作 |\n",
    "\n",
    "还有主流选择：Dagster/Prefect（数据感知编排）、K8s 原生 Argo Workflows。\n",
    "面试口径：**说清自己团队用什么 + 为什么**（易用性/生态/权限/多租户）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-5",
   "metadata": {},
   "source": [
    "## 5️⃣ 血缘追踪（表级依赖）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bd06-lineage",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:53.078693Z",
     "iopub.status.busy": "2026-10-08T09:44:53.077789Z",
     "iopub.status.idle": "2026-10-08T09:44:53.190644Z",
     "shell.execute_reply": "2026-10-08T09:44:53.165792Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "血缘（上游表 -> 下游表）:\n",
      "  ods_orders -> dwd_orders\n",
      "  ods_users -> dwd_orders\n",
      "  dwd_orders -> dws_daily_orders\n",
      "  dws_daily_orders -> ads_gmv_report\n",
      "  dws_daily_orders -> ads_user_feature\n",
      "\n",
      "  血缘的用途：\n",
      "  1) 影响分析：改一张 ODS 表，下游哪些报表/特征会变；\n",
      "  2) 故障排查：报表数据异常时快速定位源头；\n",
      "  3) 成本治理：找无下游的\"孤儿表\"下线省钱。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 血缘：记录表与表之间的来源关系\n",
    "lineage = [\n",
    "    ('ods_orders', 'dwd_orders'),\n",
    "    ('ods_users', 'dwd_orders'),\n",
    "    ('dwd_orders', 'dws_daily_orders'),\n",
    "    ('dws_daily_orders', 'ads_gmv_report'),\n",
    "    ('dws_daily_orders', 'ads_user_feature'),\n",
    "]\n",
    "print('血缘（上游表 -> 下游表）:')\n",
    "for up, down in lineage:\n",
    "    print(f'  {up} -> {down}')\n",
    "print('''\n",
    "  血缘的用途：\n",
    "  1) 影响分析：改一张 ODS 表，下游哪些报表/特征会变；\n",
    "  2) 故障排查：报表数据异常时快速定位源头；\n",
    "  3) 成本治理：找无下游的\"孤儿表\"下线省钱。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-6",
   "metadata": {},
   "source": [
    "## 6️⃣ 调度系统面试速答"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "bd06-faq",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:44:53.196454Z",
     "iopub.status.busy": "2026-10-08T09:44:53.195622Z",
     "iopub.status.idle": "2026-10-08T09:44:53.527653Z",
     "shell.execute_reply": "2026-10-08T09:44:53.511275Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1) 调度频率怎么定？ -> 分层：小时级/天级按数据时间（T-1 等）；依赖更细的任务用分钟级；\n",
      "2) 数据时间 vs 运行时间？-> 今天 01:00 跑昨天的数据（T-1）；数据时间=业务时间；\n",
      "3) 天级任务凌晨跑不完怎么办？-> 提前开始时间/并行度/拆任务/增量；\n",
      "4) 任务积压如何追？-> 提高并行度、跳过不必要重跑、优先级；\n",
      "5) 平台差异：Airflow（Python 生态）vs DolphinScheduler（可视化）.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''1) 调度频率怎么定？ -> 分层：小时级/天级按数据时间（T-1 等）；依赖更细的任务用分钟级；\n",
    "2) 数据时间 vs 运行时间？-> 今天 01:00 跑昨天的数据（T-1）；数据时间=业务时间；\n",
    "3) 天级任务凌晨跑不完怎么办？-> 提前开始时间/并行度/拆任务/增量；\n",
    "4) 任务积压如何追？-> 提高并行度、跳过不必要重跑、优先级；\n",
    "5) 平台差异：Airflow（Python 生态）vs DolphinScheduler（可视化）.\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd06-7",
   "metadata": {},
   "source": [
    "## 📝 自测清单\n",
    "\n",
    "- [ ] 能画出数据平台三块全景\n",
    "- [ ] 能写 DAG 并表示任务依赖\n",
    "- [ ] 能实现拓扑排序\n",
    "- [ ] 能讲失败重试与依赖阻断策略\n",
    "- [ ] 能说出血缘三大用途"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
