gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单
  • 量化投资
  • 在线查询工具
    • 去行号
    • 在线时间戳转换工具
    • 免费图片批量修改尺寸在线工具
    • SVG转JPG在线工具

DeepSeek-R1论文中文翻译及通俗解释

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  
  • 作者: east
  • ( 页面12 )
深度学习 2月 8,2025

DeepSeek-R1论文中文翻译及通俗解释

最近火遍全网,功能媲美OpenAI等国外最强大模型的DeepSeek,

R1论文链接以放在下面,供大家学习参考。
论文链接:https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf

考虑到很多人英文阅读起来还是有点障碍,翻译成中文并附上通俗解释。

摘要

我们推出了第一代推理模型 DeepSeek-R1-Zero 和 DeepSeek-R1。DeepSeek-R1-Zero 是通过大规模强化学习(RL)训练出来的模型,它在训练时没有将监督微调(SFT)作为初步步骤,却展现出了卓越的推理能力。在强化学习的过程中,DeepSeek-R1-Zero 自然而然地产生了许多强大且有趣的推理行为。不过,它也面临一些问题,比如生成内容的可读性差、存在语言混合现象。为了解决这些问题并进一步提升推理性能,我们推出了 DeepSeek-R1,该模型在强化学习之前加入了多阶段训练和冷启动数据。DeepSeek-R1 在推理任务上的表现与 OpenAI-o1-1217 相当。为了支持研究社区,我们开源了 DeepSeek-R1-Zero、DeepSeek-R1,以及基于 Qwen 和 Llama 从 DeepSeek-R1 中提炼出来的六个稠密模型(15 亿、70 亿、80 亿、140 亿、320 亿、700 亿参数规模)。

通俗解释

这部分主要讲了团队搞出了两个超厉害的推理模型,叫 DeepSeek-R1-Zero 和 DeepSeek-R1。DeepSeek-R1-Zero 是靠大规模强化学习训练出来的,没经过监督微调,就能自己 “琢磨” 出好多厉害的推理方法。但它也有点小毛病,像写出来的东西不太好懂,还会把不同语言混在一起。所以团队又搞出了 DeepSeek-R1,这个模型训练的时候加了些 “冷启动数据”,还分好几个阶段训练,就解决了前面那些问题,在推理能力上和 OpenAI 的一个超厉害的模型(OpenAI-o1-1217 )差不多厉害。最后,为了让大家一起研究,团队把这些模型还有基于它们做出来的一些小模型都开源了,谁都能拿去用。

1. 引言

近年来,大语言模型(LLMs)经历了快速的迭代和发展(Anthropic, 2024; Google, 2024; OpenAI, 2024a),与通用人工智能(AGI)之间的差距逐渐缩小。
最近,后训练成为完整训练流程的重要组成部分。研究表明,后训练可以提高推理任务的准确性,使模型符合社会价值观,并适应用户偏好,同时与预训练相比,所需的计算资源相对较少。在推理能力方面,OpenAI 的 o1(OpenAI, 2024b)系列模型率先通过增加思维链推理过程的长度来实现推理时的扩展。这种方法在数学、编码和科学推理等各种推理任务中取得了显著的改进。然而,如何在测试时有效地进行扩展,仍然是研究界有待解决的问题。此前有多项研究探索了各种方法,包括基于过程的奖励模型(Lightman 等人,2023; Uesato 等人,2022; Wang 等人,2023)、强化学习(Kumar 等人,2024)以及蒙特卡洛树搜索和束搜索等搜索算法(Feng 等人,2024; Trinh 等人,2024; Xin 等人,2024)。但这些方法中,没有一种能在通用推理性能上与 OpenAI 的 o1 系列模型相媲美。
在本文中,我们迈出了利用纯强化学习(RL)提升语言模型推理能力的第一步。我们的目标是探索大语言模型在没有任何监督数据的情况下发展推理能力的潜力,重点关注它们如何通过纯强化学习过程实现自我进化。具体来说,我们以 DeepSeek-V3-Base 为基础模型,采用 GRPO(Shao 等人,2024)作为强化学习框架,以提高模型在推理任务中的性能。在训练过程中,DeepSeek-R1-Zero 自然地展现出许多强大且有趣的推理行为。经过数千次强化学习步骤后,DeepSeek-R1-Zero 在推理基准测试中表现卓越。例如,在 2024 年美国数学邀请赛(AIME 2024)上,其单次回答正确(pass@1)的得分从 15.6% 提升到了 71.0%,通过多数投票法,得分进一步提高到 86.7%,与 OpenAI-o1-0912 的性能相当。
然而,DeepSeek-R1-Zero 也面临着诸如可读性差和语言混合等挑战。为了解决这些问题并进一步提升推理性能,我们推出了 DeepSeek-R1,它结合了少量冷启动数据和多阶段训练流程。具体而言,我们首先收集数千条冷启动数据,对 DeepSeek-V3-Base 模型进行微调。之后,像训练 DeepSeek-R1-Zero 一样,进行面向推理的强化学习。在强化学习过程接近收敛时,我们通过对强化学习检查点进行拒绝采样,结合来自 DeepSeek-V3 在写作、事实性问答和自我认知等领域的监督数据,创建新的监督微调(SFT)数据,然后重新训练 DeepSeek-V3-Base 模型。用新数据微调后,该检查点再进行一轮强化学习,同时考虑所有场景的提示。经过这些步骤,我们得到了一个名为 DeepSeek-R1 的检查点,其性能与 OpenAI-o1-1217 相当。
我们进一步探索从 DeepSeek-R1 向较小的稠密模型进行知识蒸馏。以 Qwen2.532B(Qwen, 2024b)为基础模型,直接从 DeepSeek-R1 进行蒸馏的效果优于在其基础上应用强化学习。这表明,较大基础模型发现的推理模式对于提高推理能力至关重要。我们开源了基于 Qwen 和 Llama(Dubey 等人,2024)系列的蒸馏模型。值得注意的是,我们蒸馏得到的 140 亿参数模型大幅超越了当前最先进的开源模型 QwQ-32B-Preview(Qwen, 2024a),而蒸馏得到的 320 亿和 700 亿参数模型在稠密模型的推理基准测试中创下了新纪录。

1.1 研究贡献

  • 后训练:在基础模型上进行大规模强化学习:我们直接将强化学习应用于基础模型,而不依赖监督微调(SFT)作为初步步骤。这种方法使模型能够探索思维链(CoT)来解决复杂问题,从而开发出 DeepSeek-R1-Zero。DeepSeek-R1-Zero 展示了自我验证、反思和生成长思维链等能力,为研究界树立了重要的里程碑。值得注意的是,这是首次通过公开研究验证,大语言模型的推理能力可以纯粹通过强化学习来激发,而无需监督微调。这一突破为该领域未来的发展铺平了道路。
    我们介绍了开发 DeepSeek-R1 的流程。该流程包含两个强化学习阶段,旨在发现更好的推理模式并符合人类偏好,还包含两个监督微调阶段,为模型的推理和非推理能力奠定基础。我们相信这个流程将有助于行业开发出更优秀的模型。
  • 知识蒸馏:小模型也能有强大能力:我们证明了可以将大模型的推理模式蒸馏到小模型中,与小模型通过强化学习发现的推理模式相比,这样能带来更好的性能。开源的 DeepSeek-R1 及其应用程序编程接口(API)将有助于研究社区在未来蒸馏出更好的小模型。
    利用 DeepSeek-R1 生成的推理数据,我们对研究社区中广泛使用的几个稠密模型进行了微调。评估结果表明,蒸馏得到的较小稠密模型在基准测试中表现出色。DeepSeek-R1-Distill-Qwen-7B 在 2024 年美国数学邀请赛(AIME 2024)上的得分达到 55.5%,超过了 QwQ-32B-Preview。此外,DeepSeek-R1-Distill-Qwen-32B 在 AIME 2024 上的得分达到 72.6%,在 MATH-500 上的得分达到 94.3%,在 LiveCodeBench 上的得分达到 57.2% 。这些结果显著超越了以前的开源模型,与 o1-mini 相当。我们向社区开源了基于 Qwen2.5 和 Llama3 系列的 15 亿、70 亿、80 亿、140 亿、320 亿和 700 亿参数规模的蒸馏模型检查点。

1.2 评估结果总结

  • 推理任务:(1)DeepSeek-R1 在 2024 年美国数学邀请赛(AIME 2024)上的单次回答正确(Pass@1)得分达到 79.8%,略高于 OpenAI-o1-1217。在 MATH-500 测试中,它取得了令人瞩目的 97.3% 的高分,与 OpenAI-o1-1217 表现相当,且显著超越其他模型。(2)在与编码相关的任务中,DeepSeek-R1 在代码竞赛任务中展现出专家水平,在 Codeforces 平台上获得 2029 的 Elo 评级,超过了竞赛中 96.3% 的人类参与者。在与工程相关的任务中,DeepSeek-R1 的表现略优于 DeepSeek-V3,这对开发者在实际工作中会有所帮助。
  • 知识水平:在 MMLU、MMLU-Pro 和 GPQA Diamond 等基准测试中,DeepSeek-R1 取得了出色的成绩,在 MMLU 上得分为 90.8%,在 MMLU-Pro 上得分为 84.0%,在 GPQA Diamond 上得分为 71.5%,显著超越 DeepSeek-V3。虽然在这些基准测试中,其性能略低于 OpenAI-o1-1217,但 DeepSeek-R1 超越了其他闭源模型,展示了其在教育任务中的竞争优势。在事实性基准测试 SimpleQA 上,DeepSeek-R1 的表现优于 DeepSeek-V3,证明了它处理基于事实的查询的能力。在这个基准测试中,OpenAI-o1 也超越了 GPT-4o,呈现出类似的趋势。
  • 其他方面:DeepSeek-R1 在广泛的任务中也表现出色,包括创意写作、通用问答、编辑、总结等。它在 AlpacaEval 2.0 上的长度控制胜率达到 87.6%,在 ArenaHard 上的胜率达到 92.3%,展示了其智能处理非考试类查询的强大能力。此外,DeepSeek-R1 在需要长上下文理解的任务中表现卓越,在长上下文基准测试中大幅超越 DeepSeek-V3。

通俗解释

大语言模型这几年发展特别快,和通用人工智能的距离越来越近。后训练在提升模型能力上很有用,OpenAI 的 o1 系列模型通过增加推理步骤让模型在很多推理任务上表现变好,但怎么让模型在测试的时候也能这么厉害,大家还在研究。
这篇论文里,团队想用纯强化学习来提升模型的推理能力。他们用 DeepSeek-V3-Base 做基础模型,通过强化学习训练出了 DeepSeek-R1-Zero。这个模型训练的时候自己就琢磨出好多厉害的推理方法,在 AIME 2024 测试里成绩提高特别多。不过它也有问题,写出来的东西不好懂,还会把不同语言混在一起。
所以团队又搞出了 DeepSeek-R1,训练的时候先给模型一些 “冷启动数据”,再分阶段训练,最后这个模型的表现和 OpenAI-o1-1217 差不多。而且,团队还把 DeepSeek-R1 的推理能力 “教” 给了一些小模型,这些小模型在测试里成绩也很好,超过了很多以前的开源模型。
从测试结果来看,DeepSeek-R1 在推理任务上特别厉害,像数学和编码任务成绩都很好;在知识类测试里也不错,比 DeepSeek-V3 好很多;在其他任务,像写作、问答这些方面也表现很棒,理解长文章的能力也很强。

2. 方法

2.1 概述

以往的研究大多依赖大量的监督数据来提升模型性能。在本研究中,我们证明了即使不使用监督微调(SFT)作为冷启动,通过大规模强化学习(RL)也能显著提升模型的推理能力。此外,加入少量冷启动数据可以进一步提升模型性能。在接下来的章节中,我们将介绍:(1)DeepSeek-R1-Zero,它直接在基础模型上应用强化学习,不使用任何监督微调数据;(2)DeepSeek-R1,它从用数千个长思维链(CoT)示例微调后的检查点开始应用强化学习;(3)将 DeepSeek-R1 的推理能力蒸馏到小型稠密模型中。

2.2 DeepSeek-R1-Zero:基础模型上的强化学习

强化学习在推理任务中已显示出显著的有效性,我们之前的研究(Shao 等人,2024;Wang 等人,2023)已证实了这一点。然而,这些研究严重依赖监督数据,而收集监督数据非常耗时。在本节中,我们探索大语言模型在无任何监督数据的情况下发展推理能力的潜力,重点关注其通过纯强化学习过程的自我进化。我们先简要介绍我们的强化学习算法,然后展示一些令人振奋的结果,希望能为研究社区提供有价值的见解。

2.2.1 强化学习算法:组相对策略优化

为节省强化学习的训练成本,我们采用组相对策略优化(GRPO)(Shao 等人,2024)。该方法舍弃了通常与策略模型规模相同的价值网络,而是通过组得分来估计基线。具体来说,对于每个问题,

