数据架构解决方案(5) -- 数据架构中的风险管理(一)
这是数据架构解决方案系列博客的第五篇,系列的其他文章:
到目前为止,我们讨论了如何从头构建一个完整数据应用架构。接下来的文章是以上面 4 章为骨架和脉络,介绍更细节和具体的方法。
首先,我们先来了解在做了一系列决策后,如何评估这个项目中的所有风险,以及如何应对这些风险,以便项目能顺利上线。
在构建一个数据驱动的应用项目时,应该要意识到哪些部分是需要担心的,哪些部分是薄弱的,特别是当你在整个架构中应用了一些以前没有生产环境经验的新技术栈的时候。但是如果能将这些有风险的环节都处理好了,那么风险就能变成新的机会,可能会成为整个项目成功的关键。
在本篇文章中,我们来讨论一下在构建实际项目的过程中,如何管理引入新技术带来各类风险,以及要如何实现。另外,我们将讨论如何通过通用的开发原则和策略,来设定切实可行的期望,并且讨论如何构建团队来成功地建立开发和管理环境。
风险分类
在深入讨论风险管理之前,我们先来对数据项目可能存在的风险做一个粗略的分类:
技术风险
任何软件项目都会引入风险。构建大型复杂的分布式数据解决方案更是会加大这些风险,当项目中引入了一些不熟悉的技术栈时,更是如此。
这些风险可能是来自于体系结构的各个组件,可能是组件之间的交互,风险也可能来自对系统设计中使用的技术的不熟悉。
团队风险
团队风险是指与实现数据架构的团队成员,以及相关的外部团队相关的风险。这类风险可能来自团队成员自身的知识水平和实力,对外部团队的依赖,团队间的沟通,甚至可能是某些具有破坏性的团队成员。
需求风险
需求风险是另一类常见的风险。
常见的需求风险包括:
需求定义不明确
问题定义不明确
需求不易实现
尤其是在使用新技术时,可能会接到之前从未实现过的需求。例如,延迟或吞吐量要求高于团队之前建立的要求。
管理风险
我们先从引入一种能为系统中的组件评定风险级别的模型开始。这些风险级别涵盖了我们在上一节中讨论的不同风险类别,并提供了量化和解决这些风险的方法。
将系统架构的风险分类
首先,我们要讲整个数据系统拆分成多个含义明确,高内聚低耦合的子系统。
下图展示了将一个常见的数据存储,数据处理系统拆分成多个子系统的例子:

这只是第一步。为了更好地分析系统风险,我们还能将这些子系统拆分得更细:
在这个阶段,拆分到这个程度就差不多了。接下来需要做的是将每个子组件的接口定义清楚,这将有助于降低某个子系统可能影响系统其余部分的风险。这样一来,就可以将一个子组件视为一个独立系统来开发,并且可以将每个子组件的风险仅包含在该组件中而不影响其他。

下一步是选择并实现组件需要的技术,如下图所示。然后可以将组件分配给团队成员来处理,并根据团队成员和技术来评估相应的风险。我们将从技术风险入手,讨论此过程。

