{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bd05-title",
   "metadata": {},
   "source": [
    "# 📨 05 · Kafka 与数据管道：分区 / 偏移量 / 消费者组\n",
    "\n",
    "> Kafka 是大数据管道的**传输中枢**（削峰填谷、解耦、缓冲）。\n",
    "> 本节手写**分区与偏移量、生产者/消费者组消费进度、重平衡**等核心概念（无 Kafka 依赖）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-q",
   "metadata": {},
   "source": [
    "## 📋 本节要解决的问题\n",
    "\n",
    "| # | 问题 | 方法 |\n",
    "|---|---|---|\n",
    "| 1 | Kafka 定位？ | 分布式消息队列（日志总线） |\n",
    "| 2 | 分区干什么？ | 并行度 + 顺序保证 |\n",
    "| 3 | 偏移量怎么管理？ | 消费者组消费进度 |\n",
    "| 4 | 怎么保证可靠性？ | 副本 + ack 机制 |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bd05-setup",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:31:49.913163Z",
     "iopub.status.busy": "2026-10-08T09:31:49.866521Z",
     "iopub.status.idle": "2026-10-08T09:32:09.795634Z",
     "shell.execute_reply": "2026-10-08T09:32:09.785850Z"
    }
   },
   "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": "bd05-1",
   "metadata": {},
   "source": [
    "## 1️⃣ Kafka 核心概念（必背）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bd05-concept",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:09.800461Z",
     "iopub.status.busy": "2026-10-08T09:32:09.799631Z",
     "iopub.status.idle": "2026-10-08T09:32:09.848412Z",
     "shell.execute_reply": "2026-10-08T09:32:09.838803Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Kafka 组件：\n",
      "  Topic  ：逻辑消息类别（如 user_click）；\n",
      "  Partition：Topic 的物理分片（并行单位，一个分区内有序）；\n",
      "  Offset ：分区内消息的序号（从 0 开始）；\n",
      "  Broker ：服务器节点（存分区副本）；\n",
      "  Producer / Consumer：生产者 / 消费者；\n",
      "  Consumer Group：一组消费者协作消费一个 Topic（组内互斥、组间广播）。\n",
      "\n",
      "为什么用 Kafka：解耦（上游不用管下游）、削峰（缓冲）、\n",
      "              顺序性（分区内）、持久化（落盘可回放）。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''Kafka 组件：\n",
    "  Topic  ：逻辑消息类别（如 user_click）；\n",
    "  Partition：Topic 的物理分片（并行单位，一个分区内有序）；\n",
    "  Offset ：分区内消息的序号（从 0 开始）；\n",
    "  Broker ：服务器节点（存分区副本）；\n",
    "  Producer / Consumer：生产者 / 消费者；\n",
    "  Consumer Group：一组消费者协作消费一个 Topic（组内互斥、组间广播）。\n",
    "\n",
    "为什么用 Kafka：解耦（上游不用管下游）、削峰（缓冲）、\n",
    "              顺序性（分区内）、持久化（落盘可回放）。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-2",
   "metadata": {},
   "source": [
    "## 2️⃣ 分区与消息写入（模拟）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bd05-part",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:09.853531Z",
     "iopub.status.busy": "2026-10-08T09:32:09.852867Z",
     "iopub.status.idle": "2026-10-08T09:32:10.077442Z",
     "shell.execute_reply": "2026-10-08T09:32:10.063682Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "分区0: [('u2', 'view', 0), ('u2', 'search', 1)]\n",
      "分区1: []\n",
      "分区2: [('u1', 'click', 0), ('u1', 'buy', 1), ('u3', 'click', 2), ('u1', 'view', 3)]\n",
      "\n",
      "➡️ 相同 key（同用户）会被路由到同一分区 -> 该用户消息有序\n",
      "✅ 分区路由演示完成\n"
     ]
    }
   ],
   "source": [
    "import zlib\n",
    "# 注：Python 内置 hash() 对字符串带随机盐，每次运行结果不同；\n",
    "# 教学演示改用确定性哈希 zlib.crc32，保证结果可复现（Kafka 默认用 murmur2，思路相同：确定性哈希取模）\n",
    "n_part = 3\n",
    "msgs = [('u1', 'click'), ('u2', 'view'), ('u1', 'buy'), ('u3', 'click'), ('u2', 'search'), ('u1', 'view')]\n",
    "partitions = [[] for _ in range(n_part)]\n",
    "for key, val in msgs:\n",
    "    p = zlib.crc32(key.encode()) % n_part\n",
    "    partitions[p].append((key, val, len(partitions[p])))   # (key, val, offset)\n",
    "for i, p in enumerate(partitions):\n",
    "    print(f'分区{i}: {p}')\n",
    "print('\\n➡️ 相同 key（同用户）会被路由到同一分区 -> 该用户消息有序');\n",
    "assert all(len(p) >= 0 for p in partitions)\n",
    "print('✅ 分区路由演示完成')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b512db32",
   "metadata": {},
   "source": [
    "### 为什么 Kafka 吞吐这么高（必背四点）\n",
    "\n",
    "1. **顺序写磁盘**：分区就是**追加日志（append-only log）**，磁盘顺序写可达数百 MB/s，接近随机写的百倍；\n",
    "2. **零拷贝（sendfile）**：消费者拉数据时，数据从页缓存直达网卡缓冲区，**不经过用户态**，省两次拷贝和上下文切换；\n",
    "3. **批量 + 压缩**：生产者攒批发送（`linger.ms`/`batch.size`），压缩（lz4/zstd）降低网络开销；\n",
    "4. **页缓存依赖**：读多写少的热数据在 OS 页缓存里命中，几乎不等磁盘。\n",
    "\n",
    "### ISR 与高水位（HW）\n",
    "\n",
    "每个分区 1 个 Leader + N 个 Follower；**ISR（In-sync Replicas）**＝与 Leader 保持同步的副本集合\n",
    "（落后超过 `replica.lag.time.max.ms` 会被踢出）。Leader 挂掉只从 ISR 里选新 Leader，保证不丢已确认数据。\n",
    "**高水位 HW**＝ISR 中最小的已同步位置——消费者**最多读到 HW**，读不到未充分复制的\"越界\"消息。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-3",
   "metadata": {},
   "source": [
    "## 3️⃣ 消费者组与偏移量（模拟）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bd05-cg",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:10.084873Z",
     "iopub.status.busy": "2026-10-08T09:32:10.083775Z",
     "iopub.status.idle": "2026-10-08T09:32:10.253887Z",
     "shell.execute_reply": "2026-10-08T09:32:10.238551Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "consumer-0: 消费 ['view', 'search'] （该分区已消费 offset 2）\n",
      "consumer-1: 消费 [] （该分区已消费 offset 0）\n",
      "consumer-2: 消费 ['click', 'buy', 'click', 'view'] （该分区已消费 offset 4）\n",
      "\n",
      "➡️ 同一用户消息保持顺序；组内消费者各管各的分区，进度记录在 offset\n"
     ]
    }
   ],
   "source": [
    "# 消费者组：3 个消费者平分 3 个分区（每个消费者一个分区）\n",
    "consumers = {f'consumer-{i}': [i] for i in range(n_part)}\n",
    "# 消费进度：记录每个分区已消费的 offset\n",
    "offsets = {i: 0 for i in range(n_part)}\n",
    "consumed = {f'consumer-{i}': [] for i in range(n_part)}\n",
    "\n",
    "# 模拟消费：各消费者从自己分区拉取\n",
    "while True:\n",
    "    progressed = False\n",
    "    for i, p in enumerate(partitions):\n",
    "        cname = f'consumer-{i}'\n",
    "        if offsets[i] < len(p):\n",
    "            key, val, ofs = p[offsets[i]]\n",
    "            consumed[cname].append(val)\n",
    "            offsets[i] += 1\n",
    "            progressed = True\n",
    "    if not progressed:\n",
    "        break\n",
    "\n",
    "for c, v in consumed.items():\n",
    "    print(f'{c}: 消费 {v} （该分区已消费 offset {offsets[int(c.split(\"-\")[1])]}）')\n",
    "print('\\n➡️ 同一用户消息保持顺序；组内消费者各管各的分区，进度记录在 offset')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ed831ba8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:10.258700Z",
     "iopub.status.busy": "2026-10-08T09:32:10.258054Z",
     "iopub.status.idle": "2026-10-08T09:32:11.902954Z",
     "shell.execute_reply": "2026-10-08T09:32:11.899751Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2oAAAFtCAYAAAB2sZmaAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAi9hJREFUeJzs3XV4U1cDBvA3SVP3lhpV3CkUd3eGy3A2ZOjYxgYDJozBnA3YBkMGQ4a7DylWXArF2lKk3lJNNY3c74+udw1JDVnDt/f3PHwfPVdyTnoX7psjVyIIggAiIiIiIiIyGtLyrgARERERERHpYlAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyDGhERvbDDhw8jPj6+vKtR7rKysnD37t3yrsb/BV5TRPRfx6BGREYtPDwcgiCIP6empiImJkb8OScnBytWrEBkZKRYlpaWhtjY2GLPu337doSGhoo/79u3DyEhIUXun5aWhqioKL3y4OBgbN68Wads69atuH79erGv/6zExEQ8fPiwTMe8qMuXL0OpVL7wedauXYsePXrg1KlTL16pf8nJkycRGBj40s87efJk9O3bFxqNptTHxMbG4vz581Cr1TrlgiDg1q1bL7uKr9yZM2dw8ODBFzrHy76mtFotoqOjcerUKVy7dk1nW3JyMlasWKHzOWNIQkICVqxYgYsXL76UOpWWQqHAihUroFAoStzXWD4viejlkAglfTIREZUTpVIJPz8/dOnSBWvWrIFMJsOYMWNw/fp1nD9/HtbW1oiPj4e7uzv279+PXr16AQCGDRuGc+fOITQ0FBYWFjh//jzCwsJ0zj137lz07NkTLVq0AAB8/fXXaNiwIbp06SLu06RJE9SqVQsAMGjQIDx+/BhBQUEwNTUV9/n666+xevVqPHjwQCyrUaMGRowYgXnz5pW6rR07dkReXh7Onj1b9jfqOSQkJMDPzw8rVqzAqFGjcOfOnRJfe+TIkbCystIpu3DhAjp27Ahzc3MsWrTI4HE9e/aEl5fXS6n38ePHdd7r0vDx8UH37t11ykaMGAETExOsW7cOQP4N7datW4s9j6H2Pys4OBgNGjTA77//jrFjx5aqfp9++im+++47JCQkwNbWViz/8ccf8fHHH+PkyZPidfqsx48f48iRI6V6ncJ69OgBb2/vMh9XGqNGjUJaWhr27dv3XMe/yDW1bt06PHjwAElJSUhMTERcXBzi4uIQGxsLlUoFW1tbvP3221i8eLF4TMHvTKVSwcTExODrZWdno127dggNDUXNmjURGBgICwuL52pfWT148ABVq1ZFeHg4qlSpUuR+xvR5WVhOTg5u3LgBNzc3VKpUqUxt3717NxISEsp0DAAEBASgcePGZT6OyNgY/kQiIjICZmZm+P777zFixAhoNBr88ccf+Pbbb+Hv748xY8Zgx44desesW7cOmzdvxpo1a8QbqYcPH+p9C56RkYEnT55AKs0fWKBQKPDkyRNxv3379uGjjz4Sbzy+++471K9fH7Nnz9a5ySsLtVqN1atXG9xWpUoVrFy5ErNmzYKfn5/e9kaNGqFRo0bP9bqGLFq0CP7+/hg5ciSA/Pdoz549BvdVKBS4cOEChg0bplN+7do19OrVC1ZWVqhduza2bNmis/3Ro0eIjIxEYGDgSwtqR48exeHDh0u9f2RkJNq0aaMX1J4VExODSZMmYfDgwZBIJDrbcnNzsXfvXrGt169fx+XLl4s8l7e3N0JCQrBixQqD25s3b4769euLP2/btg09e/bUCWkAMGnSJKxduxYDBgzA/fv3YWdnp3eu4OBgfPLJJ3j33XcB5PeOLFmyBJ999pm4z2effYYPPvhAPP+SJUvg6en50oLa06dPsXPnTvHnu3fvQhCEItv/rAEDBqBChQoAXvyaCg4OxqNHj+Dq6oratWvj1KlTeOeddzB06FB4e3vD3t5e3HfTpk1o06ZNifXLysrCwIEDoVarERERgWHDhmHYsGHYvn17kcGuPBjL5+Xp06exf/9+PHr0CA8ePMDdu3ehVquxaNEidOjQATdu3CiyDTY2Nhg+fLj48zfffIO7d+/CxcWlTO/FlClTGNTo/4LxfMIQERkwbNgwJCcnY/r06ejfvz/69euHP/74A127dsXvv/+OHj16iPuGh4fjnXfewcyZM/HWW2+J5SNGjIAgCMjKyhLLtm7diqpVq6JOnToA8ofCVaxYEf7+/uLPhfn6+mLRokWYNm0aBgwYAJlMhuDgYFy6dEkcmlQgLS0NV65cwYoVK2BmZib2rOTm5mLSpEmoX7++zg1jgbZt2+LSpUu4dOmS3jZzc/OXFtTCw8OxevVqXLhwAQkJCcjMzETr1q11hkgVFhoaiqtXr+oEiSNHjmDw4MFwd3fH0aNH4evrq3PMxYsX0a1bN3z66ado167dS6k3kB+Yv/vuu1Lv37dvX50hhQU9cuHh4ZBKpVixYgU8PDzEb/rbtm0r3owWUCgU2Lt3r/jz1atX8fPPPxf5mjY2Nvjrr7/w119/Gdxubm4uBrWTJ08iNDQUP/zwA9avX4/s7GydfTt06IBHjx7pDa9t0qQJGjZsCACQyWRwdnYGADFkFvxcwNHRUbzmZDJZkXV/Hk+fPtW5/sPDw2FpaVnqoNamTRtUqFDhha+pwMBA1KhRAzVq1BDLJBIJEhMTcf78eZw/f14sHzp0KObOnYsVK1bAzc2tyLolJCSgd+/eUCgUOHPmDJydnbF792507twZPXr0wI4dO/QC9vO6dOmSwRDz9OlTAMDmzZvFQFtYzZo10bZtWwDG8XkZHx+P0NBQ+Pj4YNeuXVi9ejX69u0LJycnzJ49G6tXrzb4WRYdHY3MzEydoAYA/fv3F3u+Czt9+jSSk5PRv39/vW1E/y8Y1IjIaCkUCiQkJGDatGnw9fVF7969AQCdO3fG9u3b0atXL6Smpor7V61aFevWrcOQIUN0zpObm4uxY8dizJgxsLa2hkqlQlpaGhQKBe7fvw8gf2hTQkKC+HOnTp1Qr149nfNMmjQJ9vb2aNGiBZYuXYoNGzYgPj4eCoVCp6csPT0dV69eRUxMDGxsbPSGwP30008lhpc1a9agY8eOejerL0oQBEycOBEffPAB6tWrh169eiEsLAzHjh0rcghdZGQknJycxJ9//PFHzJw5EyYmJhg5cqTecTk5Ofjss89QrVo1uLu7izfsjo6OGDx48AvVv6BXsl27djo35KV19epVnDp1ClFRUZBIJNizZw/q1asnBrWgoCCDPWqFTZgwARMmTNApu3nzpk4vWUnlBX766Sd4e3uje/fu6NChA5KSkgzu92wwnD59Oho2bAg/Pz8MGjRI57jPPvsM9+7dw86dO/HOO+9g/vz5UKvV4j6DBg2Cj49PkXUqq1q1aiE4OFj82c/PDxMmTMDHH38sll2/fh0REREYNGiQwXO8jGvqzJkz2L9/v85xmZmZCAwM1KkfgBJ7WAFg//79GD9+POrVq4ejR4/CwcEBAGBlZYUTJ05g7NixaNq0KdauXYtmzZqVeL6SXLhwwWCPe15eHgBgw4YNOsOuCwwYMABt27Y1ms9Le3t79OzZU/yCJCIiAtu3b0flypUBAP7+/gY/a1avXo0vv/yy1O/Xhg0bEBwczKBG/9cY1IjIaC1fvhzz58/HV199henTpwPI/+a2YP7E2rVrxQn2hw8fRnR0NADgt99+g6enpzgH4/bt29BqtWjQoAFkMpm4X0BAAMzMzAAAlpaWcHV11bn5DwsLg7+/PxwdHQEAUqlU/Lb33XffxbvvvouvvvoKv//+O65evSoeV9IctdDQUPEGpygzZszA2LFjxZv8zp07izc6APDkyRNcu3YN/fr10wsWxfnxxx9x+fJlvPHGG3jvvfdw8OBBHD9+HD4+PkUOffz55591ekf69+8PuVyOn3/+Gb/++is8PDzEbUqlErdv3xa/eS+48YyNjX0pQa2gV3LVqlXPFdRmz56N2bNn681Ru337NgCgZcuWBnvUCg/te9aCBQvw+eef49KlSzo9BadOnUKnTp3wxRdfYM6cOXrHXbp0Cfv370fHjh0hlUrFAJmTk4Nq1arp7a9SqXD27Fm0bt0acrkc4eHhuHDhAmrXrq23b3Z2NmJiYvR61oD83ragoCBYWlq+lGuqMKVSicjISL36HzhwADt27CgyqL2Ma+qzzz7DZ599htTUVOzatQtvv/02fH19sXDhQtSsWRPx8fHo2rUrrl27Vuywz6ioKMyZMwcbN26El5cX+vTpY3D+Yrt27RASEoLWrVtj0qRJmDNnTrG9cyWZMWMGZsyYoVdeMEft0KFDxc5RM5bPy7Nnz+LcuXPiax09ehQ2NjZirx8RlR6DGhEZrVmzZsHe3h7Tp0/HlStXsHHjRvz+++/Yt2+fzo1c9erVceLECZw4cQJA/nClgIAA8cZDJpNh+vTpCA8PB5B/oxcQEIBHjx6J53j2G2KVSoVff/0V3bp1w/Xr18UFLAoPM3peMTEx4mp+R44cQZ06deDp6amzj1qtxvXr1xEXFwcAqFOnjs5N9bhx43D8+HEcPXpUZ0J/SUxNTdGoUSMcPnwYf/31F9566y1xUZGinDhxQlwtzt3dHX369MHUqVOxevVqDBw4UOdb8IKbyt27d+vcVH7++ecG58gYGu5XmL+/v8HeitOnT+utkmjI48eP9d7bwtRqtc5qm6dPny6xR62w+fPn48svv8TatWv1hnO1a9cOW7duxahRoxAWFoZVq1ZBLpcDyO/Z/OCDD/TON3LkSLi4uGDbtm1624KCgtCxY0fs2LEDAwYMQFZWFh4/fmywXgXL2he1HYDO0Dbg+a+pwh48eACtVgtfX1/cvXtXnOOp1Wr1hlxev34dDRo0gEQigY+PzwtfU+fPn8etW7cQGxuLxYsX4+233xa3HTt2DGvXroWzszPu3buHoKAgg/VfuXIlZsyYgXr16mHHjh2YO3culi1bBiD/dxYWFgZPT0+dRWWOHz+Ozz77DH5+fliyZInY2/q81/bzMpbPy4Lf3S+//IKpU6fit99+E//bmD179ktrL9F/AYMaERm1iRMnwt/fH+bm5mJZly5dDN70F5g6dapOj1WDBg3QoEEDAPk31hKJBJs3b0bVqlXFfby9veHv7w8vLy+cOHECYWFhMDc3R8WKFfHLL7/g8OHDiIqKwqBBg3SCmiAIZe596NChA7744gsAgJubG+rVq4cmTZro7HPkyBF8/PHH6Nu3b5Ft9PX1RdOmTcv02lOnThVvnu7cuYMffvgBt2/f1utNi4yMRGRkJFq1agUgf5jUnj17UKdOHfTp06dMr1mcVatWiXNwDHnrrbcM3syePHmy2EUJCkRGRhYZ1K5du4YaNWqgffv2+OyzzzBkyBD8+eefej1q6enpmDhxIiwtLcWy3NxcTJw4ETt37sSuXbuKfA0PDw+cPn0avXr1Qs+ePbFr1y5YW1vj119/xdWrVzFkyBCdYYv9+/fHxx9/jJycHL1VBY8ePQpLS0tx2J6/vz/8/f0RFRWltxx+QRsMDZ1t3bq1wV64572mCrt+/TrMzc1x7Ngx/PLLL7h//z6srKz0VlQ8f/48Wrdujd27d+ONN9547tcr7MGDBzh16hTS09MNbs/NzcWMGTPg7e1d5NDPrl27Yu3ateJwwAEDBojbMjMzYWNjg+XLl4uhpsCpU6ewefNmdOjQQSwry7V95coVvccGFChpjhrwzyqHxvB5WaDwvM4XIZVKDa7Kev/+fb35kQBgYWGB0aNHv5TXJipvDGpEZPSevXF8+PBhsT1Ad+7c0fv2/uHDh5g1axZ27NiB4cOH63yjDOQP5QkLC8OhQ4fwww8/YNiwYVi/fj3kcrm4gMXAgQPFcxUsFFHSYiJAfm9Yq1atxGeWFQwfAoDRo0cjLi5O73lRY8aMMbj6Y4E+ffo8d2DSarX46aefsGbNGtjb26NVq1Z6c0Z+/vlnfPzxx1i5ciW8vb2RmZmJO3fuvNBNvCHP+ziC+fPnY9y4cSXu9+677+r0vBXMJzx+/DhycnIwY8YM+Pv748CBA2jXrh1Wrlxp8Dzt2rXDtm3bUK9ePdSuXRsdO3ZEWloaLly4gLy8PDRs2BCXL1/WWWnur7/+QteuXXHhwgWcPXsWnTp1QufOnXH27FmEhIRg1qxZ0Gg0ekFtxowZOHLkCPr166dThyNHjqBnz546gRHIv95nzZqFDz/8UCyztLTEggUL9Oa8rVu3Dmq12mBQe5FrqsDhw4fRvn17zJgxA8uXL8e3336L+fPnIzU1VexdysrKwqhRo9CnT5+XFtKA/P+umjZtiuTkZIPXVd26ddGvXz+0b99ebwXTAj4+Ps89f+/NN9/U+bks1/bFixfx22+/GdxW0Cv6/fffF7l66sSJE8Vrr7w/LwEgLi5OHDWwd+9euLq6inWPiYkxWB9DvZxqtRpyuRxJSUn46aefdLbFx8dDqVTqlTs4ODCo0f8NBjUiMnoXL15EQECAeBPw+PHjIpe5B/J7UQomth8/fhxLly5FUFAQpFIp6tatC7VaXeSDdNPS0gAAf/zxR5FLbxd+/YcPH0Kr1Ra5mAgADBkyBK1atRK/6bezs8OmTZuQkZEBPz+/IgPZhQsXkJub+9LD0fbt2+Hj44P09HQsWLAAderUgb+/P86cOQNHR0f07NkTAMQV2Lp06YIlS5bAwcEBZ8+e1ZmHc/36dZ2brqK+/S88h+/ftGTJEp2fBw8ejKCgINjb26Nbt26YP38+li5dqrfKZ1hYGBITE8UexQJyuRwtWrTAe++9h549e4orKbZp0wZz5szBsWPHAOT3tH7yySdo06aN2Gty7tw53L59GyYmJpg5cyY8PT31Fk/w9PRE48aNsXv3bp2gFhsbi+DgYJ0FOgqTSqUG56M9q+C/oVdBq9Xir7/+wvz582Fubo5PPvkEM2bMwKRJk/Dw4UPcvXsX4eHhWLx4MbRaLdasWWPwPC9yTd25cwfJyck6dQLyb96vXr2K7777DhcuXMCqVauwcOFCveMVCgX+/PNPg/Uq+KKl8PyuZw0bNuy5VoGcNm0apk2bplceGBiI4cOHIysrS/zcKG5xGsA4Pi//+OMP9OvXDytWrMDBgwexY8cOMYg9ffrU4HxYQ+9pbm4urKysULVqVb15vePGjUNwcDCuXr2K9PR0ZGVl6QzxJPp/wKBGREZNo9GgU6dO+PDDD8VnQ3Xo0KHUQ3n8/PzQs2dPbNy4EYMHD0arVq10FvlYvXo1evfuDVdXVwD5z2E6evRosXXq0KGDeJNYt25ddOzYUedb3aIWE4mNjQWQv5jD6dOnce3aNdy4cQPdunXTW83t0aNHuHXrFr7++uuXGtTy8vLw6aefIiwsTJzkv3HjRty6dQthYWFo2rSpOB+vUqVKyMnJwY8//oilS5di6NCheuE1ODgYiYmJOmUBAQF6w54KFn541r81j+fChQto1KgR3n33XWzcuFFn0Ybp06dj5MiR2Lp1K8aMGQNzc3N8+eWXOH78eJELrDy7hPiSJUvQuHFjrFy5EhMmTMBvv/2Ga9eu4cqVK+I+Xl5eYq9CcYtC9OjRA0uXLoVGoxF7Og4ePAhLS0sxRD9LEARkZmaW+D5oNJoS93lehw4dQlpamrja4JgxY6DVamFlZYXz58+jRYsWWL58OUaNGoWJEyeKqyg+63mvqSFDhmDIkCGIjY3Ft99+i507dyIqKgoAMHDgQJw7dw6nTp3CTz/9VOT7n5aWpvPfcmhoKKpXrw4g/z0G8p8ZduLECURGRsLCwkInPPbo0UMMai96bd+8eRNvvfUWVq1ahV69emHx4sUYOnQoAgMDi1y0xBg+L1UqFX7++Wf8+eefWLFiBZYuXYr3338fQ4cOxeTJk+Hu7i4+96+woKAgHDp0SKcsNTXV4OfGs+bOnYsLFy7g3Llz/9qDyIn+DQxqRGTUbt68iaysLJ0bmrIM5alcubLOIhyFabVaTJgwATdu3BBvPMriwoULuH37dqkfgB0cHAw3Nze4uLhg5cqVyMvLQ+/evcX5FwUr0a1fvx5Tp07FzJkzdYazvQwHDhxAWFgYKlWqhMmTJ8PNzQ3u7u5o3Lgx3njjDSxevBiDBg3C5MmTIZfLsW3bNrRs2RKHDh1Ct27d9Hpt3nrrrVItqX3gwAGDc8qed45aWfXu3RtjxozB999/b3D71atX8f7772PixIliWVJSkk5QMzMzK3JZd39/fyxYsADTpk1DXl4ePvroI8ybN0+c61MW3bp1w+eff46goCDxgcy7d+9Gjx49dBaxKEwikcDa2rrEc7/sZ6gV9vXXX2Pw4MHidWxiYoIJEyZg1apV8Pb2xpo1a9C4cWN8+OGHcHd3L/I8L3pNeXh4YOLEiejYsSMsLS2RmJgIOzs7rF27tsRzent74/79+xAEAVOmTEFYWBh+++03tG3bVm+OWo8ePXD9+nV8//33enPWgBe7toOCgjBo0CBs3LhRfD/9/f3x8ccfo02bNjh69KjBnnhj+LxctWoVnJycxHm35ubm2LNnDx48eIA2bdpAEASdVTwL6t2yZUu0bNlSLMvLy0NCQkKpHsw+f/581K9fHxMmTMCGDRtK3J/odcGgRkRG7fz585DJZGjevLlYVpahPMUpuCEr/Iyw0kpPT8e4ceMQEBCAzp07l+qYI0eO6NyImJqaYu/evfjwww9Rq1YtTJo0CadPn0ZCQgI2bdok9kwYEhwcjDNnzmDSpEllGs4WEBCAxYsXIzU1FUuWLEFeXh727t2L5ORkjBkzBhcvXsS2bdvEnohKlSrh9OnT6Nu3L7y9vfHdd99hypQppX69Ar169UKvXr1w/fp11KlTR+xBfN45amWRmpqK5ORk8Vlphty7dw+VKlXSWRgmOjpap3fFzs6u2OdvzZw5E5s3b8a0adPQtm1bfPrpp89V38aNG8PJyQkHDhxAmzZtoFAocOLEiWJvQF9Gj9rNmzdx8eJFjB071uDzuopz+vRpnD9/Xi8QJCQkYO7cufjhhx9Qo0YNdOnSBVOnTi32cQelVdQ1defOHXTr1g3ffvst5s2bhw8//BAeHh7iHNOSpKWlYfz48di7dy82btxY5CqvO3fuxMyZM/HGG29g4sSJ+PHHH3UW8Xjea/u3337DvHnzsG3bNrRv317s4QaAUaNGITc3Fy1btsTatWvRtWtXnWON4fPy6tWreo+j8PDwEIclfvPNN/jiiy/w4MEDeHh4IC4uDs2aNcOiRYvw3nvvicdcuXIFGo2mxKGeAODk5IQNGzagU6dO6NKlC0aOHFniMUSvBYGIyIgNHDhQaNCggfjz8OHDhQEDBhR7zJQpU4SOHTvqlS9dulQ4dOiQIAiCoFKphCFDhggWFhaCpaWlMGbMGOH8+fNCVFSUMHHiREGj0egcGxUVJfj5+Qm9e/cWVCqV4O/vLzg6OgqhoaF6r1O9enVhwYIFOmURERGCTCYTDhw4oFN+48YN4fPPPxecnZ0FiUQiABCGDBkiHDx4UFAqlUW2sX379gIA4eDBg8W+F8+aOXOmAEBo2rSpsHHjRkGpVAp3794VvLy8hE6dOgmxsbGCIAjCjz/+KNSqVUs8LicnR/j111+F9PR0saxRo0bC7NmzS/3aWq1W8PLyEqZPn16mOhemVCoFiUQiLFy4sNTH7Nu3TwAgBAUFiWXDhw8XRo8eLf7cuXNnQSqVCkePHhUEQRAWLFggtG3bttSvceTIEaFBgwaChYWFMHLkSMHc3Fx45513hLi4uGKPmzt3rsFrdf369WJ9165dK1haWgqZmZkGz3H48GGhYsWKpapnx44dhWXLlhncNnbsWKFmzZqlOk9hGRkZQuXKlYWxY8fqlD99+lRo0KCBMGTIELEsISFBcHFxKfL396LX1J49ewQ7Ozvhs88+EwRBEHx8fIT3339fcHR0FNauXatzrI+Pj3D48GHhxo0bAgBBpVIJ0dHRgre3t+Dq6ioEBgbqtROAsH//fp3yAwcOCC4uLkK9evVK/H0XJy4uThg4cKDg5+cn3Lx5UywPDw8XAAjh4eFiWUE733nnHSEhIUEsN4bPy7CwMEGj0Qg5OTkCAOHKlSvitr/++kuQyWTCypUrdV5r2bJlgomJic57Pm3aNKFKlSpF1vvtt98WAgICdMp27dol5ObmFtteotcJe9SIyGhptVqcPHlSbz5QSYrqNZg8eTJCQkLw5ZdfYvXq1ZDJZAgJCUFCQgKWL1+O9u3bo1q1apg2bRqUSqU41yE8PBydO3dGpUqVcP78eSxcuBDfffcdfH19Dc51GTp0KAICAnTK3n//fQQEBKBBgwaYO3cubty4gevXryMnJwfdunXDL7/8gu7duyMoKAh//vknRo8ejZycHNSqVQs1a9bEmDFj0L59e/F8n3/+OVq0aIF27dqV6b3p0aMHBg8erLM6YeXKlbFgwQL4+flh7969UKlUWLFihc7DbM3NzTFp0iSdc9WqVQubN2+Gu7t7iT0wGo0Gly5dQlRUFLp161amOhdmamqKmjVrYvHixZBKpeJiHkVJTU3FL7/8gooVK+o9AqFAREQETp06hc8//xz9+/fHd999B5VKVWJdkpOTsXnzZqxZswYhISF48803sWPHDlSqVAmzZ8/GzJkz4evri8GDB2Pw4MHo3LmzzoqfhcXGxmLfvn06Zbdu3cKtW7ewevVqeHl56fSoubq6wsLCAvHx8QgJCcHTp09LNUT03r17cHd3h7W1NSpWrKjTG3zu3LlS9zoV9vHHH0Mul4vPGwPyn7339ttvo1mzZjpDDl1cXLB9+3b07t0bKSkpWLRokc618yLX1K+//oqpU6fihx9+0OmZady4MYYMGYKuXbtCqVSKw1uHDx8Ob29vREdHQyaTQSaToWLFivj222/RunVrvYUpChYDevZ32LNnT9y6dQuHDx9+7gde//nnn5g0aRK6dOmCK1eulNhr1adPH1y5cgXjxo2Dn58ffvzxR4wbN84oPi8LL+Nf2NWrVzFgwABMnToV48eP19k2depUHD9+HMOGDUNwcDAEQcC6deswa9YshIaGIjAwUO98RS3Pv3bt2pfyvEsiYyARhL9nxxIRGZnLly+jadOm2LZtGwYNGgQAGDFiBHJzc3UmxyclJYk/5+bm4ptvvkHbtm2xZcsWAPkPXl2/fj3u3r2LzMxMNGjQAKNGjcKECRN0ljpPSkrC77//jt9++w3p6en45JNP8O6772Ls2LG4f/8+Tp48iatXr2LQoEHQaDQICAiAvb09TE1NxT+CIECpVOr86dy5Mzp16gQTExNUrVoVX3/9Nby8vBAQEIDq1avrPbcLyB/Kdv/+fVy7dg3379/HlClTip3X8zKsWbMG33zzDQRBQKVKlbB06VJxIQVDoqOj8e677+LOnTslPnxaIpHA3t5efE7Yi7h06RImT56Mu3fvlhiozMzMUK9ePSxbtgyNGjXCli1bkJiYiJ9++gl9+vTBjz/+iH79+iE7OxtHjx7Fnj178M477+Dp06dwcXHBwIEDIZfLodVqoVKpxOX558yZg/Pnz8PT0xOjRo3CW2+9ZfCZZVevXsWKFSuwdetWqNVqNGzYEL/88gv8/f0BAPPmzcPFixfx1VdfYezYsaV+D+rXr4+AgACEhYUByF+hc9OmTSUe1717d3HOT+3atcWVBhMTE+Hq6qr3iIHSCA8Ph1KpRJ06dXDv3j28//77uHz5MubNm6cTmAq7efMmBg8eDI1Ggx9//FEc5vsi11RGRob4zLoCvr6++PrrrzF06FBcvHgR3bp1w6JFi/Dmm2+ib9++sLW1xdWrV+Hm5mZwvltYWBjGjx8PBwcH3L9/H1FRUXj48OFzzWktTlRUFK5cuYL+/fvrbSt44Hd4eLjBL4b+/PNPtG/fHlFRUUbxeVkgNzcXFhYWuHLlCqpUqYJq1aqhXbt22LJli8HPvISEBNSuXRtdu3ZFxYoV8eeffyI0NBTHjx/H3Llzy/R+DhgwAPPnzy/TMUTGiEGNiIzW06dPsXnzZgwdOhQuLi4A8r8tValUmDBhgrhfamoqfH19IZfLIZPJ4O3tjZUrV4oLOVy7dg1HjhxB3bp10axZM/FcRdFqtTh69CgsLCzQrl07hIWFwd7eXjwuJycHhw8fRnh4OBQKBfLy8pCXlweVSgWtVguJRCL+AfKflVZUbw79u2bNmoXdu3ejQoUKWL16NQ4ePIhPP/0UV65cEZ8tlpeXh2PHjuH27dt4+vQp1Go1NBoNtFotevfujbZt22Lp0qXo1KmTXs9pUXJzcxEYGIjw8HBMnz5dLN+3bx8ePXpkcBW8f9OuXbswffp0REVFlfkB7oXl5ORgzZo1GDVqVInL1Gs0GmzYsAGdO3fWeVDyyzR37lz069cPjRo1ApC/dL2lpSXq1auH999/Hzk5ObCxscGECRMMhqDs7GzMmTMHeXl5sLGxweDBg0v9O39Znj59ik8++QQLFiwo8oHXBfsZw+dlAbVajalTp2LOnDnw9vbGnj170L179yJ7lYH8xxHUrFkTpqamuH37triYDtF/FYMaERH9ZyUkJOD69evFLhLyXyAIAgRBMNjTQURE5YNBjYiIiIiIyMjwqzMiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyfo/YfptVqERsbCxsbmxda5YuIiIiIiEomCAIyMjLg4eFR4gJODGr/YbGxsfDy8irvahARERER/adERUXB09Oz2H0Y1P7DbGxsAORfKCU974aIiIiIiF6MQqGAl5eXeB9eHAa1/7CC4Y62trYMakRERERE/5LSTDviYiJERERERERGhkGNiIiIiIjIyDCoERERERERGRkGNSIiIiIiIiPDoEZERERERGRkGNSIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREbGpLwrQOUvLi4OmZmZ5V0NIiIiIqJXwtLSEvb29uVdjTJhUCPMWj8McnNZeVeDiIiIqNRqa3qUdxXoNSKXyzFlypTXKqwxqBERERHRa2fEiBHlXQV6TaSkpODQoUPIzs5mUCMiIiIiepVcXV3LuwpErxQXEyEiIiIiIjIyDGpERERERERGhkGNiIiIiIjIyDCoERERERERGRkGNSIiIiIiIiPDoEZERERERGRkGNSIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREaGQY2IiIiIiMjIMKgREREREREZGQY1IiIiIiIiI8OgRkREREREZGRMyrsCRETPUudpkJmshL27JfJy1MhMUcKxopXefpkpuYi7n1aqc9q6WsC1st0L1y0tPhtPHyqK3ce1qh1sK1jolKXEZMLKwRxmloY/dnMzVchIykUFX5sXruPrKPpOCnLS80rcz8nHRudaeHApAVWaugIAnj5SIC0uW+8YC1tTeNZxNHg+rUZASnQmnH2M433XqLR4+jgDjp5WeHIjyeA+BdeXRqXFwyuJpTqvqaUJfPydX2ZViYjoFWNQIyKjc/9MHDJTlGg2uDKy0/NwYXM4ur1bDzK57iCA9IQchJ2PL/ImvDALW1Px78osFeLD0yFoBTh6WeuFquIkPclAWnw2KtY2/JpPgpNgamUinjPiciK0ai0SIhTQagS4V8sPi551HBFxORE5GSpkPM1BjiIPHjUcSh3U1HkaxIWmARIJvP5uv6Gy8pKVqkTsvVT4NqwAubmsxP3VeVrk5WqK3Sc+LA0ataAT1G4djRKDWsy9NGg1Wjh6WovblZkqhF9MKPIaUeWqcX7zA7QaWc3glwHPqyztT4nJwqOrT6FIzEFmSi7s3CxRr6sX7p6KRe2OFXX2jbyVLF5f6jwNbh6NQvWWbiXWRxDK3gZVrgZxYWlQ52nhWtkWVg5mZT8JERE9Nwa1VyQyMhJHjhzBhAkTkJ2djSVLluD999+HmZn+P3Rbt27F/v37S33uTz/9FNWqVQMA/PXXXzhw4AC0Wi2aNWuGYcOGQSrliFZ6faXGZuHRtafoNLk2AMDezRLOvja4dzoWdTp56u1vaW+G+t28kRKTZfBGOyU6U+fGPTU2C+f/DIe9uxUkEuD6gSeo18ULVZq5lrqOedlqZCXnGtymytENGzITCTKS88SgkJ6QDUt7M2SlKhEflo6a7T1g19Yd1o7mpX59rUaLwFX3IDWRwraCObzqOBosex4atRZPH2XAreqL9T6GHItC9O1UeNR0KFVQ821Qcm+PMlMl/j05MhMp0ZkQtED4+XjYuuYHY41KC1WOWtxPpfzn95GemIPEB+l657VxNseDiwlwcLfUKTezlsO7nlOJ9TKkLO2Xm0lRwc8GglaAZ20HVG3hhrwcNUxMpWIILfBsj6FEAtTt4qVTlvhQARMz2QsFz+w0JQLX3Ie1gxmkJhLcPByJlsOrwqWS7XOfk4iIyoZB7RXIzMxE37590alTJwCAhYUFTp48iaSkJPzwww96+9+4cQMPHjzAiBEjSnV+G5v8b9y/++47/PTTTxg8eDAEQcCUKVOwa9cu7Nq16+U1huhflJejxqVtEWj4hi8sbP7pAWvQ0wfHl9+Bo6cVPGo46B2nylXj8vYIePs7o1Y7D7H84dVE3Dsdhy5T6og3y+o8LdqOrQFrp/xgFHkrGdf2PkblJi6QSCWlqqe5jSnsnrmpL5ASk6Xzs1tVe9w7HYeqzV1hZmGCe6diEdDXFwBg5WiGijX121MSxdNcpCfkoM/chpCbyYosex5PH2XgwtYH6Dcv4LnPkRKThcSI4oeHPisrTYnkJ5nwrl/KYCQBJLL835dEJoFEkv93E1MZTK3++aetcE+SVq3ba5camwUHDysxfKTFZ8PETAZTi/zjZabP96VXWdufm6mGMlOFbEUe8nLzQ6bTCwzFjL6dAkt7sxcKaiHHouHoaYXmQ6oAAK7vf4ybRyLReXKd5z4nERGVDYPaS6ZQKNCjRw/UqFEDX3/9NQBAIpFg/fr1aNOmDaysrDB//nzxpqJAjRo1MGHCBKxatQoTJkyAXC7X2b57925UqVIFdevWFctq1qyJsLAwWFnl/2Pcr18/dOzYEXfu3EHt2rVfcUuJXi51ngbnNobB299ZL7yYWpigxbCqCNoYhrwcjV7vi9zcBG3fqoEz60KRl61C/e7eSHqSidvHY9B2bHWdHo1nhxY6eFjm98IoNTC1MEF6QjY0Kt3hcwCQkZSL+LA0JEVmIvGhAgkR+j0zAJCXo4FEKkFelhr27pZIi8uGnasFHl19ioykXJhamiA9LhtyCxNkpuQi/Hy8zvEeNR3EIWZJkRnIeJoLM0sTVPCzgdzcBGnx2Xj899ylx9eewtrZHBa2pnpl7tXsAeT3PCme5sDe3RIOHv/cuKtyNUh8pIBaqUEFPxtY2pkhJToTsfdSIWgEhJ+Ph5WjmcFgXBxBK+DGgSeo2c4DNw9Hlfq4jKe5CA2KK3VQc/KyhpOXNW4djYKvvzOyFfnz29R5GuRl/dOjlleod83Bw0p8D+6ciEGOIg/Nh1aBzCQ/kEVcTsSDSwloPbIaLO2fb5jfc7VfEKDVCshOU8KmggW0WqEMYxVL9+VCWQhaAbGhaWJIA/J7PB9eeYrcDBXMbeTFHE1ERC8Lg9pLFBoain79+qFVq1ZYvny5zhBEd3d3BAYGon///ggKCsKKFStQtWpVneOzs7Px559/Yvv27di5cyecnPJvWI4cOYJhw4Zh48aNOkGtV69eOsc3atQIABAbG8ugRq+V3AwVgjaFQaMWIDeV6oWXApWbuCIsKB6x91MR8IavzjYLW1O0fasGzv4RiovbIpD0OANNBlSCnavhnq8CcaHpsHY0E3tR7p2KRW6mCu3erqmzn0wuhYWdKZIjM1GthRsyU3KhSMxBamw2fPz/CRc2FSxg7Zh/ky8zk0FuYQKPmg5IT8iGmaUJ3KvbAwCkUgkkkEAikyDxoQKCRoDr38MNNSotgjaFIzM5F84+1shIVuL6gSdoNaIa8nLVyE5TAsgPjyZmMsjkUr0yALi6+xESHirg4meDsKB4+Pf0gWtlWyie5uDchjBYO5nDzMoEwYcj0XxoFWhUWmSn50EQ8s8j/TvAKLNUiLyZbPD986jlAKtCoSbiSiIkEsC7nlOZglr+66iL/N0D+XMSCwcoZbYaghY4siQEdTp7wrueIxRPdYekyi1M4OStG7rvnYpFXGga6nb2EkMaALhUtkVethqn14ai5Yiq4jzDV93+Cn62cPS0xr1Tsajc2EUc+lgaEkl+OH109alYlp6QP+cx/Pw/Ic6lih3sXCxK1ZasNCU0eVrYVPhnOG5BD3Rmai6DGhHRv4RB7SXZvHkzpk+fjoULF2LChAkG9/H09ERQUBAWLVqEJk2a4M0338Svv/4qbre3t8fx48fx5ptvolmzZjh06BDS0tIwaNAg/PzzzxgwYECxdTh//jykUilq1KjxUttG9KrJ5FLUaOMBjVqLjKRcZCbnIiU6S6d3JSMpBxq1gI7v1EL07RQxWBVmbi2Hf08fnP79PhwqWsGlUvHDxyJvJuPOyRg0H/pPz0Hj/pUgGOjNsLQzhaWdI24ejoSJqRT2bpYwMZXBzs0Sjfr6FfkayY8zAAA56XlQKTWwcc6/4XWoaAUbF3NUaeoKjUoLrVoQ5yPdPh6N3Iw8dJlWByamf4euPY9w/cBjdBhfCzITKWLvpaFhobD6bJlWo8Xj4CS0HF4V7tXsoVFpkfN3r9O1vY/hUd0e/j19AOTP8Qr5KxodJ9aCRCLB0ycZOucWtPmhyBCt5p/3KjMlF3dOxKDtW8/3GSQIQrELimg1WvHvD68kIuR4NID8ayItLhvJkZkGj1PlqPEo4yl8/J1wff8T5Gao0HxYFZxceRedJtUWh9kGH3gCl8q2qN/dC2fXh6H1yGqwdbH4V9qf8CAd6jwtEh4q4OxrAysHM6jztHrBVZGYgwp++de1VitAaiIBBN36adRaqFUSnTKtOv+9K01b1Mr8feWm//REF/RKa/K0+gcSEdErwaD2kvTs2RMtW7bEjz/+WOJcswULFmDq1KnIysrS22ZhYYGdO3diypQpaN68OSQSCT777DO8/fbbxZ4zIiIC48ePx5gxY+Dl5WVwH6VSCaVSKf6sUJRtDgnRqyI3l6FirX+G2EVcSYTURIraHf5Z8S7yVjLiQtMgM5EWucx4alwWLm59gLpdPBF5KxmXtj9E00GVIZXpDg/TqrW4eSQKMXdT0WpEVVTw+2eBhGdXlnyWRCKB1d+9Cxq1FpkpSoNLyxf0TkikEmSm5EIml0KrESD/O2Cq87QwNTf8EZwQoYCPv7MY0gDAp74TzvwRKt5wl0Qqk8K1sh2u7X2MKk1d4BdQAdZO5lDnaZAclQkHDysxBGSl5SE9PhuC1vBwO3MbucGFXArTqrW4tP0hqrVwg72bJZRZqmL3N/g61nKd3/mzHCpawfTvwGDrYoEuU+rg8E+3YGFrCkViDqSFfnfh5+NRsZYjLO3zQ5jUJP8acPGzhVddR0ikElRu4oo7J2LQqK8fkp5kID0hB83frAITU1n+n797Jv+N9j8OToKdqwVMLUxwYcsDNO5fCb4NncV5eAVcq/zz6Ae1Ugu5WX49C9cvL1sNS3szVG3uipyMPJ2FakrTloLXVOdpYGr5z/UKPP+8PSIiKjsGtZfE1tYWtra2aNmyJTIzM3Hr1i1s27YNX375pc5+U6ZMwZw5c+Dn5ycObXyWTCbDpEmTsGHDBqhUKtSpU/zk7cOHD2P48OHo0KEDfvnllyL3++qrrzB//vyyN47oX5byd5AoTKPWFhui4kLTcHnXQ9Tt5IlKjV3gU98Zgavv4dKOCDQd+E9Y06q1OLcxHJAAnSbXhrl12YZxCYIgrviYo8i/GTcxkyHiciLqdfcGhPyFF9z+XoZfpdRAEABHL2vkZqhg42QOJ29rPL6RBEs7U4OvoVFpxWBRoGChk7Ksst5qRFVE3U7Bg4sJuH82Di2HV4NtBXNAAPKydYNEpcYuRQa10gyXu3sqFhlJOZDVcUT4+XioVfk39o+vJ6GCn81LWS3Qo7o9lFkqpMZm6T33zLWKHSSPFDC3lsO2ggWiQlKQmZwrrgDpXd8JUplUp5e2eis3nFp9DxGXExF6Lg4NenmL4bhwfV91+xVP84fQetdzhLmVHJWbuMDCVo763byLfT9yFHk6j514VnJUJm4fj0b78TXFedGlaYulnSkgyQ/wBUNNs//+IsLGqfSrkxIR0YvhV2Mv2cCBAzFmzBhUr14d9evXx5gxY3T+CIIgLv5RlOPHj6NNmzaYM2cOFixYgD59+mDbtm0G9/3222/Rr18/fPzxx9i+fTvMzYv+R/Tjjz9Genq6+CcqqmzzR4j+DcosFWJD0+BVV3d5eVWuBiZFfJsfcTkRF7dFIKC3Lyo1dgGQ33PQenQ1JD/JRMixf6718AsJyMtRo9XwqkWGNENDHwsU9KhZOZnDwjb/eLcqdnD0soag0SIzJRfu1e1h45w/HyjiciJqtHYXzxtyPBrhF+KRGpMFhyJW5XPyskLM3TSdesSHp8OhopXOnKriaNVaKLPU8K7nhA4TasHFzxZPbiTBzEoOC1s5nLxt4N/DG/49vFG/mxe86jpCaiKFRAoIGkHntQuGyxn6UzBcztLeFN51nZCZnCsOXwXy5zTlZpa9d60oqbHZuLzzocFt907FIivln1ED7tXt4dPAGT4NnMUhp4XJTKTwDaiAGweewMbZHBVrGX6kwatuf1RICqq3chPDlJOXNSztzKDVCEiO+mc4Z3Jkpk6YTonW/0KjMJdKtjAxlekEs9K0Rf730v5RIf8cFx2SAkdPK5hZcX4aEdG/hT1qr8itW7dQq1YtnTKtVovc3FxYW1sbPEar1eKrr77CwoUL8fPPP+Ott94CAJiYmGDYsGFIT0/H+PHjxf03btyI+fPn4/jx42jVqlWJdTIzMzP4HDciY6HO0+DitghUb+mmd0OYkZSrs2hDYW5V7eDgYam3UqO1ozlaj66ms+pjQoQCEgn+nt/0D8/ajnDyssaV3Y+gzFSh1chqunVTahBzLzV/Hl1iDlR5GmQk5SI9Lhs3j0SiQU9vHPvlDmRyKTpNyl/MRyKVIOANX7HXQyKRoNngykiNycLj60mo391wj0mtDhURuOoeAlfdg0tlW2QmK/H0kQKtRlUzuL8hGo2AE7/dgWcdR5iYypAUmYmGvfPnpNXr5o2rex4hNTYLVvZmiAtLQ6VGFeD098O/BeTPY3OsaIVKjV1KNVyuUiMXnZ+VWSo8CU5GnY6e4iqWUSHJsHW1hJ2L/gPGJVJAqy65vzA1NsvgA8rT4rORl63G7ePRsHPL327rYlHkEvUpMVm4fyYWisQcNB9aBVG3k3F2fRhqtnOHs7dub92rbr9vA2dY2MpxNzBWLNOotLi0PQKCALR4swogAe6fi4PMRIomAypBKpMgKiSlyGuoQO2OFXFhywN41naETC4tVVsAoG5nT5xdHwZ1nhYmcikibyWj9ajqJR5HREQvD4PaK6BWq7F9+3bs27dPpzw9Pb3YHrUPPvgA27Ztw7Fjx9CyZUudcplMhqlTp6Jjx46oVKkSAGDhwoWYOXNmqUIakbGLC01DyLFoeNVxRI02HhAEAfdOx0FmIkFejgaRN5PRfnxNveNyM1SIvZcKAEUuJgEAZlZyeNd3gns1O2Sl5UF4ZqpXQQ+Sdz0naPL0F7SQmkiheJqDqi3cILeQwcrBDHIzGQSNAGsnc5zbGA63anZQ52lxYcsD+DZ0hns1ezj7WCP0bBxi76fB298J5tZyJEdnwquuk97cuQIWNqboMrUOom6nICtFiQp+NmjQ01sMr+Y2cr0HdD9bJjeToeWIaoi9lwqJRILWo6qJvS9edRxhW8Ec8WHpUCk1qNfNSwwnFramaDO6OuLD02Bm9fz/RMjkUlRp5io+002r0eLq3sfoPNnwirS2FSyQmarEzcORRQ4JVWarEXE5EfW7eyM+PB0p0ZkwMZUhMyUXl7ZHoFEfP6jyNDi1+j7UKi0SIxT5C6gIAgQt4ORtjSfByYi+kwKpTILKTVzQbHAVSGUSVKzlgKTIDISdi8e1pMdwq2oHt2p2cK38fA/+Lkv7C4JcgRxFHoI2hsPRywoNevqIw16bDa6MoI3huLj1Abzr5V8/BQuLFMXJyxqN+vqVOPfyWRX8bP9euCcVEinQcVJtDnskIvqXSYTixvjQc1mwYAH279+Py5cv65QfPnwY48aNQ0xMjE757NmzER8fjyVLlkCpVMLFRfeb2QKPHj2Cn1/+6nIajQZyuRweHh6wt7fX2a9v3756c+MMUSgUsLOzQ585DXV6HIjKQ+TNZNh7WOr0loQci0JetgZSmQQeNezhWkX3plmRmIMnwUmlOr+5rSmqPhNuXlRmci6SozOhVmrhVtVOvOHOTMlFfFg6KjWqAAAIO58AUwsZfBo4Q2YiRcKDdFTws4FUln/znPhQAUEr6LXv/8nTxxm4fSzaYNguEB+ejtj7qdCoDC+YIpVJ4eRtDd8Gzkh8qEDiQwUq+NrAzi3/eXVufz/eQJWrRmxoGrJSlPkramoFmFnJUblxBTy+kQT36vY6C2w8KzdThbiwNNi5Wr7QQ6MLK03748LSYCKXwtHLGnGhafCsrT8UU63UIPGhAvYeVsjLVsPOzQIPLiTo7BN9JxWmFjKdeXEyuVQcFkz0/+L3GSfKuwr0mkhISMDGjRsxYcIEeHh4lGtdCu6/09PTYWtb/Pxt9qi9ZEuXLsUvv/yCM2fOAACGDRsGpVIJqVSKY8eO4cMPPzR43NmzZzFlypRSvcawYcPQrVs3rF+/3uD2ypUrP1/licqRoQcd1+1seAXTArYuFqjbpfh9XiVrJ3Px+VI65Y7mqNLsn/Iabdx1tj8byF7GQhtGTxBQs33x/zi6VbUTw1ZJXCrZ6rxvhY+Tm5vAp77hlUGrNncr8dzm1nL4NaxQqnqUWinaX/CQcgAGQxqQv3CNx98PhLe0M4Wg1X+kgUvl/PelcLmJht/JEhG9bhjUXpKkpCQMHjwY2dnZOHfuHKpUyX8u08iRIxEdHQ2tVotp06ahTZs2esf269cPvr6+pX6tihUrQiqVlvgYACIiY1H4EQj/Ra+q/RKppNhHGhAR0euLQe0lcXZ2xg8//AB/f39x5S4A6N69e4nHNm3aFE2bNn2V1SMiIiIiotcIg9pL1KBBg/KuAhERERER/R/gc9SIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREaGQY2IiIiIiMjIMKgREREREREZGQY1IiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjY1LeFSAiIiIiKquEhITyrgK9JlJSUsq7Cs+FQY1QU9sFZhqz8q4GERERUalt3LixvKtArxG5XA5LS8vyrkaZMKgRxowZAxsbm/KuBhERERHRK2FpaQl7e/vyrkaZMKgR3N3dYWtrW97VICIiIiKiv3ExESIiIiIiIiPDoEZERERERGRkGNSIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREaGQY2IiIiIiMjIMKgREREREREZGQY1IiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyDGhERERERkZFhUCMiIiIiIjIyDGpERERERERGhkGNiIiIiIjIyDCoERERERERGRkGNSIiIiIiIiPDoEZERERERGRkGNSIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREaGQY2IiIiIiMjIMKgREREREREZGQY1IiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyDGhERERERkZFhUCMiIiIiIjIyDGpERERERERGxqS8K0DlLy4uDpmZmeVdDXoNWFpawt7evryrQURERPR/j0GNsG7dOpiZmZV3Neg1IJfLMWXKFIY1IiIioleMQY3QuXNneHt7l3c1yMilpKTg0KFDyM7OZlAjIiIiesUY1AgODg5wdXUt72oQEREREdHfuJgIERERERGRkWFQIyIiIiIiMjIMakREREREREaGQY2IiIiIiMjIMKgREREREREZGQY1IiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZEye98AtW7agRYsW8Pb2xurVq9GzZ0+4u7vr7ff555/jwYMHpTrnDz/8AFdX1+etkmj69OlISUkpcrujoyOWLl2qU5aWloZ169ZhxowZBo958uQJ9uzZgy5duqBmzZovXMfXzcOHD7Fo0aJS7bt69Wrx70ePHkVOTg769u0LlUqFSZMmGTxm+vTpqFevnsFtJ06cgLW1NZo2bVr2ir9kKSkpOHXqFHJzc2FmZobDhw/r7ePg4IDvvvsOALB9+3Yc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k/KuAJW/1NRUJCQklHc1yMilpKSUdxWIiIiI/jMY1AjHjh2DmZlZeVeDXgNyuRyWlpblXQ0iIiKi/3sMaoQxY8bAxsamvKtBrwFLS0vY29uXdzWIiIiI/u8xqBHc3d1ha2tb3tUgIiIiIqK/cTERIiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyDGhERERERkZFhUCMiIiIiIjIyDGpERERERERGhkGNiIiIiIjIyDCoERERERERGRkGNSIiIiIiIiPDoEZERERERGRkGNSIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREaGQY2IiIiIiMjIMKgREREREREZGQY1IiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyDGhERERERkZFhUCMiIiIiIjIyDGpERERERERGhkGNiIiIiIjIyDCoERERERERGRkGNSIiIiIiIiPDoEZERERERGRkGNSIiIiIiIiMDIMaERERERGRkWFQIyIiIiIiMjIMakREREREREbGpLwrQOUvLi4OmZmZ5V0NIiL6j7O0tIS9vX15V4OIyCgwqBFmrR8GubmsvKtBRP9namt6lHcV6DUjl8sxZcoUhjUiIjCoERHRKzJixIjyrgK9RlJSUnDo0CFkZ2czqBERgUGNiIheEVdX1/KuAhER0WuLi4kQEREREREZGQY1IiIiIiIiI8OgRkREREREZGQY1IiIiIiIiIwMgxoREREREZGRYVAjIiIiIiIyMgxqRERERERERoZBjYiIiIiIyMgwqBERERERERkZBjUiIiIiIiIjw6BGRERERERkZBjUiIiIiIiIjAyDGhERERERkZFhUCMiIiIiIjIyDGpERERERERGxqS8K0D/DU+CkyCVSeBV1wmRN5MhQIBPfWe9/ULPxuHxjaRSnbNOJ09UrOXwwnW7eSQSqTFZkMoMf2+hzFKh1chqsLA11Sm/vu8xqrd2h5WDmU65KleD1Lgs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",
      "text/plain": [
       "<Figure size 950x360 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 可视化：每个分区的消费进度（已提交 offset vs 最新 offset）\n",
    "fig, ax = plt.subplots(figsize=(9.5, 3.6))\n",
    "for i, p in enumerate(partitions):\n",
    "    newest = len(p)\n",
    "    ax.barh(i, newest + 1, color='#F2F2F2', ec='#7F7F7F', height=0.5)\n",
    "    ax.barh(i, max(offsets[i], 0.001), color='#548235', height=0.5)\n",
    "    ax.text(newest / 2, i, f'分区{i}: 最新offset={newest}, 已提交={offsets[i]}, 积压={newest - offsets[i]}',\n",
    "            ha='center', va='center', fontsize=9.5, color='black')\n",
    "ax.set_yticks(range(n_part)); ax.set_yticklabels([f'分区{i}' for i in range(n_part)])\n",
    "ax.set_xlabel('消息位置（offset 从 0 递增）')\n",
    "ax.set_title('消费进度：绿色=已提交位置；灰色剩余=未消费积压', fontsize=12)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-4",
   "metadata": {},
   "source": [
    "## 4️⃣ 重平衡（Rebalance）演示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bd05-rebalance",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:11.917038Z",
     "iopub.status.busy": "2026-10-08T09:32:11.916188Z",
     "iopub.status.idle": "2026-10-08T09:32:11.982484Z",
     "shell.execute_reply": "2026-10-08T09:32:11.966437Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5 分区 / 3 消费者 分配:\n",
      "  c0: 分区 [0, 3]\n",
      "  c1: 分区 [1, 4]\n",
      "  c2: 分区 [2]\n",
      "\n",
      "  消费者加入/退出 -> 触发 Rebalance（分区重新分配）；\n",
      "  代价：rebalance 期间消费暂停、可能重复消费（需幂等/去重）。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 5 个分区、3 个消费者时的分配（简化 round-robin）\n",
    "n_part5, n_cons3 = 5, 3\n",
    "assign = {f'c{i}': [] for i in range(n_cons3)}\n",
    "for p in range(n_part5):\n",
    "    assign[f'c{p % n_cons3}'].append(p)\n",
    "print('5 分区 / 3 消费者 分配:')\n",
    "for c, ps in assign.items():\n",
    "    print(f'  {c}: 分区 {ps}')\n",
    "print('''\n",
    "  消费者加入/退出 -> 触发 Rebalance（分区重新分配）；\n",
    "  代价：rebalance 期间消费暂停、可能重复消费（需幂等/去重）。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-5",
   "metadata": {},
   "source": [
    "## 5️⃣ 可靠性：ACK 与副本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bd05-ack",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:11.987115Z",
     "iopub.status.busy": "2026-10-08T09:32:11.986216Z",
     "iopub.status.idle": "2026-10-08T09:32:12.247781Z",
     "shell.execute_reply": "2026-10-08T09:32:12.245899Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "生产者 acks 三档：\n",
      "  acks=0：不等确认（最快，可能丢）；\n",
      "  acks=1：leader 落盘即确认（默认，丢 leader 时可能丢）；\n",
      "  acks=all：全部 ISR 副本确认（最稳，慢）。\n",
      "\n",
      "消费者语义：\n",
      "  At-most-once ：可能丢（offset 先提交）；\n",
      "  At-least-once：可能重（offset 后提交 + 重试）；\n",
      "  Exactly-once ：幂等写入 + 事务（Kafka 支持）。\n",
      "\n",
      "可靠性组合拳：3 副本 + acks=all + 消费端幂等去重。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''生产者 acks 三档：\n",
    "  acks=0：不等确认（最快，可能丢）；\n",
    "  acks=1：leader 落盘即确认（默认，丢 leader 时可能丢）；\n",
    "  acks=all：全部 ISR 副本确认（最稳，慢）。\n",
    "\n",
    "消费者语义：\n",
    "  At-most-once ：可能丢（offset 先提交）；\n",
    "  At-least-once：可能重（offset 后提交 + 重试）；\n",
    "  Exactly-once ：幂等写入 + 事务（Kafka 支持）。\n",
    "\n",
    "可靠性组合拳：3 副本 + acks=all + 消费端幂等去重。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-6",
   "metadata": {},
   "source": [
    "## 6️⃣ Kafka 面试高频追问"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "bd05-faq",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:32:12.267545Z",
     "iopub.status.busy": "2026-10-08T09:32:12.266876Z",
     "iopub.status.idle": "2026-10-08T09:32:12.498973Z",
     "shell.execute_reply": "2026-10-08T09:32:12.487123Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1) 分区顺序 vs 全局顺序？ -> 只保证分区内有序，要全局有序只能 1 分区（牺牲并行）；\n",
      "2) 消息积压怎么办？       -> 扩分区+扩消费者、批量消费、临时降级；\n",
      "3) 消费速度跟不上？       -> 增加消费者（≤分区数）、优化反序列化、批量；\n",
      "4) 数据重复消费？         -> 幂等（唯一键去重）或事务；\n",
      "5) Kafka vs RocketMQ？    -> 吞吐/顺序/事务侧重不同；\n",
      "6) 为什么高吞吐？         -> 顺序写磁盘、零拷贝、批量/压缩。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''1) 分区顺序 vs 全局顺序？ -> 只保证分区内有序，要全局有序只能 1 分区（牺牲并行）；\n",
    "2) 消息积压怎么办？       -> 扩分区+扩消费者、批量消费、临时降级；\n",
    "3) 消费速度跟不上？       -> 增加消费者（≤分区数）、优化反序列化、批量；\n",
    "4) 数据重复消费？         -> 幂等（唯一键去重）或事务；\n",
    "5) Kafka vs RocketMQ？    -> 吞吐/顺序/事务侧重不同；\n",
    "6) 为什么高吞吐？         -> 顺序写磁盘、零拷贝、批量/压缩。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9027d61",
   "metadata": {},
   "source": [
    "### 版本动态：Kafka 4.0（2025-03 发布）\n",
    "\n",
    "- 彻底移除 ZooKeeper，**KRaft 模式**成为唯一运行模式（元数据用 Raft 协议自管理，部署更简单）；\n",
    "- **KIP-848 新消费者组协议**正式可用：重平衡由 Broker 端协调增量完成，\n",
    "  改善旧协议\"stop-the-world 全组暂停\"的问题（面试提到可加分）；\n",
    "- 客户端要求 Java 11+、Broker 要求 Java 17+。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd05-7",
   "metadata": {},
   "source": [
    "## 📝 自测清单\n",
    "\n",
    "- [ ] 能画出 Topic/Partition/Offset/Broker 结构\n",
    "- [ ] 能手写 key 哈希分区路由\n",
    "- [ ] 能解释消费者组与重平衡\n",
    "- [ ] 能对比 acks 三档与消费三语义\n",
    "- [ ] 能答 6 个 Kafka 追问"
   ]
  }
 ],
 "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
}