用户与助手进行对话。用户提出问题,助手进行解答。助手先在脑海中思考推理过程,然后为用户提供答案。推理过程和答案分别包含在<think></think>和<answer></answer>标签内,即<think>推理过程在此处</think><answer>答案在此处</answer>。用户:提示。助手:

用户助手
提示<think>推理过程在此处</think><answer>答案在此处</answer>

表 1 DeepSeek-R1-Zero 的模板。训练过程中,提示部分会被具体的推理问题替代。

2.2.2 奖励建模

奖励是训练信号的来源,它决定了强化学习的优化方向。为训练 DeepSeek-R1-Zero,我们采用基于规则的奖励系统,主要包含两种类型的奖励:

  • 准确率奖励:准确率奖励模型用于评估回答是否正确。例如,对于有确定答案的数学问题,要求模型以指定格式(如在方框内)给出最终答案,以便基于规则可靠地验证答案的正确性。同样,对于 LeetCode 问题,可以使用编译器根据预定义的测试用例生成反馈。
  • 格式奖励:除准确率奖励模型外,我们还采用格式奖励模型,强制模型将其思考过程置于<think>和</think>标签之间。
    在开发 DeepSeek-R1-Zero 时,我们没有应用结果或过程神经奖励模型,因为我们发现神经奖励模型在大规模强化学习过程中可能会遭受奖励作弊问题,并且重新训练奖励模型需要额外的训练资源,还会使整个训练流程变得复杂。

2.2.3 训练模板

为训练 DeepSeek-R1-Zero,我们首先设计了一个简单的模板,引导基础模型遵循我们指定的指令。如表 1 所示,该模板要求 DeepSeek-R1-Zero 首先生成推理过程,然后给出最终答案。我们有意将约束限制在这种结构格式上,避免任何特定内容的偏差,例如强制要求反思性推理或推崇特定的问题解决策略,以确保我们能准确观察模型在强化学习过程中的自然发展。

2.2.4 DeepSeek-R1-Zero 的性能、自我进化过程和顿悟时刻

  • DeepSeek-R1-Zero 的性能:图 2 展示了 DeepSeek-R1-Zero 在 2024 年美国数学邀请赛(AIME 2024)基准测试中,整个强化学习训练过程中的性能变化轨迹。如图所示,随着强化学习训练的推进,DeepSeek-R1-Zero 的性能稳步提升。值得注意的是,AIME 2024 上的平均单次回答正确(pass@1)得分显著提高,从最初的 15.6% 跃升至令人瞩目的 71.0%,达到了与 OpenAI-o1-0912 相当的性能水平。这一显著改进凸显了我们的强化学习算法随着时间推移优化模型性能的有效性。
    表 2 对 DeepSeek-R1-Zero 和 OpenAI 的 o1-0912 模型在各种推理相关基准测试中的表现进行了对比分析。结果显示,强化学习使 DeepSeek-R1-Zero 在无需任何监督微调数据的情况下获得了强大的推理能力。这是一项值得关注的成就,因为它强调了模型仅通过强化学习就能有效学习和泛化的能力。此外,通过多数投票法,DeepSeek-R1-Zero 的性能还可以进一步提升。例如,在 AIME 基准测试中采用多数投票法时,DeepSeek-R1-Zero 的性能从 71.0% 提升至 86.7%,超过了 OpenAI-o1-0912 的性能。DeepSeek-R1-Zero 在使用和不使用多数投票法的情况下都能取得如此有竞争力的性能,凸显了其强大的基础能力以及在推理任务中进一步提升的潜力。
  • DeepSeek-R1-Zero 的自我进化过程:DeepSeek-R1-Zero 的自我进化过程生动展示了强化学习如何驱动模型自主提升推理能力。通过直接从基础模型启动强化学习,我们可以在不受监督微调阶段影响的情况下,密切监测模型的发展。这种方法清晰呈现了模型随时间的演变,尤其是在处理复杂推理任务的能力方面。
    如图 3 所示,DeepSeek-R1-Zero 的思考时间在整个训练过程中持续改善。这种改善并非外部调整的结果,而是模型内部的自然发展。DeepSeek-R1-Zero 通过利用更长的测试时计算资源,自然而然地获得了解决日益复杂推理任务的能力。这种计算过程从生成数百到数千个推理令牌不等,使模型能够更深入地探索和优化其思维过程。
    这种自我进化最显著的特点之一是,随着测试时计算量的增加,模型会出现复杂的行为。例如,模型会自发地进行反思(重新审视和评估之前的步骤),并探索解决问题的替代方法。这些行为并非预先编程设定,而是模型与强化学习环境交互的结果。这种自发的发展显著增强了 DeepSeek-R1-Zero 的推理能力,使其能够更高效、准确地处理更具挑战性的任务。
  • DeepSeek-R1-Zero 的顿悟时刻:在训练 DeepSeek-R1-Zero 的过程中,观察到一个特别有趣的现象 ——“顿悟时刻”。如表 3 所示,这个时刻出现在模型的一个中间版本中。在此阶段,DeepSeek-R1-Zero 学会了通过重新评估初始方法,为一个问题分配更多思考时间。这种行为不仅证明了模型推理能力的不断提升,也是强化学习能够产生意想不到的复杂结果的生动例证。
    这个时刻不仅对模型来说是一个 “顿悟时刻”,对于观察其行为的研究人员而言也是如此。它凸显了强化学习的力量与魅力:我们并非直接教模型如何解决问题,而只是为其提供正确的激励,它就能自主开发出先进的问题解决策略。“顿悟时刻” 有力地提醒我们,强化学习具有解锁人工智能系统新智能水平的潜力,为未来开发更自主、自适应的模型铺平了道路。
  • DeepSeek-R1-Zero 的缺点:尽管 DeepSeek-R1-Zero 展现出强大的推理能力,并自主发展出了意想不到的强大推理行为,但它也面临一些问题。例如,DeepSeek-R1-Zero 存在可读性差和语言混合等挑战。为了使推理过程更具可读性并与开放社区共享,我们探索了 DeepSeek-R1,这是一种利用强化学习并结合对人类友好的冷启动数据的方法。

通俗解释

以前提升模型能力大多靠大量的监督数据,这篇论文则证明了用大规模强化学习,就算不用监督微调,也能提升模型推理能力,加点冷启动数据效果还会更好。接下来就介绍了三种方法,这里先讲 DeepSeek-R1-Zero。
强化学习在推理任务里本来就挺好用,但以前收集监督数据太费时间。这次用的 GRPO 算法能省点训练成本,它不用和策略模型一样大的价值网络,通过一组数据的得分来估算基线,然后优化策略模型。
训练的时候,奖励很重要。DeepSeek-R1-Zero 用的是基于规则的奖励系统,一方面看答案对不对,对了就给准确率奖励,像数学题按要求格式答对了、LeetCode 问题通过测试用例就给分;另一方面要求模型按规定格式写推理过程,符合格式就给格式奖励。因为神经奖励模型容易出问题,还费资源,所以没采用。
训练模板就是让模型按规定来,先写推理过程,再写答案,这样能看看模型自己在强化学习过程中是怎么发展的。
从结果来看,DeepSeek-R1-Zero 在 AIME 2024 测试里成绩越来越好,和 OpenAI-o1-0912 差不多,用多数投票法还能超过它。而且在训练过程中,它思考时间越来越长,自己就学会解决更难的问题,还能反思、找新方法,就像突然 “开窍” 了一样。不过它也有问题,写的东西不好懂,还会混着多种语言,所以就有了后面的 DeepSeek-R1 。

2.3 DeepSeek-R1:基于冷启动的强化学习

受 DeepSeek-R1-Zero 令人鼓舞的结果启发,自然产生了两个问题:1)通过引入少量高质量数据作为冷启动,能否进一步提高推理性能或加快收敛速度?2)如何训练一个既能够生成清晰、连贯的思维链(CoT),又具备强大通用能力的用户友好型模型?为了解决这些问题,我们设计了一个训练 DeepSeek-R1 的流程,该流程包含四个阶段,具体如下。

2.3.1 冷启动

与 DeepSeek-R1-Zero 不同,为避免从基础模型进行强化学习训练时早期冷启动阶段的不稳定性,对于 DeepSeek-R1,我们构建并收集了少量长思维链数据,对模型进行微调,以此作为初始的强化学习执行者。为收集此类数据,我们探索了多种方法:使用带有长思维链示例的少样本提示;直接促使模型生成带有反思和验证的详细答案;收集格式易读的 DeepSeek-R1-Zero 输出;以及通过人工标注进行后处理来优化结果。
在本研究中,我们收集了数千条冷启动数据,对 DeepSeek-V3-Base 进行微调,作为强化学习的起点。与 DeepSeek-R1-Zero 相比,冷启动数据具有以下优势:

  • 可读性:DeepSeek-R1-Zero 的一个关键局限在于其内容往往不便于阅读。生成的回答可能会混合多种语言,或者缺少用于突出答案的 Markdown 格式,不便于用户查看。相比之下,在为 DeepSeek-R1 创建冷启动数据时,我们设计了一种易读的模式,在每个回答的末尾添加总结,并过滤掉对读者不友好的回答。这里,我们将输出格式定义为 | 特殊标记 |<推理过程>| 特殊标记 |< 总结 >,其中推理过程是针对查询的思维链,总结用于概括推理结果。
  • 潜力:通过结合人类先验知识精心设计冷启动数据的模式,我们发现其性能优于 DeepSeek-R1-Zero。我们认为迭代训练对于推理模型而言是一种更好的方式。

2.3.2 面向推理的强化学习

在利用冷启动数据对 DeepSeek-V3-Base 进行微调后,我们采用与 DeepSeek-R1-Zero 相同的大规模强化学习训练过程。这个阶段专注于提升模型的推理能力,特别是在编码、数学、科学和逻辑推理等推理密集型任务中,这些任务通常具有明确的问题和清晰的解决方案。在训练过程中,我们发现思维链经常出现语言混合的情况,尤其是当强化学习提示涉及多种语言时。为缓解语言混合问题,我们在强化学习训练过程中引入了语言一致性奖励,该奖励通过计算思维链中目标语言词汇的比例来衡量。尽管消融实验表明,这种调整会导致模型性能略有下降,但该奖励符合人类偏好,使生成的内容更具可读性。最后,我们将推理任务的准确率与语言一致性奖励直接相加,形成最终的奖励。然后,对微调后的模型进行强化学习训练,直至其在推理任务上达到收敛。

2.3.3 拒绝采样与监督微调

当面向推理的强化学习收敛后,我们利用得到的检查点为下一轮收集监督微调(SFT)数据。与最初主要聚焦于推理的冷启动数据不同,这个阶段整合了来自其他领域的数据,以增强模型在写作、角色扮演和其他通用任务方面的能力。具体而言,我们按照以下方式生成数据并微调模型:

  • 推理数据:我们整理推理提示,并通过对上述强化学习训练得到的检查点进行拒绝采样,生成推理轨迹。在之前的阶段,我们仅纳入了可以使用基于规则的奖励进行评估的数据。然而在这个阶段,我们通过纳入更多数据来扩展数据集,其中部分数据使用生成式奖励模型,将真实答案和模型预测输入 DeepSeek-V3 进行判断。此外,由于模型输出有时较为混乱且难以阅读,我们过滤掉了包含混合语言的思维链、冗长的段落和代码块。对于每个提示,我们采样多个回答,仅保留正确的回答。总体而言,我们收集了约 60 万个与推理相关的训练样本。
  • 非推理数据:对于写作、事实性问答、自我认知和翻译等非推理数据,我们采用 DeepSeek-V3 的流程,并复用了 DeepSeek-V3 的部分监督微调数据集。对于某些非推理任务,在回答问题之前,我们通过提示促使 DeepSeek-V3 生成潜在的思维链。然而,对于诸如 “你好” 这类简单查询,我们则不提供思维链作为回应。最终,我们总共收集了约 20 万个与推理无关的训练样本。
    我们使用上述整理的约 80 万个样本的数据集,对 DeepSeek-V3-Base 进行了两个轮次的微调。

2.3.4 全场景强化学习

为了进一步使模型符合人类偏好,我们实施了第二个强化学习阶段,旨在提升模型的实用性和无害性,同时优化其推理能力。具体而言,我们结合奖励信号和多样化的提示分布来训练模型。对于推理数据,我们遵循 DeepSeek-R1-Zero 中概述的方法,利用基于规则的奖励来指导数学、代码和逻辑推理领域的学习过程。对于通用数据,我们借助奖励模型来捕捉复杂和微妙场景中的人类偏好。我们基于 DeepSeek-V3 的流程,采用类似的偏好对和训练提示分布。在评估实用性时,我们仅关注最终的总结,确保评估重点在于回答对用户的实用性和相关性,同时尽量减少对底层推理过程的干扰。在评估无害性时,我们评估模型的整个回答,包括推理过程和总结,以识别并减轻生成过程中可能出现的任何潜在风险、偏差或有害内容。最终,奖励信号和多样化数据分布的整合使我们能够训练出一个在推理方面表现出色,同时注重实用性和无害性的模型。