上图展示了我们为每一类场景选择了一个具体的技术方案,目前我们可以将这些技术方案看做是一个场景的占位符,表示这只是我们在设计之初的选择,在实现和验证的过程中,可以随时用另一个可能更适合的技术方案替换掉。这也提醒了我们在设计和实现的时候,使用 可替换接口 的重要性。
技术风险
对于一个团队来说,权衡一个技术方案的风险权重有时候并不是那么容易,因为在没有真正上生产环境之前,所有的测试和数据都只能当做参考。但直觉通常可以起到一定作用:比如,如果你和团队以前有在生产环境中使用过某项技术的经验,那么该技术的风险评级应该较低。相反地,你应该给一个你很少或根本没有经验的技术定一个更高的风险评级。
此外,了解一项技术可能会涉及到多个层次的知识。
以 SQL 为例,某些团队可能有多年的 MySQL 使用经验,但可能对 Hive、Spark SQL或 Impala, ClickHouse 等较新的 SQL 查询引擎没有太多的经验。由于不同的查询引擎的行为方式可能会不一样,支持的 SQL 标准也不一样,所以了解这些功能和限制对于使用这些系统是非常关键的。
当我们说我们知道一项技术时,我们需要自上而下地了解它。
团队风险
一个团队的风险取决于你对团队成员的个人能力的认识、以及团队完成任务和不能按时完成任务的历史。通常情况下,如果团队中新成员或者实战经验尚浅的成员较多的话,可能意味着该团队的风险权重更高。
此外,不管经验水平如何,每个团队都有不同类型的具有不同技能的人员。下面简单介绍一下一个完善的团队至少应该的一些角色:
QA
QA 负责确保项目具有非常高的测试覆盖率,保证交付的数据的高质量。优秀的 QA 还应该保持对细节的专注,比如:代码是完全版本控制的,代码的合理注释等等。
调研人员
这个角色负责调研并测试各类新软件。他们的作用是在更改设计或方法为时已晚之前,详细并且合理地测试这些新的技术方案,并了解可能存在的风险。
开发人员
这类角色负责理解业务细节,并且将业务需求转换为代码,真正的将业务完成。
协调人员
与其他团队和管理层进行及时有效的沟通对于本团队而言是一项重要的任务。
并不是所有的开发人员都喜欢这个任务,因为这个角色继续要了解技术实现的细节,也需要掌握和人沟通的技巧。
除此之外,还有一些角色可能会对团队有负面影响:
孤僻的天才
标题有点夸张,想要表达的意思是:优秀的程序员,写代码的效率超高,但是不善于在团队合作,喜欢单打独斗。
这类角色在某些情况下会起到大的作用:比如需要攻克项目中的重大难点时。
但是如果对于他们管理不善或者团队规范团队成员不合他们的想法时,可能他们会变成团队的不良影响。
傲慢且偏执
一个团队经常会有一个成员,他们有时会无意中破坏团队的气氛。
有时这些人喜欢对一些不重要的细节和团队成员争论,并且确信他们知道做任何事情的最佳方法。虽然这些人通常都可以给团队的生产力带来提升,但他们对团队其他成员带来的负面情绪可能比他们对生产力的提升还要大。如果真的有这种情况发生,务必避免这类角色。
如果可能的话,尽量让两个或者两个以上的成员负责同一个组件,一方面是当一个成员不可用(比如休假)时,有备用的成员。另一方面是,有两人相互为对方负责会让这个组件更加可靠。
其他团队相关的风险
除了本团队相关的风险,还有与外部团队合作的风险。
只要你的团队和其他合作团队有依赖的关系,你就面临着这类风险的可能。
记住下面几点:
- 相互尊重;
- 职责定义和需求定义要明确;
- 交互接口要事先商量好并且定义明确;
- 文档清晰明确;
需求风险
和需求相关的风险有多种。
比较常见的是需求定义模糊,这意味着在项目进行过程中需求可能会进行调整,这会导致可能给项目引入新的风险;
另一种风险是,需求是之前没有处理过的。比如更高的 SLA 级别。
管理需求相关的风险常用的方法是:
明确需求整体的功能和目标
再复杂的需求都有自己的终极目标,首先需要和所有利益相关方明确的就是这个需求要实现的目标和功能。
将大需求拆分成可管理的多个小需求
如题所示。
对每个小需求提出可实现的方案
如果可能的话,对每个子需求都提出一份可实现的技术方案,并且对这个方案做 POC,然后根据 POC 的结果做相应的调整。
当每个子需求的 POC 都有结果后,再对整体方案做一个 POC,最后将结果告知所有利益相关方。
按照这几个步骤做下去之后,
- 需求肯定是明确了
- 开发团队的成员对需求有了更深的理解
- 需求提出方对方案的设计和实现有了信心
- 根据 POC 的结果,可以整理出需求实现的整体时间线
给风险分级
根据上述的三种风险类别,总结之后可以给每个组件分个级别,分了级别后,才能更有针对性的应对这些风险。

如图所示,给每个组件分好风险级别后,可以给出说明为什么某个组件的风险高。
举例说明:
流处理
经验 (技术风险)
我们团队以前从来没有处理过相关场景的问题。
零数据丢失 (技术风险)
一条数据都不能丢失,这对于团队来说引入了一个复杂的技术场景,而且上线后的运维工作会变得更加不易。
降低风险
给风险分级后,就可以着手降低风险了。有些方法已经介绍过,这里做一个补漏和总结:
固化需求
如上所说,详细明确的功能需求可以帮助将需求风险降到最低。
确保给你的需求得到所有利益相关者的认同
明确项目职责范围并确保利益相关者同意
明确与其他团队的接口要求和协议
定义好接口可以帮助降低架构风险,因为当需求有变更的时候,可以更容易地重构组件或替换技术栈。
优先考虑风险较大的组件
尽早处理风险较大的子组件可以留出额外的时间,以防遇到更多问题。
将风险更高的子任务分给更有经验的团队成员
利用外部资源帮助解决信息不透明(不对等)的情况
使用原型和 POC 来降低前期架构风险
用风险较小的组件替换风险较高的组件
例如,在假设的风险分解中,我们可能决定用可用团队成员更熟悉的工具(如 Spark Structured Streaming)替换 Flink 来处理流式数据。
总结
本篇主要介绍了在构建数据架构过程中可能会遇到的三种风险,以及如何将它们化小的方法。
技术风险
团队成员风险
需求风险