通俗解释

DeepSeek-R1-Zero 表现不错,但是大家还想让模型更好,就有了两个新问题:用点高质量数据做冷启动,能不能让模型推理能力更强、训练更快?能不能训练出既会清晰推理,又有很多通用能力,对用户很友好的模型?所以就设计了 DeepSeek-R1 的训练流程,有四个阶段。
第一个阶段是冷启动。DeepSeek-R1-Zero 从基础模型直接训练,前期不太稳定。DeepSeek-R1 就先收集一些长思维链数据,微调模型。收集数据的方法有好几种,像用带长思维链的例子提示模型、让模型自己生成详细答案再优化等。冷启动数据有两个好处,一是更可读,以前模型回答的内容不好懂,现在设计了新格式,回答完还有总结;二是性能更好,结合了人的经验设计的数据,训练效果更好。
第二个阶段是面向推理的强化学习。用冷启动数据微调完模型后,就用和训练 DeepSeek-R1-Zero 一样的强化学习方法训练。这个阶段主要提升模型在一些推理任务上的能力。训练时发现思维链会混语言,就加了个语言一致性奖励,虽然对性能有点影响,但是生成的内容更符合人的习惯,更好懂。把准确率和这个奖励加起来作为最终奖励,一直训练到模型在推理任务上表现稳定。
第三个阶段是拒绝采样与监督微调。前面强化学习训练稳定后,就用得到的模型收集新数据来微调。这次的数据不只是推理的,还有写作、问答这些其他领域的数据。推理数据通过拒绝采样得到,还扩展了数据集,去掉不好的内容;非推理数据用 DeepSeek-V3 的流程收集,简单问题就不用思维链回答。最后用这些收集到的 80 万个样本的数据,微调模型两轮。
最后一个阶段是全场景强化学习。为了让模型更符合人的喜好,又进行了一次强化学习训练。对推理数据和以前一样用基于规则的奖励训练;对通用数据,用奖励模型来符合人的偏好。评估的时候,实用性只看总结有没有用、相不相关,无害性则检查整个回答有没有问题。这样训练出来的模型,推理厉害,还好用、安全。

2.4 知识蒸馏:赋予小模型推理能力

为了使更高效的小模型也具备像 DeepSeek-R1 那样的推理能力,我们使用为 DeepSeek-R1 整理的 80 万个样本,直接对 Qwen(Qwen, 2024b)和 Llama(AI@Meta, 2024)等开源模型进行微调,具体细节见 2.3.3 节。我们的研究结果表明,这种简单的知识蒸馏方法能够显著提升小模型的推理能力。这里使用的基础模型包括 Qwen2.5-Math-1.5B、Qwen2.5-Math-7B、Qwen2.5-14B、Qwen2.5-32B、Llama-3.1-8B 和 Llama-3.3-70B-Instruct。我们选择 Llama-3.3,是因为其推理能力略优于 Llama-3.1。
对于蒸馏后的模型,我们仅进行监督微调,不包含强化学习阶段,尽管加入强化学习可以大幅提升模型性能。我们在此的主要目的是展示知识蒸馏技术的有效性,将强化学习阶段的探索留给更广泛的研究社区。

通俗解释

团队想让小模型也能像 DeepSeek-R1 一样会推理,就用 DeepSeek-R1 整理的 80 万个样本去微调 Qwen、Llama 这些开源模型。结果发现,这样简单的操作就能让小模型推理能力变强。用的基础模型有不同参数规模的,像 15 亿、70 亿参数的等,选 Llama-3.3 是因为它推理能力相对好一点。
蒸馏后的小模型只做了监督微调,没做强化学习,虽然做强化学习能让模型性能更好,但团队这次主要是想看看蒸馏方法好不好用,强化学习就留给其他研究人员去探索了。

3. 实验

3.1 DeepSeek-R1 评估

基准测试(指标)Claude-3.5-Sonnet-1022GPT-4o-0513DeepSeek V3OpenAI o1-miniOpenAI o1-1217DeepSeek R1
架构混合专家(MoE)混合专家(MoE)
激活参数数量370 亿370 亿
参数总数6710 亿6710 亿
英语MMLU(单次准确率)88.387.288.585.291.890.8
MMLU-Redux(精确匹配率)88.988.089.186.792.9
MMLU-Pro(精确匹配率)78.072.675.980.384.0
DROP(3 次提示 F1 值)88.383.791.683.990.292.2
IF-Eval(严格提示)86.584.386.184.883.3
GPQA Diamond(单次准确率)65.049.959.160.075.771.5
SimpleQA(正确率)28.438.224.97.047.030.1
FRAMES(准确率)72.580.573.376.982.5
AlpacaEval2.0(长度控制胜率)52.051.170.057.887.6
ArenaHard(GPT-4-1106 评判)85.280.485.592.092.3
代码LiveCodeBench(思维链单次准确率)38.932.936.253.863.465.9
Codeforces(百分比排名)20.323.658.793.496.696.3
Codeforces(评级)7177591134182020612029
SWE Verified(问题解决率)50.838.842.041.648.949.2
Aider-Polyglot(准确率)45.316.049.632.961.753.3
数学AIME 2024(单次准确率)16.09.339.263.679.279.8
MATH-500(单次准确率)78.374.690.290.096.497.3
CNMO 2024(单次准确率)13.110.843.267.678.8
中文CLUEWSC(精确匹配率)85.487.990.989.992.8
C-Eval(精确匹配率)76.776.086.568.991.8
C-SimpleQA(正确率)55.458.768.040.363.7

表 4 DeepSeek-R1 与其他代表性模型的比较
在 MMLU、MMLU-Pro 和 GPQA Diamond 等面向教育的知识基准测试中,DeepSeek-R1 相较于 DeepSeek-V3 展现出更优的性能。这种提升主要归因于在 STEM 相关问题上准确率的提高,这得益于大规模强化学习。此外,DeepSeek-R1 在 FRAMES(一个依赖长上下文的问答任务)上表现出色,展示了其强大的文档分析能力。这凸显了推理模型在人工智能驱动的搜索和数据分析任务中的潜力。在事实性基准测试 SimpleQA 上,DeepSeek-R1 的表现优于 DeepSeek-V3,证明了它处理基于事实的查询的能力。在该基准测试中,OpenAI-o1 优于 GPT-4o,DeepSeek-R1 也呈现出类似的超越趋势。不过,DeepSeek-R1 在中文 SimpleQA 基准测试上的表现比 DeepSeek-V3 差,这主要是因为在经过安全性强化学习后,它倾向于拒绝回答某些查询。如果不进行安全性强化学习,DeepSeek-R1 在该测试上的准确率能超过 70%。
DeepSeek-R1 在 IF-Eval(一个用于评估模型遵循格式指令能力的基准测试)上也取得了令人瞩目的成绩。这些改进可归因于在监督微调(SFT)和强化学习训练的最后阶段纳入了指令遵循数据。此外,在 AlpacaEval2.0 和 ArenaHard 上,DeepSeek-R1 表现卓越,这表明它在写作任务和开放域问答方面具有优势。它大幅超越 DeepSeek-V3 的表现,突出了大规模强化学习的泛化优势,不仅提升了推理能力,还改善了模型在不同领域的性能。而且,DeepSeek-R1 生成的总结长度简洁,在 ArenaHard 上平均为 689 个词元,在 AlpacaEval 2.0 上平均为 2218 个字符。这表明 DeepSeek-R1 在基于 GPT 的评估中避免了引入长度偏差,进一步巩固了其在多个任务上的稳健性。
在数学任务上,DeepSeek-R1 的表现与 OpenAI-o1-1217 相当,大幅超越其他模型。在编码算法任务(如 LiveCodeBench 和 Codeforces)中也呈现出类似趋势,以推理为核心的模型在这些基准测试中占据主导地位。在面向工程的编码任务上,OpenAI-o1-1217 在 Aider 测试中表现优于 DeepSeek-R1,但在 SWE Verified 测试中二者性能相当。我们认为,随着相关强化学习训练数据量的增加,DeepSeek-R1 的工程性能将在后续版本中得到提升。

通俗解释

研究人员对 DeepSeek-R1 进行了各种测试,和好多厉害的模型对比。从表格里能看到,在知识类测试里,像 MMLU 这些,DeepSeek-R1 比 DeepSeek-V3 考得好,特别是在 STEM 相关的问题上,因为大规模强化学习让它更会做这类题。在处理长文章问答的 FRAMES 测试里,它也表现不错,说明分析文档能力强。在 SimpleQA 这个测试里,它比 DeepSeek-V3 厉害,能更好地回答事实类问题,和 OpenAI-o1 比 GPT-4o 表现好是一个道理。不过在中文 SimpleQA 测试里,它比 DeepSeek-V3 差,是因为做了安全性强化学习后,有些问题它不愿意回答,如果没这个限制,准确率能更高。
在测试模型按格式回答问题能力的 IF-Eval 测试里,DeepSeek-R1 成绩很好,这是因为训练后期加了相关的数据。在写作和开放域问答的测试(AlpacaEval2.0 和 ArenaHard)里,它表现也很棒,比 DeepSeek-V3 强很多,说明大规模强化学习让它在好多领域都更厉害。而且它生成的总结不长,在评估的时候不会因为长度问题影响结果,很稳定。
在数学任务和编码算法任务测试里,DeepSeek-R1 和 OpenAI-o1-1217 水平差不多,比其他模型好很多。在工程编码任务上,OpenAI-o1-1217 在 Aider 测试里比它好一点,但在 SWE Verified 测试里二者差不多。以后随着训练数据变多,DeepSeek-R1 在工程方面的能力还能提升。

3.2 蒸馏模型评估

模型AIME 2024MATH-500 单次准确率GPQA Diamond 单次准确率LiveCodeBench 单次准确率CodeForces 评级
单次准确率64 次采样多数投票准确率
GPT-4o-05139.313.474.649.932.9759
Claude-3.5-Sonnet-102216.026.778.365.038.9717
OpenAI-o1-mini63.680.090.060.053.81820
QwQ-32B-Preview50.060.090.654.541.91316
DeepSeek-R1-Distill-Qwen-1.5B28.952.783.933.816.9954
DeepSeek-R1-Distill-Qwen-7B55.583.392.849.137.61189
DeepSeek-R1-Distill-Qwen-14B69.780.093.959.153.11481
DeepSeek-R1-Distill-Qwen-32B72.683.394.362.157.21691
DeepSeek-R1-Distill-Llama-8B50.480.089.149.039.61205
DeepSeek-R1-Distill-Llama-70B70.086.794.565.257.51633

表 5 DeepSeek-R1 蒸馏模型与其他可比模型在推理相关基准测试中的比较
如表 5 所示,仅仅通过蒸馏 DeepSeek-R1 的输出,高效的 DeepSeek-R1-7B(即 DeepSeek-R1-Distill-Qwen-7B,以下简称类似)就能在所有方面超越像 GPT-4o-0513 这样的非推理模型。DeepSeek-R1-14B 在所有评估指标上都超过了 QwQ-32B-Preview,而 DeepSeek-R1-32B 和 DeepSeek-R1-70B 在大多数基准测试中显著超越 o1-mini。这些结果展示了知识蒸馏的强大潜力。此外,我们发现对这些蒸馏模型应用强化学习会带来进一步的显著提升。我们认为这值得进一步探索,因此在此仅展示简单监督微调蒸馏模型的结果。

通俗解释

研究人员还测试了从 DeepSeek-R1 蒸馏出来的小模型。从表格数据能看出,这些小模型表现很不错。就拿 DeepSeek-R1-Distill-Qwen-7B 来说,它在各个测试里都比 GPT-4o-0513 考得好。DeepSeek-R1-14B 比 QwQ-32B-Preview 厉害,DeepSeek-R1-32B 和 DeepSeek-R1-70B 在大部分测试里比 o1-mini 还好。这说明把大模型的能力蒸馏到小模型里这个方法很有用。而且如果再给这些蒸馏后的小模型做强化学习,它们还能变得更厉害,不过这次研究人员没展示这部分结果,以后可以继续研究。

4. 讨论

4.1 知识蒸馏与强化学习

在 3.2 节中可以看到,通过对 DeepSeek-R1 进行知识蒸馏,小模型能取得令人瞩目的成绩。然而,仍有一个问题:模型不经过知识蒸馏,通过本文中讨论的大规模强化学习训练,能否达到类似的性能?
为回答这个问题,我们使用数学、代码和 STEM 数据,对 Qwen-32B-Base 进行了超过 10,000 步的大规模强化学习训练,得到了 DeepSeek-R1-Zero-Qwen-32B。实验结果如表 6 所示,经过大规模强化学习训练的 320 亿参数基础模型,其性能与 QwQ-32B-Preview 相当。然而,从 DeepSeek-R1 蒸馏得到的 DeepSeek-R1-Distill-Qwen-32B,在所有基准测试中的表现都显著优于 DeepSeek-R1-Zero-Qwen-32B。
因此,我们可以得出两个结论:第一,将更强的模型知识蒸馏到较小模型中能产生优异的效果,而较小模型依靠本文提到的大规模强化学习则需要巨大的计算资源,甚至可能无法达到知识蒸馏的性能。第二,虽然知识蒸馏策略既经济又有效,但要突破智能的边界,可能仍需要更强大的基础模型和大规模强化学习。

模型AIME 2024MATH-500 单次准确率GPQA Diamond 单次准确率LiveCodeBench 单次准确率
单次准确率64 次采样多数投票准确率
QwQ-32B-Preview50.060.090.654.541.9
DeepSeek-R1-Zero-Qwen-32B47.060.091.655.040.2
DeepSeek-R1-Distill-Qwen-32B72.683.394.362.157.2

表 6 知识蒸馏模型与强化学习模型在推理相关基准测试中的比较

通俗解释

前面看到知识蒸馏让小模型成绩很好,大家就想知道,小模型不蒸馏,直接用大规模强化学习训练,能不能有同样好的表现呢?于是研究人员就用 Qwen-32B-Base 这个模型,用数学、代码等数据进行大规模强化学习训练,训练了 10000 多步,得到了 DeepSeek-R1-Zero-Qwen-32B 这个模型。
对比发现,这个经过强化学习训练的模型,和 QwQ-32B-Preview 表现差不多。但是从 DeepSeek-R1 蒸馏出来的 DeepSeek-R1-Distill-Qwen-32B,在各项测试里都比 DeepSeek-R1-Zero-Qwen-32B 好很多。
这就说明,把大模型的知识 “传” 给小模型的知识蒸馏方法效果很好,小模型要是想用大规模强化学习达到同样效果,不仅特别费计算资源,可能还做不到。虽然知识蒸馏又省钱又好用,但想要让模型更聪明,可能还是得靠更厉害的大模型和大规模强化学习。

4.2 失败尝试

在开发 DeepSeek-R1 的早期阶段,我们也经历了失败和挫折。在此分享这些失败经验以供参考,但这并不意味着这些方法无法用于开发有效的推理模型。

  • 过程奖励模型(PRM):过程奖励模型是一种引导模型寻找更好推理任务解决方法的合理途径(Lightman 等人,2023;Uesato 等人,2022;Wang 等人,2023)。然而在实际应用中,PRM 存在三个主要局限性,可能会阻碍其最终成功。第一,在一般推理中,明确定义精细的推理步骤具有挑战性。第二,判断当前中间步骤是否正确是一项艰巨的任务。使用模型进行自动标注可能无法得到令人满意的结果,而人工标注不利于大规模应用。第三,一旦引入基于模型的 PRM,不可避免地会导致奖励作弊(Gao 等人,2022),重新训练奖励模型需要额外的训练资源,并且会使整个训练流程变得复杂。总之,虽然 PRM 在对模型生成的前 N 个响应进行重新排序或辅助引导搜索方面(Snell 等人,2024)表现出良好的能力,但在我们的实验中,与大规模强化学习过程中引入的额外计算开销相比,其优势有限。
  • 蒙特卡洛树搜索(MCTS):受 AlphaGo(Silver 等人,2017b)和 AlphaZero(Silver 等人,2017a)的启发,我们探索使用蒙特卡洛树搜索(MCTS)来提高测试时计算的可扩展性。这种方法将答案分解为较小的部分,使模型能够系统地探索解决方案空间。为实现这一点,我们促使模型生成多个与搜索所需的特定推理步骤相对应的标签。在训练过程中,我们首先使用收集到的提示,通过由预训练价值模型引导的 MCTS 来寻找答案。随后,我们使用得到的问答对来训练策略模型和价值模型,迭代优化这个过程。

然而,在扩大训练规模时,这种方法遇到了几个挑战。第一,与国际象棋不同,在国际象棋中搜索空间相对明确,而令牌生成的搜索空间呈指数级增大。为解决这个问题,我们为每个节点设置了最大扩展限制,但这可能导致模型陷入局部最优解。第二,价值模型直接影响生成的质量,因为它引导搜索过程的每一步。训练一个精细的价值模型本身就很困难,这使得模型难以通过迭代得到改进。虽然 AlphaGo 的核心成功在于训练价值模型以逐步提升性能,但由于令牌生成的复杂性,在我们的设置中难以复制这一原理。
总之,虽然 MCTS 与预训练价值模型结合可以在推理时提高性能,但通过自我搜索迭代提升模型性能仍然是一个巨大的挑战。

通俗解释

在研究 DeepSeek-R1 的时候,团队也试过一些方法但没成功。
有一种叫过程奖励模型(PRM)的方法,本来想着用它能引导模型更好地推理。但实际用的时候发现有问题:一是在推理过程中,很难把每一步都规定得很清楚;二是判断中间步骤对不对很难,用模型自动标注不准,人工标注又没办法大规模做;三是用了这个模型容易出现奖励作弊的情况,重新训练奖励模型又费资源又让训练过程变复杂。虽然它在给模型的回答排序、引导搜索这些方面有点用,但总体来说,在大规模强化学习里,它带来的麻烦比好处多。
还有蒙特卡洛树搜索(MCTS)方法,是从 AlphaGo 这些成功的例子里得到的启发,想用它让模型在测试的时候计算能力更强。这个方法就是把答案拆成小部分,让模型慢慢找解决方案,训练的时候用预训练的价值模型帮忙找答案,再用这些答案训练模型。
但是扩大训练规模的时候就不行了。一方面,和国际象棋比起来,模型生成内容的搜索范围大太多了,限制搜索节点又容易让模型卡在局部最优解里;另一方面,价值模型对生成结果影响很大,但是很难训练好,所以模型很难通过不断训练变得更好。虽然 MCTS 和预训练价值模型一起用,在推理的时候有点用,但想靠它让模型一直进步太难了。

5. 结论、局限性与未来工作

在本研究中,我们分享了通过强化学习提升模型推理能力的历程。DeepSeek-R1-Zero 代表了一种不依赖冷启动数据的纯强化学习方法,在各种任务中都取得了优异的性能。DeepSeek-R1 则更强大,它利用冷启动数据和迭代强化学习微调。最终,DeepSeek-R1 在一系列任务上的表现与 OpenAI-o1-1217 相当。
我们进一步探索了将推理能力蒸馏到小型稠密模型中。以 DeepSeek-R1 为教师模型生成 80 万个训练样本,对几个小型稠密模型进行微调。结果很有前景:DeepSeek-R1-Distill-Qwen-1.5B 在数学基准测试中表现超过 GPT-4o 和 Claude-3.5-Sonnet,在 AIME 测试中得分为 28.9%,在 MATH 测试中得分为 83.9%。其他稠密模型也取得了令人瞩目的成绩,显著超越了基于相同基础检查点的其他指令微调模型。
未来,我们计划在以下几个方向对 DeepSeek-R1 进行研究:

  • 通用能力:目前,DeepSeek-R1 在函数调用、多轮对话、复杂角色扮演和 JSON 输出等任务上的能力不如 DeepSeek-V3。未来,我们计划探索如何利用长思维链来提升这些领域的任务表现。
  • 语言混合:DeepSeek-R1 目前针对中文和英文进行了优化,在处理其他语言的查询时可能会出现语言混合问题。例如,即使查询使用的是非中文或英文的其他语言,DeepSeek-R1 也可能会用英文进行推理和回答。我们旨在在未来的更新中解决这一局限性。
  • 提示工程:在评估 DeepSeek-R1 时,我们发现它对提示很敏感。少样本提示始终会降低其性能。因此,我们建议用户直接描述问题,并使用零样本设置指定输出格式,以获得最佳结果。
  • 软件工程任务:由于评估时间长,影响了强化学习过程的效率,大规模强化学习在软件工程任务中尚未得到广泛应用。因此,DeepSeek-R1 在软件工程基准测试上相比 DeepSeek-V3 并没有显著改进。未来版本将通过对软件工程数据实施拒绝采样,或在强化学习过程中纳入异步评估来提高效率,从而解决这一问题。

通俗解释

这篇研究主要是讲怎么用强化学习让模型更会推理。DeepSeek-R1-Zero 是直接用强化学习训练的,不用冷启动数据,在很多任务里表现都不错。DeepSeek-R1 更厉害,用了冷启动数据,还反复用强化学习微调,最后和 OpenAI 很厉害的 o1-1217 模型表现差不多。
团队还把 DeepSeek-R1 的推理能力教给了小模型,用它生成的 80 万个样本去训练小模型,结果小模型成绩很好,比一些以前的模型考得都好。
不过,DeepSeek-R1 也有不足的地方,以后团队打算从这几个方面继续研究改进。在通用能力方面,它在函数调用这些任务上不如 DeepSeek-V3,以后看看能不能用长思维链让它在这些任务里表现更好。在语言方面,它对中文和英文优化得比较好,处理其他语言容易混,之后要解决这个问题。在提示方面,它对提示很敏感,少样本提示会让它发挥不好,所以建议用户直接描述问题、用零样本设置。在软件工程任务方面,因为评估时间长,大规模强化学习用得少,它在这方面进步不大,以后会用拒绝采样、异步评估这些方法来提高效率。


作者 east
面试 2月 7,2025

从几千份大数据面经吐血整理:大厂大数据高频八股文面试题

这是从大厂,特别是互联网大厂几百份面试题中挑选各个知识点高频,又有一定难度的面试题,包含了大量每次面试经常问的面试题,吃透这份面试题,可以覆盖大部分八股文面试题。

请详细说一说 Java 中的四种引用:强引用、软引用、弱引用、虚引用

java 类加载机制

Java 的抽象类和接口有什么区别和联系

介绍一下 Java 的反射

GC 算法有哪些

请说明进程与线程的区别

请说明栈和堆的区别,以及它们具体存放的东西

红黑树和二叉搜索树,二叉树之间的区别

hashmap 的底层原理

Redis 有哪些常用的数据结构和使用场景

Redis 数据结构的底层结构

描述一下链表和数组之间的区别

常见的排序算法,时间复杂度,空间复杂度

红黑树和二叉搜索树,二叉树之间的区别

Java 线程创建的几种方式

Hadoop 的序列化和 Java 的序列化的区别

Hadoop 的 Combiner 的作用,什么情况下不能用 Combiner

hadoop ha 当一个 namenode 挂掉。会有数据丢失吗。如果有,有什么解决方法

介绍下 HDFS,说下 HDFS 优缺点,以及使用场景

简单介绍一下 HDFS 架构及其读写流程

HDFS 的常见数据格式,列式存储格式和行存储格式异同点,列式存储优点有哪些

Hadoop的checkpoint流程

Hadoop的默认块大小是多少?为什么要设置这么大?

Hadoop常见的压缩算法?

Hadoop作业提交到YARN的流程?

HDFS的块默认大小,64M和128M是在哪个版本更换的?怎么修改默认块大小?

MapReduce为什么一定要有环型缓冲区

MapReduce数据倾斜产生的原因及其解决方案

MapReduce Shuffle为什么要将数据写入环形缓冲区

YARN的设计思路是什么

说下为什么要使用Hive?Hive的优缺点?Hive的作用是什么?

Hive内部表和外部表的区别?

Hive的三种自定义函数是什么?实现步骤与流程?它们之间的区别?作用是什么?

Hive的cluster by、sort by、distribute by、order by区别?

Hive分区和分桶的区别及如何优化

Hive 的 union 和 union all 的区别

Hive 的 join 操作原理,left join、right join、inner join、outer join 的异同

Hive 的开窗函数有哪些

Hive row_number,rank,dense_rank 的区别

迪卡尔积会产生什么问题?

迪卡尔积会产生数据倾斜吗?

介绍下Flume采集数据的原理?底层实现?

Hadoop的Checkpoint流程?

Kafka怎么保证数据不丢失,不重复?

Kafka的offset存在哪?

Flink 的四大基石都有哪些?

Kafka 怎么保证消费顺序正确

watermark 的作用是啥?如何保证数据不丢失?

请介绍一下 Kafka 选举流程。

请介绍 Kafka 的功能和高吞吐的原因。

HBase 中的二级索引

在删除 HBase 中的一个数据的时候,它什么时候真正的进行删除呢?当你进行删除操作,它是立马就把数据删除掉了吗?

列式数据库的适用场景和优势?列式存储的特点?

HBase 为什么随机查询很快?

HBase RowKey 设计原则

HBase 的热点问题

Spark 和 Hadoop 区别

Spark 的工作原理是什么?

Spark 的工作流程是什么?

Spark on standalone 模型、YARN 架构模型

什么情况下会产生Spark Shuffle?

Spark数据倾斜问题,如何定位,解决方案

Spark join在什么情况下会变成窄依赖?

Spark的batchsize,怎么解决小文件合并问题?

Spark参数(性能)调优

介绍一下Spark怎么基于内存计算的

reduceByKey和groupByKey的区别和作用?

使用reduceByKey出现数据倾斜怎么办?

Spark为什么比Hadoop速度快?

Spark 的 RDD 是什么?具体解释下弹性是怎么实现的?

Spark Streaming的双流join的过程,怎么做的?

Spark SQL读取文件,内存不够使用,如何处理?

Sparkstreaming和Flink的区别

Checkpoint产生了很多快照,怎么进行处理呢?

SparkStreaming和StructuredStreaming的区别

Flink架构

Flink的四大基石都有哪些?

watermark的作用是啥?如何保证数据不丢失?

Flink的窗口了解哪些,都有什么区别,有哪几种?如何定义?

Flink的Checkpoint底层如何实现的?savepoint和checkpoint有什么区别?

Flink的ExactlyOnce语义怎么保证?

Flink和Spark的区别?什么情况下使用Flink?有什么优点?

Flink backPressure反压机制,指标监控你是怎么做的?如何处理背(反)压?

Flink解决数据延迟的问题

数据仓库分层(层级划分),每层做什么?分层的好处?

星型模型和雪花模型的区别?应用场景?优劣对比

增量表、全量表和拉链表

数据仓库怎么设计表,怎么建模

增量表和全量表优缺点?

拉链表概念?缓慢变化维概念?

数据库事务的隔离级别?解决了什么问题?默认事务隔离级别?

为什么要有三大范式,建数据库时一定要遵循吗?

数据库第一范式、第二范式和第三范式的作用

说说事务的 ACID 特性

mysql 索引失效的原因?

mysql 索引的数据结构为什么使用 B + 树?

SQL 调优怎么做的?

说说三次握手和四次挥手,为什么不能两次握手和三次挥手

TDP 和 UDP 的区别

HTTP 有哪些状态码?

关注公众号【大模型全栈程序员】回复“大数据八股文”获取详细参考答案

作者 east
doris 2月 7,2025

Doris更新某一列完整教程

通过临时表来更新
例如有下面的表结构

ods_t_iot (
pid varchar(255) NOT NULL,
ptime bigint NOT NULL,
pvalue decimal(38,9) NOT NULL,
ds varchar(30) NULL
) ENGINE=OLAP
UNIQUE KEY(pid, ptime, pvalue, ds)
需要把ds这一列更新为2025-02-07

  1. 创建一个新表并导入数据
    由于不能直接使用 UPDATE,一种常见的方法是创建一个新表,然后通过批量插入的方式将数据导入,并修改 ds 列的值。下面是详细步骤:

步骤 1: 创建一个新表
首先,我们需要创建一个新的表,结构与原表一致,唯一的区别是我们会把 ds 列的默认值设置为 ‘2025-02-07’,并确保与原表的列顺序、类型保持一致。

CREATE TABLE ods_t_iot_new like ods_t_iot;
步骤 2: 使用 INSERT INTO SELECT 语句从原表导入数据
接下来,我们将原表的数据导入到新表中,同时确保 ds 列的值设置为 ‘2025-02-07’。可以使用以下 SQL:

INSERT INTO ods_t_iot_new (pid, ptime, pvalue, ds) SELECT pid, ptime, pvalue, IFNULL(ds, ‘2025-02-07’) AS ds FROM ods_t_iot;
在这里,IFNULL(ds, ‘2025-02-07’) 会将原表中 ds 列为 NULL 的数据替换为 ‘2025-02-07’。

步骤 3: 删除原表并重命名新表
导入数据完成后,我们可以删除原表并将新表重命名为原表名。这样,所有数据都已经更新,ds 列也被设置为 ‘2025-02-07’。

DROP TABLE ods_t_iot;

ALTER TABLE ods_t_iot_new RENAME ods_t_iot;

作者 east
大数据开发, 面试 2月 3,2025

二本生的破局:从迷茫到上岸知名互联网大数据岗,我是这样做的

​

大学时的迷茫,直到如今回想起来,依然觉得有点“懵懂”。我本科就读于一所普通的二本院校,专业是计算机相关。对于未来的职业方向,我一直没有一个明确的目标。身边的师兄师姐们给出了很多建议。Java开发的岗位早已是“烂大街”的状态,几乎人人都能进入,但也难以脱颖而出。C++的就业方向则相对小众,竞争相对较小,但是行业需求并不大。大数据开发虽然岗位不多,但薪资可观,且未来的增长潜力巨大——这让我决心全力投入到大数据的学习和实践中。

刷题:编程能力的磨砺之路

提升编程能力,绝对是每个技术开发者必须经历的过程。对于我来说,刷题成为了提升编程能力的“必经之路”。无论是面试中的笔试,还是实际的编码工作,扎实的编程能力总是能起到决定性的作用。通过LeetCode,我挑战了200+道题。最初,很多题目都让我头大,甚至看半天也没有任何思路,感觉几乎要放弃。但我始终坚持每一道题,仔细分析每种解题方法,总结出最优的解法。

解决不了的问题,我会去寻找答案,去研究大神们是如何分析并解决问题的,理解他们的思路之后,我自己再亲手实现一遍。这个过程不仅是对算法的磨练,更是对思维方式的训练。

除了LeetCode,我还选择了《剑指 Offer》这本书。这本书的题目紧扣面试核心,尤其适合那些准备大数据或Java开发岗位的应聘者。书中不仅有面试中常见的题目,还特别注重对思路的培养。虽然有些题目一开始并不容易通过,但在面试现场,面试官更看重的是你的思考过程和解决方案,而不是你是否一次性通过了所有测试用例。

特别是大厂高频手撕面试题,更是要准备熟悉:

从上千份大厂面经呕心沥血整理:大厂高频手撕面试题(数据结构和算法篇 ,Java实现亲试可跑)


数据库:SQL技能是大数据开发的根基

SQL是大数据开发者必须掌握的一项技能,尤其是在与数据库打交道的过程中,它是操作数据的核心工具。对我来说,SQL不仅仅是日常工作中处理数据的工具,它更是提高自己业务理解和解决问题的“钥匙”。

我在学习SQL时,花了大量时间深入理解了它的高级用法,特别是窗口函数、子查询等复杂查询方法。为了更加深入地理解SQL的应用,我做了大量的练习,包括针对具体业务场景的SQL题目,如留存分析、在线时长统计、漏斗分析、连续登录天数计算等。这些练习不仅提升了我的SQL能力,还帮助我理解了如何通过SQL解决实际工作中的问题。面试中,我几乎没有遇到过SQL方面的难题,面试官通常会对我解决问题的方式给予高度评价。

大厂面试手撕SQL面试题(Hive实现:样例数据、详细思路、亲试可行的运行截图)_hive sql经典面试题-CSDN博客


理论学习:扎实的知识体系是进阶的基石

尽管编程和SQL能力非常重要,但大数据开发所涉及的理论知识同样不容忽视。这些理论知识不仅能帮助你解决实际问题,更能让你站在更高的角度去思考和分析问题。为了在大数据开发领域立足,我专注于构建一个完整的知识体系,包括数据仓库理论、操作系统原理、计算机网络、Java基础等方面的知识。

数据仓库与分层理论:
为了深入了解大数据在企业中的实际应用,我精读了《维度建模工具箱》和《大数据之路:阿里巴巴大数据实践》这两本书。《维度建模工具箱》详细介绍了如何进行数据建模,特别是维度建模,这对构建灵活且高效的数据仓库架构至关重要。而《大数据之路:阿里巴巴大数据实践》则通过阿里巴巴的真实案例,帮助我理解了大数据的应用场景以及发展趋势。

操作系统与计算机网络:
作为计算机专业的基础课程,操作系统和计算机网络对于大数据开发的深入理解同样重要。我花了两周时间复习了这些基础课程,结合项目中的实际应用加深理解。例如,在操作系统的进程管理与内存管理的复习过程中,我结合了大数据处理中的并发控制、资源分配等内容;在学习计算机网络的TCP/IP协议时,我思考这些知识如何在Hadoop等大数据组件的网络通信中得以应用。

Java编程与多线程:
Java是大数据开发中最常用的编程语言之一,我花了一个月时间复习Java的基础、源码、多线程以及JVM的相关内容。通过深入分析Java的类库和源码,我理解了Java的底层实现。多线程和JVM的内容相对复杂,但我通过阅读经典书籍并结合实际案例进行了深入学习,并最终在面试中得心应手。

MySQL优化:
MySQL作为常用的关系型数据库,优化MySQL的性能也是大数据开发者的必修课。我读了两遍《高性能MySQL》,这本书涵盖了MySQL的性能优化、索引优化、存储引擎等核心知识。在实际项目中,通过对MySQL的优化,我提升了数据存取效率,减少了响应时间,确保了数据库在大数据场景下的高效运行。


大数据组件:从基础到深入,掌握核心技术

在学习了编程语言和理论知识之后,我将重点放在了大数据开发的核心技术上。对于一个大数据开发者来说,掌握相关的大数据组件和框架是进入行业的必要条件。

Hadoop:
Hadoop作为大数据处理的基础框架,我通过反复研读《Hadoop权威指南》,深入了解了Hadoop的架构、HDFS(分布式文件系统)、MapReduce(分布式计算框架)和YARN(资源管理器)。我不仅仅停留在理论层面,还通过搭建Hadoop集群,进行了一些实际操作,积累了大量的实践经验。

Hive:
Hive是基于Hadoop的SQL查询工具,我不仅学习了HiveQL的基本语法,还深入研究了Hive的性能调优和配置优化。在项目中,我通过实践学会了如何使用Hive进行数据仓库建设和数据分析,同时优化了查询性能,提高了数据处理效率。

Spark与其他工具:
虽然Spark、Flink、Kafka等大数据工具的学习我并没有深入到实际项目中,但我确保了自己对这些工具的基本概念、应用场景和技术原理有足够的了解。对于每个工具的学习,我都花时间去了解它们的功能、优势以及如何在特定场景下应用。


精美简历:突出重点,简洁明了

简历是进入面试的第一步,而对于我来说,如何让简历“脱颖而出”是一项不容忽视的挑战。为了让面试官快速抓住我的核心竞争力,我在简历中只列出了自己真正掌握的技术,如Hadoop、Hive、Spark等。

在描述项目经验时,我尽量详细描述自己在项目中的职责、解决的关键问题和取得的成绩。例如,在数据仓库建设项目中,我详细阐述了自己负责的模块设计、遇到的难点以及如何克服这些问题;在报表开发中,我展示了如何优化查询流程、提高数据处理效率。通过这些真实的项目经验,我的简历更具说服力。


面试准备:知己知彼,百战不殆

除了理论学习与技能提升,面试技巧的磨练同样不可忽视。我查阅了大量大数据开发岗位的面试经验和面试题,整理成文档,并进行逐一分析。通过这些面经,我不仅了解了面试官最关心的技术点,还学习了如何在面试中展示自己的优势。

面试过程中,我始终保持自信,尽量展示出我的技术深度与广度。同时,我也通过模拟面试,提升自己的表达能力和应变能力。

这里汇集了上百家中大厂的大数据面经:

大数据最全面试题-Offer直通车


面试过程:从等待到收获

投递简历后,我并没有期待快速的反馈。前期的简历投递并没有让我立刻迎来面试机会,但我没有气馁。在不断优化简历、提升技术实力后,面试机会开始逐渐增多。经过几轮严格的笔试和面试,我最终成功拿到了某知名互联网企业的大数据开发岗位的Offer,薪资在同行中领先。

大数据大厂校招网申入口最全集合和2025年校园招聘时间线(持续更新)

这段求职历程不仅让我收获了职位,也让我深刻体会到,只有通过持续的学习和实践,才能在激烈的技术竞争中站稳脚跟。 ​

作者 east
Flink 1月 24,2025

解决flink报错:org.apache.flink.streaming.api.datastream.DataStreamSink[com.chuneng.saas.vo.IotData] cannot be applied to (com.chuneng.saas.dao.SinkToTDengine) iotStream.sinkTo(new SinkToTDengine)

在scala用下面的代码,

iotStream.sinkTo(new SinkToTDengine)

出现报错:

overloaded method value sinkTo with alternatives:
  (sink: org.apache.flink.api.connector.sink2.Sink[com.chuneng.saas.vo.IotData])org.apache.flink.streaming.api.datastream.DataStreamSink[com.chuneng.saas.vo.IotData] <and>
  (sink: org.apache.flink.api.connector.sink.Sink[com.chuneng.saas.vo.IotData, _, _, _])org.apache.flink.streaming.api.datastream.DataStreamSink[com.chuneng.saas.vo.IotData]
 cannot be applied to (com.chuneng.saas.dao.SinkToTDengine)
    iotStream.sinkTo(new SinkToTDengine)

遇到的错误是由于 sinkTo 方法期望的参数类型与提供的 SinkToTDengine 类型不匹配。具体来说,sinkTo 方法期望的是一个实现了 Sink 接口的类型,而您的 SinkToTDengine 类继承自 RichSinkFunction,这导致类型不兼容。

错误原因分析

这表明 sinkTo 方法期望的是 Sink[IotData] 或 Sink[IotData, _, _, _] 类型,而您传递的是 SinkToTDengine,它继承自 RichSinkFunction<IotData>,因此类型不匹配。

解决方案

要解决这个问题,您需要将 SinkToTDengine 转换为 Flink 支持的 Sink 类型。

使用 addSink 方法

Flink 提供了 addSink 方法,可以直接接受实现了 SinkFunction 的自定义 Sink。这是最直接和常用的方式。

修改后的代码示例:

iotStream
  .map(rd => {
    val iotData = new IotData()
    iotData.setPid(rd.getDeviceCode.replaceAll(".", "-"))
    iotData.setVal(rd.getCompensationMW.toString)

    // 将13位时间戳转换为%Y-%m-%d %H:%M:%S.%f格式,毫秒保留3位小数
    val timestamp = rd.getTime // 假设rd.getTime()返回的是13位时间戳(毫秒级)
    val instant = Instant.ofEpochMilli(timestamp)
    val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
      .withLocale(Locale.CHINA)
      .withZone(ZoneId.systemDefault())
    val formattedTime = formatter.format(instant)

    iotData.setTs(formattedTime)
    iotData
  })
  .print()
  .addSink(new SinkToTDengine()) // 使用 addSink 方法
作者 east
bug清单, Flink 1月 23,2025

解决flink 1.7通过Flink Doris Connector写入Caused by: java.lang.NullPointerException: Unknown checkpoint for org.apache.flink.streaming.api.connector.sink2.CommittableWithLineage

在flink 1.7项目,通过Flink Doris Connector,采用批处理读取Doris数据进行计算然后写入到doris的另外一个表。采用flink sql方式。

原来的代码进行脱敏后的代码如下:

EnvironmentSettings settings = EnvironmentSettings.newInstance().inBatchMode().build();
TableEnvironment tableEnvironment = TableEnvironment.create(settings);

// 数据源配置
String sourceDDL = "CREATE TABLE <SOURCE_TABLE_NAME>(" +
        "pid STRING," +
        "pvalue decimal(39,3)," +
        "ptime TIMESTAMP(3)," +
        "ds DATE" +
        ") WITH (" +
        "'connector' = 'doris'," +
        "'fenodes' = '<IP_ADDRESS>:<PORT>'," +
        "'table.identifier' = '<DATABASE_NAME>.<TABLE_NAME>'," +
        "'username' = '<USERNAME>'," +
        "'password' = '<PASSWORD>'" +
        ")";

tableEnvironment.executeSql(sourceDDL);
// 获取当前时间戳
String timestamp = String.valueOf(System.currentTimeMillis());

// 目标 Doris 表 DDL
String sinkDDL = "CREATE TABLE <TARGET_TABLE_NAME> (" +
        "station_sn STRING," +
        "pid_system_code STRING," +
        "`day` STRING," +
        "`value` STRING," +
        "created_at TIMESTAMP(3)," +
        "dt DATE" +
        ") WITH (" +
        "'connector' = 'doris'," +
        "'fenodes' = '<IP_ADDRESS>:<PORT>'," +
        "'table.identifier' = '<DATABASE_NAME>.<TABLE_NAME>'," +
        "'username' = '<USERNAME>'," +
        "'password' = '<PASSWORD>'," +
        "'sink.label-prefix' = '<LABEL_PREFIX>_" + timestamp + "'" +
        ")";

执行报错如下:

Exception in thread "main" java.util.concurrent.ExecutionException: org.apache.flink.table.api.TableException: Failed to wait job finish
	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at org.apache.flink.table.api.internal.TableResultImpl.awaitInternal(TableResultImpl.java:118)
	at org.apache.flink.table.api.internal.TableResultImpl.await(TableResultImpl.java:81)
	at com.chuneng.saas.doris.FlinkBatchSql.main(FlinkBatchSql.java:68)
Caused by: org.apache.flink.table.api.TableException: Failed to wait job finish
	at org.apache.flink.table.api.internal.InsertResultProvider.hasNext(InsertResultProvider.java:85)
	at org.apache.flink.table.api.internal.InsertResultProvider.isFirstRowReady(InsertResultProvider.java:71)
	at org.apache.flink.table.api.internal.TableResultImpl.lambda$awaitInternal$1(TableResultImpl.java:105)
	at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1626)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.concurrent.ExecutionException: org.apache.flink.runtime.client.JobExecutionException: Job execution failed.
	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
	at org.apache.flink.table.api.internal.InsertResultProvider.hasNext(InsertResultProvider.java:83)
	... 6 more
Caused by: org.apache.flink.runtime.client.JobExecutionException: Job execution failed.
	at org.apache.flink.runtime.jobmaster.JobResult.toJobExecutionResult(JobResult.java:144)
	at org.apache.flink.runtime.minicluster.MiniClusterJobClient.lambda$getJobExecutionResult$3(MiniClusterJobClient.java:141)
	at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:602)
	at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:577)
	at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
	at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
	at org.apache.flink.runtime.rpc.akka.AkkaInvocationHandler.lambda$invokeRpc$1(AkkaInvocationHandler.java:267)
	at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
	at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
	at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
	at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
	at org.apache.flink.util.concurrent.FutureUtils.doForward(FutureUtils.java:1300)
	at org.apache.flink.runtime.concurrent.akka.ClassLoadingUtils.lambda$null$1(ClassLoadingUtils.java:93)
	at org.apache.flink.runtime.concurrent.akka.ClassLoadingUtils.runWithContextClassLoader(ClassLoadingUtils.java:68)
	at org.apache.flink.runtime.concurrent.akka.ClassLoadingUtils.lambda$guardCompletionWithContextClassLoader$2(ClassLoadingUtils.java:92)
	at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
	at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
	at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
	at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
	at org.apache.flink.runtime.concurrent.akka.AkkaFutureUtils$1.onComplete(AkkaFutureUtils.java:47)
	at akka.dispatch.OnComplete.internal(Future.scala:300)
	at akka.dispatch.OnComplete.internal(Future.scala:297)
	at akka.dispatch.japi$CallbackBridge.apply(Future.scala:224)
	at akka.dispatch.japi$CallbackBridge.apply(Future.scala:221)
	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64)
	at org.apache.flink.runtime.concurrent.akka.AkkaFutureUtils$DirectExecutionContext.execute(AkkaFutureUtils.java:65)
	at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:72)
	at scala.concurrent.impl.Promise$DefaultPromise.$anonfun$tryComplete$1(Promise.scala:288)
	at scala.concurrent.impl.Promise$DefaultPromise.$anonfun$tryComplete$1$adapted(Promise.scala:288)
	at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:288)
	at akka.pattern.PromiseActorRef.$bang(AskSupport.scala:622)
	at akka.pattern.PipeToSupport$PipeableFuture$$anonfun$pipeTo$1.applyOrElse(PipeToSupport.scala:24)
	at akka.pattern.PipeToSupport$PipeableFuture$$anonfun$pipeTo$1.applyOrElse(PipeToSupport.scala:23)
	at scala.concurrent.Future.$anonfun$andThen$1(Future.scala:536)
	at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:33)
	at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:33)
	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:64)
	at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:63)
	at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:100)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
	at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:85)
	at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:100)
	at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:49)
	at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:48)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: org.apache.flink.runtime.JobException: Recovery is suppressed by NoRestartBackoffTimeStrategy
	at org.apache.flink.runtime.executiongraph.failover.flip1.ExecutionFailureHandler.handleFailure(ExecutionFailureHandler.java:139)
	at org.apache.flink.runtime.executiongraph.failover.flip1.ExecutionFailureHandler.getFailureHandlingResult(ExecutionFailureHandler.java:83)
	at org.apache.flink.runtime.scheduler.DefaultScheduler.recordTaskFailure(DefaultScheduler.java:258)
	at org.apache.flink.runtime.scheduler.DefaultScheduler.handleTaskFailure(DefaultScheduler.java:249)
	at org.apache.flink.runtime.scheduler.DefaultScheduler.onTaskFailed(DefaultScheduler.java:242)
	at org.apache.flink.runtime.scheduler.SchedulerBase.onTaskExecutionStateUpdate(SchedulerBase.java:748)
	at org.apache.flink.runtime.scheduler.SchedulerBase.updateTaskExecutionState(SchedulerBase.java:725)
	at org.apache.flink.runtime.scheduler.SchedulerNG.updateTaskExecutionState(SchedulerNG.java:80)
	at org.apache.flink.runtime.jobmaster.JobMaster.updateTaskExecutionState(JobMaster.java:479)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.flink.runtime.rpc.akka.AkkaRpcActor.lambda$handleRpcInvocation$1(AkkaRpcActor.java:309)
	at org.apache.flink.runtime.concurrent.akka.ClassLoadingUtils.runWithContextClassLoader(ClassLoadingUtils.java:83)
	at org.apache.flink.runtime.rpc.akka.AkkaRpcActor.handleRpcInvocation(AkkaRpcActor.java:307)
	at org.apache.flink.runtime.rpc.akka.AkkaRpcActor.handleRpcMessage(AkkaRpcActor.java:222)
	at org.apache.flink.runtime.rpc.akka.FencedAkkaRpcActor.handleRpcMessage(FencedAkkaRpcActor.java:84)
	at org.apache.flink.runtime.rpc.akka.AkkaRpcActor.handleMessage(AkkaRpcActor.java:168)
	at akka.japi.pf.UnitCaseStatement.apply(CaseStatements.scala:24)
	at akka.japi.pf.UnitCaseStatement.apply(CaseStatements.scala:20)
	at scala.PartialFunction.applyOrElse(PartialFunction.scala:127)
	at scala.PartialFunction.applyOrElse$(PartialFunction.scala:126)
	at akka.japi.pf.UnitCaseStatement.applyOrElse(CaseStatements.scala:20)
	at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:175)
	at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:176)
	at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:176)
	at akka.actor.Actor.aroundReceive(Actor.scala:537)
	at akka.actor.Actor.aroundReceive$(Actor.scala:535)
	at akka.actor.AbstractActor.aroundReceive(AbstractActor.scala:220)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:579)
	at akka.actor.ActorCell.invoke(ActorCell.scala:547)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
	at akka.dispatch.Mailbox.run(Mailbox.scala:231)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
	... 4 more
Caused by: java.lang.NullPointerException: Unknown checkpoint for org.apache.flink.streaming.api.connector.sink2.CommittableWithLineage@265569e2
	at org.apache.flink.util.Preconditions.checkNotNull(Preconditions.java:104)
	at org.apache.flink.streaming.runtime.operators.sink.committables.CommittableCollector.getCheckpointCommittables(CommittableCollector.java:241)
	at org.apache.flink.streaming.runtime.operators.sink.committables.CommittableCollector.addCommittable(CommittableCollector.java:234)
	at org.apache.flink.streaming.runtime.operators.sink.committables.CommittableCollector.addMessage(CommittableCollector.java:126)
	at org.apache.flink.streaming.runtime.operators.sink.CommitterOperator.processElement(CommitterOperator.java:193)
	at org.apache.flink.streaming.runtime.tasks.OneInputStreamTask$StreamTaskNetworkOutput.emitRecord(OneInputStreamTask.java:237)
	at org.apache.flink.streaming.runtime.io.AbstractStreamTaskNetworkInput.processElement(AbstractStreamTaskNetworkInput.java:146)
	at org.apache.flink.streaming.runtime.io.AbstractStreamTaskNetworkInput.emitNext(AbstractStreamTaskNetworkInput.java:110)
	at org.apache.flink.streaming.runtime.io.StreamOneInputProcessor.processInput(StreamOneInputProcessor.java:65)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.processInput(StreamTask.java:550)
	at org.apache.flink.streaming.runtime.tasks.mailbox.MailboxProcessor.runMailboxLoop(MailboxProcessor.java:231)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.runMailboxLoop(StreamTask.java:839)
	at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:788)
	at org.apache.flink.runtime.taskmanager.Task.runWithSystemExitMonitoring(Task.java:952)
	at org.apache.flink.runtime.taskmanager.Task.restoreAndInvoke(Task.java:931)
	at org.apache.flink.runtime.taskmanager.Task.doRun(Task.java:745)
	at org.apache.flink.runtime.taskmanager.Task.run(Task.java:562)
	at java.lang.Thread.run(Thread.java:748)

这可能是 Flink 批处理模式下通常不需要 checkpoint,但 Doris Sink Connector 默认可能依赖 checkpoint 相关逻辑,从而导致 NullPointerException。

添加与 sink 行为相关的参数, 设置不用 checkpoint 。

修改后的sink如下:

String sinkDDL = “CREATE TABLE (” +
“station_sn STRING,” +
“pid_system_code STRING,” +
“day STRING,” +
“value STRING,” +
“created_at TIMESTAMP(3),” +
“dt DATE” +
“) WITH (” +
“‘connector’ = ‘doris’,” +
“‘fenodes’ = ‘:’,” +
“‘table.identifier’ = ‘.’,” +
“‘username’ = ”,” +
“‘password’ = ”,” +
“‘sink.label-prefix’ = ‘_” + timestamp + “‘,” +

"'doris.batch.size' = '1000'," +  // 批量写入大小
"'sink.enable-2pc' = 'false'" + // 禁用两阶段提交
")";
作者 east
Flink 1月 23,2025

flink 1.12用Flink SQL写入Doris的坑

在flink 1.12,用flink sql写入doris,相关pom配置如下:

   <dependency>
      <groupId>org.apache.doris</groupId>
      <artifactId>flink-doris-connector-1.12_2.11</artifactId>
      <version>1.0.3</version>
    </dependency>

to_date('2025-01-14')实际写入到doris变成了另外一个日期,非常坑。而且 
Flink Connector 24.0.0 版本之后支持使用Arrow Flight SQL 读取数据 ,速度提高非常快。

flink-doris-connector各版本兼容如下。

版本兼容​

Connector VersionFlink VersionDoris VersionJava VersionScala Version
1.0.31.11,1.12,1.13,1.140.15+82.11,2.12
1.1.11.141.0+82.11,2.12
1.2.11.151.0+8–
1.3.01.161.0+8–
1.4.01.15,1.16,1.171.0+8–
1.5.21.15,1.16,1.17,1.181.0+8–
1.6.21.15,1.16,1.17,1.18,1.191.0+8–
24.0.11.15,1.16,1.17,1.18,1.19,1.201.0+8–

比较好选择是选择Flink 1.16以上(可以兼容hive语法90
%以上)。升级到flink 1.17后,to_date(‘2025-01-14’)返回结果果然正常了。

作者 east
bug清单, Flink 1月 23,2025

解决flink 1.7 Exception in thread “main” org.apache.flink.table.api.ValidationException: Unable to create a sink for writing table

问题分析

  1. 报错提示的主要内容
    • ValidationException: Unable to create a sink for writing table ...
    • Could not load service provider for factories 和 org.apache.flink.table.planner.delegation.DefaultExecutorFactory not a subtype。
    • 这些问题通常是因为 Flink 运行环境或依赖配置不正确。
  2. 可能原因
    • Flink 和 Doris 依赖版本不匹配:
      • 使用的 Flink Doris Connector 是 flink-doris-connector-1.17,其版本号为 24.0.1,需要确保它与当前 Flink 的版本(1.17.x)兼容。或者flink的jar包有的不是1.17.x版本,和上面的 link-doris-connector-1.17 不兼容。

解决方案

1. 检查 Flink 和 Doris Connector 的兼容性

  • 确认 Flink 和 Doris Connector 的版本兼容。
  • 当前使用的是 flink-doris-connector-1.17,对应 Flink 1.17.x。如果使用的是其他版本的 Flink(如 1.16 或 1.18),需要更换依赖:
<dependency>
    <groupId>org.apache.doris</groupId>
    <artifactId>flink-doris-connector-1.17</artifactId>
    <version>24.0.1</version>
</dependency>

2. 添加 Flink Doris Connector 所需的运行时依赖

确保项目中包含以下依赖(建议手动检查 pom.xml 是否缺失),检查flink的jar是否都是1.17.x版本:

<dependency>
    <groupId>org.apache.doris</groupId>
    <artifactId>flink-doris-connector-1.17</artifactId>
    <version>24.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-planner_2.12</artifactId>
    <version>1.17.0</version>
    <scope>provided</scope>
</dependency>

确保 flink-table-planner_2.12 版本与 Flink 版本匹配。

作者 east
bug清单, Flink 1月 23,2025

解决flink 1.7项目 找不到org.apache.flink.table.descriptors.TableDescriptor

flink版本1.7的项目代码如下:

   StreamExecutionEnvironment executionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
        executionEnvironment.setParallelism(1);

        // 设置 Flink SQL 环境
        EnvironmentSettings settings = EnvironmentSettings.newInstance().inStreamingMode().build();
        StreamTableEnvironment tableEnvironment = StreamTableEnvironment.create(executionEnvironment, settings);

运行报错找不到org.apache.flink.table.descriptors.TableDescriptor。

问题分析

  1. 依赖冲突或缺失:
    • Flink 1.17.2 中 TableDescriptor 类已被废弃。Flink 1.13 开始引入了 TableDescriptor 的新概念,用于定义表源和表目标,而旧版依赖中的 org.apache.flink.table.descriptors 相关类在后续版本中被逐步移除。
    • 如果代码中还有引用 org.apache.flink.table.descriptors 包下的类(如连接器或格式描述符),可能导致运行时报错。
  2. API 版本不匹配:
    • 在 Flink 1.17.2 中,推荐使用 Table API 的新方式(TableDescriptor 不再使用)。这可能意味着您正在使用旧版本的 API,或者您的代码依赖了不兼容的旧包。

解决方案

1. 检查代码中是否仍在使用旧版 API

移除任何对 org.apache.flink.table.descriptors 的直接依赖。使用以下代码替换旧方法:

// 创建 Flink 流执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);

// 创建 Flink SQL 表执行环境
EnvironmentSettings settings = EnvironmentSettings.newInstance().inStreamingMode().build();
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);

// 定义表源或目标时,使用 Table API 的新方式
TableDescriptor descriptor = TableDescriptor.forConnector("kafka") // 替换为实际使用的连接器
        .schema(Schema.newBuilder()
                .column("field1", DataTypes.STRING())
                .column("field2", DataTypes.INT())
                .build())
        .format("json") // 替换为实际使用的格式
        .option("property.key", "value") // 替换为实际连接器选项
        .build();

tableEnv.createTemporaryTable("my_table", descriptor);

2. 更新依赖

确保项目使用的依赖与 Flink 1.17.2 版本兼容。在 pom.xml 或 build.gradle 文件中明确声明以下依赖:

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-java_2.12</artifactId>
    <version>1.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-api-java-bridge_2.12</artifactId>
    <version>1.17.2</version>
</dependency>
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-planner_2.12</artifactId>
    <version>1.17.2</version>
    <scope>provided</scope>
</dependency>

3. 清理旧依赖

如果仍需要使用 TableDescriptor 类,请确认没有混用老旧版本的连接器或额外库,例如 flink-connector-kafka 等。检查项目中是否存在以下老依赖,并替换为新版依赖:

旧版依赖示例:

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-common</artifactId>
    <version>1.12.x</version>
</dependency>

作者 east
bug清单, Flink 1月 23,2025

解决flink 1.7项目 java.lang.ClassNotFoundException: org.apache.flink.shaded.guava18.com.google.common.collect.ImmutableList

运行flink 1.7的项目,报错如下:

Exception in thread “main” java.lang.NoClassDefFoundError: org/apache/flink/shaded/guava18/com/google/common/collect/ImmutableList at org.apache.flink.table.planner.plan.schema.FlinkPreparingTableBase.<init>(FlinkPreparingTableBase.java:92) at org.apache.flink.table.planner.plan.schema.ExpandingPreparingTable.<init>(ExpandingPreparingTable.java:42) at org.apache.flink.table.planner.catalog.QueryOperationCatalogViewTable.<init>(QueryOperationCatalogViewTable.java:49) at org.apache.flink.table.planner.catalog.QueryOperationCatalogViewTable.create(QueryOperationCatalogViewTable.java:58) at org.apache.flink.table.planner.plan.FlinkCalciteCatalogReader.convertQueryOperationView(FlinkCalciteCatalogReader.java:146) at org.apache.flink.table.planner.plan.FlinkCalciteCatalogReader.toPreparingTable(FlinkCalciteCatalogReader.java:110) at org.apache.flink.table.planner.plan.FlinkCalciteCatalogReader.getTable(FlinkCalciteCatalogReader.java:91) at org.apache.calcite.prepare.CalciteCatalogReader.getTableForMember(CalciteCatalogReader.java:229) at org.apache.calcite.sql.validate.SqlValidatorUtil.getRelOptTable(SqlValidatorUtil.java:144) at org.apache.calcite.sql.validate.SqlValidatorUtil.getRelOptTable(SqlValidatorUtil.java:110) at org.apache.calcite.sql2rel.SqlToRelConverter.convertIdentifier(SqlToRelConverter.java:2490) at org.apache.calcite.sql2rel.SqlToRelConverter.convertFrom(SqlToRelConverter.java:2144) at org.apache.calcite.sql2rel.SqlToRelConverter.convertFrom(SqlToRelConverter.java:2093) at org.apache.calcite.sql2rel.SqlToRelConverter.convertFrom(SqlToRelConverter.java:2050) at org.apache.calcite.sql2rel.SqlToRelConverter.convertSelectImpl(SqlToRelConverter.java:663) at org.apache.calcite.sql2rel.SqlToRelConverter.convertSelect(SqlToRelConverter.java:644) at org.apache.calcite.sql2rel.SqlToRelConverter.convertQueryRecursive(SqlToRelConverter.java:3438) at org.apache.calcite.sql2rel.SqlToRelConverter.convertQuery(SqlToRelConverter.java:570) at org.apache.flink.table.planner.calcite.FlinkPlannerImpl.org$apache$flink$table$planner$calcite$FlinkPlannerImpl$$rel(FlinkPlannerImpl.scala:165) at org.apache.flink.table.planner.calcite.FlinkPlannerImpl.rel(FlinkPlannerImpl.scala:157) at org.apache.flink.table.planner.operations.SqlToOperationConverter.toQueryOperation(SqlToOperationConverter.java:902) at org.apache.flink.table.planner.operations.SqlToOperationConverter.convertSqlQuery(SqlToOperationConverter.java:871) at org.apache.flink.table.planner.operations.SqlToOperationConverter.convert(SqlToOperationConverter.java:250) at org.apache.flink.table.planner.operations.SqlToOperationConverter.convertSqlInsert(SqlToOperationConverter.java:564) at org.apache.flink.table.planner.operations.SqlToOperationConverter.convert(SqlToOperationConverter.java:248) at org.apache.flink.table.planner.delegation.ParserImpl.parse(ParserImpl.java:77) at org.apache.flink.table.api.internal.TableEnvironmentImpl.executeSql(TableEnvironmentImpl.java:660) at com.chuneng.saas.doris.FlinkCuSohJdbcSqlAnalyze.main(FlinkCuSohJdbcSqlAnalyze.java:98) Caused by: java.lang.ClassNotFoundException: org.apache.flink.shaded.guava18.com.google.common.collect.ImmutableList at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

  • 从报错信息 java.lang.NoClassDefFoundError: org/apache/flink/shaded/guava18/com/google/common/collect/ImmutableList 和 Caused by: java.lang.ClassNotFoundException: org.apache.flink.shaded.guava18.com.google.common.collect.ImmutableList 可以看出,程序在运行时无法找到 org.apache.flink.shaded.guava18.com.google.common.collect.ImmutableList 这个类。
  • 这通常是因为相应的依赖库没有被正确地添加到项目的类路径中,导致 JVM 在运行时无法加载所需的类。

修改方案:

  1. 确认你是否在项目的构建文件(如 Maven 的 pom.xml 或 Gradle 的 build.gradle)中添加了 Apache Flink 相关的依赖。
  2. 确保使用的 Flink 版本是兼容的,并且其依赖的 Guava 版本是 flink-shaded-guava 的 18 版本。
  3. 对于 Maven 项目,检查 pom.xml 中是否有类似如下的依赖:

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-shaded-guava</artifactId>
    <version>18.0</version>
</dependency>
  1. 对于 Gradle 项目,检查 build.gradle 中是否有类似如下的依赖:

implementation 'org.apache.flink:flink-shaded-guava:18.0'
  1. 如果已经添加了依赖,可能是因为依赖冲突导致无法找到正确的类。可以使用 mvn dependency:tree(对于 Maven)或 gradle dependencies(对于 Gradle)命令查看依赖树,找出是否有多个版本的 Guava 被引入,然后通过排除冲突的依赖来解决。
作者 east
Java, 大数据开发 1月 22,2025

手撕代码刷题秘籍,小白到Offer收割机的进阶之路

​

 要准备面试,无非就是要准备熟背八股文,做有深度的项目,好好学习数据结构和算法,刷题准备手撕面试题。

其中手撕面试题的准备时间是比较长的。八股文和大厂手撕面试题可以看下面专栏,花了半个月时间从上千份大厂面经分类整理出面试题及手撕面试题。

嵌入式最全面试题-Offer直通车

大数据最全面试题-Offer直通车

Java开发及前端最全面试题-Offer直通车

Android最全面试题-Offer直通车

C++后端开发最全面试题-从入门到Offer

线上笔试

不少公司面试的第一关就是线上笔试题📃。咱得自己在家对着电脑做,就像考试一样,限定时间内完成题目。这种时候,环境相对熟悉,压力可能没那么大,但也得注意别因为在家就放松警惕,一定要严格按照考试要求来,提前调试好设备,保证网络稳定,别到时候因为这些小问题影响发挥。

现场手撕代码

等过了笔试,到了现场面试,这可就刺激了🤯。面试官会给你一台电脑,让你当场敲代码,有时候甚至直接给你一张纸,让你手写代码。这种情况对咱的心理素质和编程能力要求更高。在面试官眼皮子底下写代码,紧张是肯定的,但越这时候越得稳住,千万别慌了神。咱平时刷题练的就是这时候的底气💪。

入门指南:选对资料,开启刷题第一步

刚接触手撕代码刷题,选对入门资料太重要了📚,除了学校的数据结构和算法教科书,公认是推荐《剑指 Offer》。这本书对数据结构和算法的讲解特别详细,还有对应的 Java 代码示例,很适合新手。你可以先从基础的数据结构,像数组、链表这些开始看,把基础打牢。网上也有不少相关的在线教程,比如慕课网、网易云课堂上都有优质课程,跟着视频一步步学,理解起来更容易。

手撕面试题很多,下面这些是大厂高频的手撕面试题:

从上千份大厂面经呕心沥血整理:大厂高频手撕面试题(数据结构和算法篇 ,Java实现亲试可跑)

 从上千份大厂面经呕心沥血整理:大厂高频手撕面试题(数据结构和算法篇 ,C++实现亲试可跑)

循序渐进:从易到难,稳步提升

刷题就像爬山,得一步一个脚印👣。先从简单的题目入手,比如求数组的和、判断一个数是否为素数这类基础题。把这些简单题做熟了,不仅能建立自信,还能让咱熟悉编程的基本语法和逻辑。等简单题得心应手了,再慢慢增加难度,比如做一些涉及排序算法优化、查找算法应用的题目。面对难题别害怕,就像拆解乐高积木一样,把问题拆分成一个个小问题,逐个击破。每次成功解决一道难题,你会发现自己的编程能力又上了一个台阶。

实战演练:参加竞赛,提升实战能力

如果是在校生,参加算法竞赛对提升大数据刷题能力简直太有帮助了🎉。像 ACM 国际大学生程序设计竞赛、蓝桥杯这些,都是很不错的平台。在竞赛中,你会遇到来自各地的高手,和他们同场竞技,能让你见识到各种巧妙的解题思路和编程技巧。而且竞赛的时间压力很大,能锻炼你在紧张环境下快速思考和编写代码的能力。就像我认识一个学长,参加了几次 ACM 竞赛后,再去面试大数据岗位,那些手撕代码的题目对他来说轻松多了。

合理规划:把握刷题节奏和时间

刷题可不是一蹴而就的事儿,得合理安排时间和节奏🕙。每天刷几道题,这个得根据自己的情况来。要是你时间比较充裕,每天刷 3 – 5 道题也没问题;要是平时学业或者工作忙,每天保证 1 – 2 道题的练习量。别一开始就猛刷,把自己累到了,后面反而坚持不下去。一般来说,先把基础的算法和数据结构题目刷完,再去刷一些综合应用的题目。刷完一本书或者一个阶段的题目后,可以去力扣、牛客网这些平台上找一些大数据专项题目来巩固,刷个 80 – 150 道,基本就差不多了。

效果检验:判断刷题能力是否提升

怎么知道自己刷题有没有效果呢🧐?首先就是看刷题的数量,量变引起质变,刷的题多了,自然会有感觉。但光数量可不够,还得看质量。比如你能不能用多种方法解决同一道题,这说明你对知识点理解得很透彻。还有就是尝试挑战一些难度更高的题目,如果能顺利解决,那能力肯定提升了。另外,刷题平台一般都会给出代码的时间复杂度和空间复杂度分析,看看自己的代码效率有没有提高,这也是检验能力的重要标准。 ​

作者 east
Flink 1月 22,2025

Flink1.7官方文档中文翻译:及时流处理

简介#

及时流处理是有状态流处理的一种扩展,其中时间在计算中发挥一定作用。例如,在进行时间序列分析、基于特定时间段(通常称为窗口)进行聚合,或者在处理事件时事件发生的时间很关键等情况时,都会涉及到及时流处理。
在接下来的章节中,我们将重点介绍在使用 Flink 进行及时流处理应用开发时,需要考虑的一些主题。
返回顶部

时间概念:事件时间与处理时间#

在流处理程序中提及时间(例如定义窗口时),可以涉及不同的时间概念:

  • 处理时间:处理时间指的是执行相应操作的机器的系统时间。

当一个流处理程序基于处理时间运行时,所有基于时间的操作(如时间窗口)将使用运行相应操作符的机器的系统时钟。一个按小时划分的处理时间窗口将包含在系统时钟显示整点之间到达特定操作符的所有记录。例如,如果一个应用程序在上午 9:15 开始运行,第一个按小时划分的处理时间窗口将包含上午 9:15 到 10:00 之间处理的事件,下一个窗口将包含上午 10:00 到 11:00 之间处理的事件,依此类推。
处理时间是最简单的时间概念,无需在流和机器之间进行协调。它能提供最佳性能和最低延迟。然而,在分布式和异步环境中,处理时间不具备确定性,因为它易受记录进入系统的速度(例如从消息队列进入)、记录在系统内操作符之间流动的速度以及中断(计划内或其他情况)的影响。

  • 事件时间:事件时间是每个事件在其产生设备上发生的时间。这个时间通常在记录进入 Flink 之前就嵌入其中,并且可以从每条记录中提取出事件时间戳。在事件时间中,时间的推进取决于数据,而非任何物理时钟。基于事件时间的程序必须指定如何生成事件时间水印,这是一种在事件时间中标记时间推进的机制。这种水印机制将在后续章节中介绍。

在理想情况下,无论事件何时到达或其顺序如何,基于事件时间的处理都能产生完全一致且确定的结果。然而,除非已知事件按时间戳顺序到达,否则事件时间处理在等待乱序事件时会产生一定延迟。由于只能等待有限的时间,这就限制了基于事件时间的应用程序的确定性程度。
假设所有数据都已到达,即使处理乱序或迟到的事件,或者重新处理历史数据,基于事件时间的操作也会按预期执行,并产生正确且一致的结果。例如,一个按小时划分的事件时间窗口将包含所有携带的事件时间戳属于该小时的记录,无论它们到达的顺序如何,也无论它们何时被处理。(有关更多信息,请参阅 “延迟” 部分。)
请注意,有时基于事件时间的程序在实时处理实时数据时,会使用一些基于处理时间的操作,以确保它们能够及时推进。
事件时间与处理时间

Event Time and Processing Time


事件时间与水印#

注意:Flink 实现了数据流模型中的许多技术。若要深入了解事件时间和水印,可查看以下文章。

  • Tyler Akidau 的《Streaming 101》
  • 《数据流模型》论文

一个支持事件时间的流处理器需要一种方式来衡量事件时间的推进。例如,一个构建按小时划分窗口的窗口操作符,需要在事件时间超过一小时结束时得到通知,以便该操作符能够关闭正在处理的窗口。
事件时间可以独立于处理时间(由物理时钟测量)推进。例如,在一个程序中,某个操作符的当前事件时间可能略落后于处理时间(考虑到接收事件的延迟),但两者以相同速度推进。另一方面,另一个流处理程序可能通过快速处理已经缓冲在 Kafka 主题(或其他消息队列)中的一些历史数据,在仅几秒钟的处理时间内推进数周的事件时间。
Flink 中衡量事件时间推进的机制是水印。水印作为数据流的一部分流动,并携带一个时间戳 t。Watermark (t) 声明在该流中事件时间已到达时间 t,这意味着该流中不应再有时间戳 t’ <= t 的元素(即时间戳早于或等于水印的事件)。
下图展示了带有(逻辑)时间戳的事件流以及同步流动的水印。在这个例子中,事件是按(时间戳)顺序排列的,这意味着水印只是流中的周期性标记。
有序事件流和水印
水印对于乱序流至关重要,如下图所示,其中事件并非按时间戳排序。一般来说,水印表明在流中的那个点,所有到某个时间戳的事件都应该已经到达。一旦水印到达一个操作符,该操作符可以将其内部事件时间时钟推进到水印的值。
无序事件流和水印
请注意,新创建的流元素的事件时间继承自产生它们的事件,或者触发这些元素创建的水印。

并行流中的水印#

水印在源函数处或紧随源函数之后生成。源函数的每个并行子任务通常独立生成其水印。这些水印定义了该特定并行源的事件时间。
随着水印在流处理程序中流动,它们会推进水印到达的操作符处的事件时间。每当一个操作符推进其事件时间时,它会为下游的后续操作符生成一个新的水印。
有些操作符会消费多个输入流,例如 union 操作符,或者在 keyBy (…) 或 partition (…) 函数之后的操作符。这样的操作符的当前事件时间是其输入流事件时间的最小值。随着其输入流更新它们的事件时间,该操作符的事件时间也会更新。
下图展示了事件和水印在并行流中流动,以及操作符跟踪事件时间的示例。
并行数据流、操作符与事件和水印

延迟#

有可能某些元素会违反水印条件,即即使在 Watermark (t) 出现之后,仍会出现更多时间戳 t’ <= t 的元素。实际上,在许多实际场景中,某些元素可能会被任意延迟,使得无法指定一个时间,保证在该时间之前具有特定事件时间戳的所有元素都已到达。此外,即使延迟可以界定,将水印延迟太多通常也不可取,因为这会导致事件时间窗口的评估出现过多延迟。
因此,流处理程序可能会明确预期一些延迟元素。延迟元素是指在系统的事件时间时钟(由水印指示)已经超过延迟元素的时间戳之后才到达的元素。有关如何在事件时间窗口中处理延迟元素的更多信息,请参阅 “允许的延迟”。

窗口化#

对流中的事件进行聚合(例如计数、求和)与批处理中的方式不同。例如,不可能对流中的所有元素进行计数,因为流通常是无限的(无界的)。相反,对流的聚合(计数、求和等)是通过窗口来界定范围的,例如 “过去 5 分钟的计数” 或 “过去 100 个元素的求和”。
窗口可以由时间驱动(例如:每 30 秒)或由数据驱动(例如:每 100 个元素)。通常可以区分不同类型的窗口,例如滚动窗口(无重叠)、滑动窗口(有重叠)和会话窗口(由不活动间隙分隔)。
时间窗口和计数窗口
有关窗口的更多示例,请查看此博客文章,或者查看 DataStream API 的窗口文档。介绍一下Flink的时间概念如何在Flink中使用事件时间?Flink的窗口操作符有哪些?

作者 east

上一 1 … 11 12 13 … 93 下一个

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。回复”chatgpt”获取免注册可用chatgpt。回复“大数据”获取多本大数据电子书

标签

AIGC AI创作 bert chatgpt github GPT-3 gpt3 GTP-3 hive mysql O2O tensorflow UI控件 不含后台 交流 共享经济 出行 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 日历 机器学习 深度学习 物流 用户系统 电商 画图 画布(canvas) 社交 签到 联网 读书 资讯 阅读 预订

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • 如何在Chrome中设置启动时自动打开多个默认网页
  • spark内存溢出怎样区分是软件还是代码原因
  • MQTT完全解析和实践
  • 解决运行Selenium报错:self.driver = webdriver.Chrome(service=service) TypeError: __init__() got an unexpected keyword argument ‘service’
  • python 3.6使用mysql-connector-python报错:SyntaxError: future feature annotations is not defined
  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?

文章归档

  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年1月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年7月
  • 2018年6月

分类目录

  • Android (73)
  • bug清单 (79)
  • C++ (34)
  • Fuchsia (15)
  • php (4)
  • python (45)
  • sklearn (1)
  • 云计算 (20)
  • 人工智能 (61)
    • chatgpt (21)
      • 提示词 (6)
    • Keras (1)
    • Tensorflow (3)
    • 大模型 (1)
    • 智能体 (4)
    • 深度学习 (14)
  • 储能 (44)
  • 前端 (5)
  • 大数据开发 (491)
    • CDH (6)
    • datax (4)
    • doris (31)
    • Elasticsearch (15)
    • Flink (78)
    • flume (7)
    • Hadoop (19)
    • Hbase (23)
    • Hive (41)
    • Impala (2)
    • Java (71)
    • Kafka (10)
    • neo4j (5)
    • shardingsphere (6)
    • solr (5)
    • Spark (100)
    • spring (11)
    • 数据仓库 (9)
    • 数据挖掘 (7)
    • 海豚调度器 (10)
    • 运维 (34)
      • Docker (3)
  • 小游戏代码 (1)
  • 小程序代码 (139)
    • O2O (16)
    • UI控件 (5)
    • 互联网类 (23)
    • 企业类 (6)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (25)
    • 电商类 (22)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 嵌入式 (71)
    • autosar (63)
    • RTOS (1)
    • 总线 (1)
  • 开发博客 (16)
    • Harmony (9)
  • 技术架构 (6)
  • 数据库 (32)
    • mongodb (1)
    • mysql (13)
    • pgsql (2)
    • redis (1)
    • tdengine (4)
  • 未分类 (7)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.