This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
<audio id="audio" title="18 | 如何自己开发一个大数据SQL引擎" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9d/65/9d9a6a0590ddc5d22013efc967eb1165.mp3"></audio>
从今天开始我们就进入了专栏的第三个模块,一起来看看大数据开发实践过程中的门道。学习一样技术,如果只是作为学习者,被动接受总是困难的。**但如果从开发者的视角看,很多东西就豁然开朗了,明白了原理,有时甚至不需要学习,顺着原理就可以推导出各种实现细节**。
各种知识从表象上看,总是杂乱无章的,如果只是学习这些繁杂的知识点,固然自己的知识面是有限的,并且遇到问题的应变能力也很难提高。所以有些高手看起来似乎无所不知,不论谈论起什么技术,都能头头是道,其实并不是他们学习、掌握了所有技术,而是他们是在谈到这个问题的时候,才开始进行推导,并迅速得出结论。
我在Intel的时候面试过一个交大的实习生她大概只学过一点MapReduce的基本知识我问她如何用MapReduce实现数据库的join操作可以明显看出她没学习过这部分知识。她说我想一下然后盯着桌子看了两三秒的时间就开始回答基本跟Hive的实现机制一样。从她的回答就能看出这个女生就是一个高手高手不一定要很资深、经验丰富把握住了技术的核心本质掌握了快速分析推导的能力能够迅速将自己的知识技能推进到陌生的领域就是高手。
这也是我这个专栏的目的,讲述大数据技术的核心原理,分享一些高效的思考和思维方式,帮助你构建起自己的技术知识体系。
在这个模块里,我将以大数据开发者的视角,讲述大数据开发需要关注的各种问题,以及相应的解决方案。希望你可以进入我的角色,跳出纷繁复杂的知识表象,掌握核心原理和思维方式,进而融会贯通各种技术,再通过各种实践训练,最终成为真正的高手。
前面专栏我们提到过程序员的三大梦想也就是开发数据库、操作系统和编译器。今天我们通过一个支持标准SQL语法的大数据仓库引擎的设计开发案例看看如何自己开发一个大数据SQL引擎。
在学习今天的内容前我们先回顾一下前面讨论过的大数据仓库Hive。作为一个成功的大数据仓库它将SQL语句转换成MapReduce执行过程并把大数据应用的门槛下降到普通数据分析师和工程师就可以很快上手的地步。这部分内容如果你忘记了可以返回[专栏第11期](http://time.geekbang.org/column/article/69459)复习一下。
但是Hive也有自己的问题由于它使用自己定义的Hive QL语法这对已经熟悉Oracle等传统数据仓库的分析师来说还是有一定的上手难度。特别是很多企业使用传统数据仓库进行数据分析已经由来已久沉淀了大量的SQL语句并且这些SQL经过多年的修改打磨非常庞大也非常复杂。我曾经见过某银行的一条统计报表SQL打印出来足足两张A4纸。这样的SQL光是完全理解可能就要花很长时间再转化成Hive QL就更加费力还不说转化修改过程中可能引入的bug。
2012年那会我还在Intel亚太研发中心大数据团队当时团队决定开发一款能够支持标准数据库SQL的大数据仓库引擎希望让那些在Oracle上运行良好的SQL可以直接运行在Hadoop上而不需要重写成Hive QL。这就是后来的[Panthera](http://github.com/intel-hadoop/project-panthera-ase)项目。
在开发Panthera前我们分析一下Hive的主要处理过程大体上分成三步
1.将输入的Hive QL经过语法解析器转换成Hive抽象语法树Hive AST<br>
2.将Hive AST经过语义分析器转换成MapReduce执行计划。<br>
3.将生成的MapReduce执行计划和Hive执行函数代码提交到Hadoop上执行。
Panthera的设计思路是保留Hive语义分析器不动替换Hive语法解析器使其将标准SQL语句转换成Hive语义分析器能够处理的Hive抽象语法树。用图形来表示的话是用红框内的部分代替黑框内原来Hive的部分。
<img src="https://static001.geekbang.org/resource/image/72/b0/7236e0335857fd75d7d773634eaf51b0.png" alt="">
红框内的组件我们重新开发过浅蓝色的是我们使用的一个开源的SQL语法解析器将标准SQL解析成标准SQL抽象语法树SQL AST后面深蓝色的就是团队自己开发的SQL抽象语法树分析与转换器将SQL AST转换成Hive AST。
那么标准SQL和Hive QL的差别在哪里呢
标准SQL和Hive QL的差别主要有两个方面一个是语法表达方式Hive QL语法和标准SQL语法略有不同另一个是Hive QL支持的语法元素比标准SQL要少很多比如数据仓库领域主要的测试集[TPC-H](http://www.tpc.org/tpch/)所有的SQL语句Hive都不支持。尤其是Hive不支持复杂的嵌套子查询而对于数据仓库分析而言嵌套子查询几乎是无处不在的。比如下面这样的SQL在where查询条件existes里面包含了另一条SQL语句。
```
select o_orderpriority, count(*) as order_count
from orders
where o_orderdate &gt;= date '[DATE]'
and o_orderdate &lt; date '[DATE]' + interval '3' month
and exists
( select * from lineitem
where l_orderkey = o_orderkey and l_commitdate &lt; l_receiptdate )
group by o_orderpriority order by o_orderpriority;
```
所以开发支持标准SQL语法的SQL引擎的难点就变成**如何将复杂的嵌套子查询消除掉**也就是where条件里不包含select。
SQL的理论基础是关系代数而关系代数的主要操作只有5种分别是并、差、积、选择、投影。所有的SQL语句最后都能用这5种操作组合完成。而一个嵌套子查询可以等价转换成一个连接join操作。
比如这条SQL
```
select s_grade from staff where s_city not in (select p_city from proj where s_empname=p_pname)
```
这是一个在where条件里嵌套了not in子查询的SQL语句它可以用left outer join和left semi join进行等价转换示例如下这是Panthera自动转换完成得到的等价SQL。这条SQL语句不再包含嵌套子查询
```
select panthera_10.panthera_1 as s_grade from (select panthera_1, panthera_4, panthera_6, s_empname, s_city from (select s_grade as panthera_1, s_city as panthera_4, s_empname as panthera_6, s_empname as s_empname, s_city as s_city from staff) panthera_14 left outer join (select panthera_16.panthera_7 as panthera_7, panthera_16.panthera_8 as panthera_8, panthera_16.panthera_9 as panthera_9, panthera_16.panthera_12 as panthera_12, panthera_16.panthera_13 as panthera_13 from (select panthera_0.panthera_1 as panthera_7, panthera_0.panthera_4 as panthera_8, panthera_0.panthera_6 as panthera_9, panthera_0.s_empname as panthera_12, panthera_0.s_city as panthera_13 from (select s_grade as panthera_1, s_city as panthera_4, s_empname as panthera_6, s_empname, s_city from staff) panthera_0 left semi join (select p_city as panthera_3, p_pname as panthera_5 from proj) panthera_2 on (panthera_0.panthera_4 = panthera_2.panthera_3) and (panthera_0.panthera_6 = panthera_2.panthera_5) where true) panthera_16 group by panthera_16.panthera_7, panthera_16.panthera_8, panthera_16.panthera_9, panthera_16.panthera_12, panthera_16.panthera_13) panthera_15 on ((((panthera_14.panthera_1 &lt;=&gt; panthera_15.panthera_7) and (panthera_14.panthera_4 &lt;=&gt; panthera_15.panthera_8)) and (panthera_14.panthera_6 &lt;=&gt; panthera_15.panthera_9)) and (panthera_14.s_empname &lt;=&gt; panthera_15.panthera_12)) and (panthera_14.s_city &lt;=&gt; panthera_15.panthera_13) where ((((panthera_15.panthera_7 is null) and (panthera_15.panthera_8 is null)) and (panthera_15.panthera_9 is null)) and (panthera_15.panthera_12 is null)) and (panthera_15.panthera_13 is null)) panthera_10 ;
```
通过可视化工具将上面两条SQL的语法树展示出来是这样的。
<img src="https://static001.geekbang.org/resource/image/2e/2b/2ebce9da37fff01e5701342699b69f2b.png" alt="">
这是原始的SQL抽象语法树。
<img src="https://static001.geekbang.org/resource/image/3a/15/3aafd8cf731eb6fd5b0e125847084f15.png" alt="">
这是等价转换后的抽象语法树,内容太多被压缩得无法看清,不过你可以感受一下(笑)。
那么在程序设计上如何实现这样复杂的语法转换呢当时Panthera项目组合使用了几种经典的设计模式每个语法点被封装到一个类里去处理每个类通常不过几十行代码这样整个程序非常简单、清爽。如果在测试过程中遇到不支持的语法点只需为这个语法点新增加一个类即可团队协作与代码维护非常容易。
使用装饰模式的语法等价转换类的构造Panthera每增加一种新的语法转换能力只需要开发一个新的Transformer类然后添加到下面的构造函数代码里即可。
```
private static SqlASTTransformer tf =
new RedundantSelectGroupItemTransformer(
new DistinctTransformer(
new GroupElementNormalizeTransformer(
new PrepareQueryInfoTransformer(
new OrderByTransformer(
new OrderByFunctionTransformer(
new MinusIntersectTransformer(
new PrepareQueryInfoTransformer(
new UnionTransformer(
new Leftsemi2LeftJoinTransformer(
new CountAsteriskPositionTransformer(
new FilterInwardTransformer(
//use leftJoin method to handle not exists for correlated
new CrossJoinTransformer(
new PrepareQueryInfoTransformer(
new SubQUnnestTransformer(
new PrepareFilterBlockTransformer(
new PrepareQueryInfoTransformer(
new TopLevelUnionTransformer(
new FilterBlockAdjustTransformer(
new PrepareFilterBlockTransformer(
new ExpandAsteriskTransformer(
new PrepareQueryInfoTransformer(
new CrossJoinTransformer(
new PrepareQueryInfoTransformer(
new ConditionStructTransformer(
new MultipleTableSelectTransformer(
new WhereConditionOptimizationTransformer(
new PrepareQueryInfoTransformer(
new InTransformer(
new TopLevelUnionTransformer(
new MinusIntersectTransformer(
new NaturalJoinTransformer(
new OrderByNotInSelectListTransformer(
new RowNumTransformer(
new BetweenTransformer(
new UsingTransformer(
new SchemaDotTableTransformer(
new NothingTransformer())))))))))))))))))))))))))))))))))))));
```
而在具体的Transformer类中则使用组合模式对抽象语法树AST进行遍历以下为Between语法节点的遍历。我们看到使用组合模式进行树的遍历不需要用递归算法因为递归的特性已经隐藏在树的结构里面了。
```
@Override
protected void transform(CommonTree tree, TranslateContext context) throws SqlXlateException {
tf.transformAST(tree, context);
trans(tree, context);
}
void trans(CommonTree tree, TranslateContext context) {
// deep firstly
for (int i = 0; i &lt; tree.getChildCount(); i++) {
trans((CommonTree) (tree.getChild(i)), context);
}
if (tree.getType() == PantheraExpParser.SQL92_RESERVED_BETWEEN) {
transBetween(false, tree, context);
}
if (tree.getType() == PantheraExpParser.NOT_BETWEEN) {
transBetween(true, tree, context);
}
}
```
将等价转换后的抽象语法树AST再进一步转换成Hive格式的抽象语法树就可以交给Hive的语义分析器去处理了从而也就实现了对标准SQL的支持。
当时Facebook为了证明Hive对数据仓库的支持Facebook的工程师手工将TPC-H的测试SQL转换成Hive QL我们将这些手工Hive QL和Panthera进行对比测试两者性能各有所长总体上不相上下这说明Panthera自动进行语法分析和转换的效率还是不错的。
PantheraASE和Facebook手工Hive QL对比测试结果如下。
<img src="https://static001.geekbang.org/resource/image/c1/6f/c1866cede6eb563481d917b0f06b176f.png" alt="">
事实上标准SQL语法集的语法点非常多我们经过近两年的努力绞尽脑汁进行各种关系代数等价变形依然没有全部适配所有的标准SQL语法。
我在开发Panthera的时候查阅了很多关于SQL和数据库的网站和文档发现在我们耳熟能详的那些主流数据库之外还有很多名不见经传的数据库此外还有大量的关于SQL的语法解析器、测试数据和脚本集、各种周边工具。我们经常看到的MySQL、Oracle这些产品仅仅是整个数据库生态体系的冰山一角。还有很多优秀的数据库在竞争中落了下风、默默无闻而更多的支撑起这些优秀数据库的论文、工具非业内人士几乎闻所未闻。
这个认识给了我很大触动,我一直期待我们中国人能开发出自己的操作系统、数据库、编程语言,也看到有很多人前仆后继投入其中。但是这么多年过去了,大部分努力惨淡收场,小部分结果沦落为笑柄,成为人们饭后的谈资。我曾经思考过,为什么会这样?
开发Panthera之后我想我们国家虽然从事软件开发的人数很多但是绝大多数都在做最顶层的应用开发底层技术开发和研究的人太少做出来的成果也太少。我们在一个缺乏周边生态体系、没有足够的竞争产品的情况下就想直接开发出自己有影响力的操作系统、数据库、编程语言无异于想在沙漠里种出几棵参天大树。
不过,庆幸的是,我也看到越来越多有全球影响力的底层技术产品中出现中国人的身影,小草已经在默默生长,假以时日,料想必有大树出现。
今天我讲的是一个SQL引擎是如何设计出来的也许在你的工作几乎不可能去开发SQL引擎但是了解这些基础的知识了解一些设计的技巧对你用好数据库开发更加灵活、有弹性的系统也会很有帮助。
## 思考题
SQL注入是一种常见的Web攻击手段如下图所示攻击者在HTTP请求中注入恶意SQL命令drop table users;服务器用请求参数构造数据库SQL命令时恶意SQL被一起构造并在数据库中执行。
<img src="https://static001.geekbang.org/resource/image/8c/4f/8c92076fc8b4005ce075734e9641cd4f.png" alt="">
但是JDBC的PrepareStatement可以阻止SQL注入攻击MyBatis之类的ORM框架也可以阻止SQL注入请从数据库引擎的工作机制解释PrepareStatement和MyBatis的防注入攻击的原理。
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,105 @@
<audio id="audio" title="19 | Spark的性能优化案例分析" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a6/9b/a63eaccdb5c467197624bf83ab20cf9b.mp3"></audio>
我们知道现在最主流的大数据技术几乎都是开源的产品不管是Hadoop这样的大数据存储与计算产品还是Hive、Spark SQL这样的大数据仓库又或者Storm、Flink这样的大数据流计算产品还有Mahout、MLlib这样的大数据机器学习算法库它们都来自开源社区。所以我们在使用大数据、学习大数据的过程中肯定少不了要和开源社区打交道。
我在Intel工作期间主要工作就是参与Apache开源社区的大数据项目开发其实上一期我讲的Panthera最初也是准备为Hive项目增强标准SQL处理能力而开发但是因为和Apache Hive项目管理方在开发理念上的冲突最终选择独立开源。后来我又参与了Apache Spark的开发为Spark源代码提交了一些性能优化的Patch。我想通过专栏两期的内容具体介绍一下如何参与Apache这样开源社区的软件开发如何进行软件性能优化以及我在Apache Spark源码上做的一些优化实践。
一方面我希望你能借此更深入、系统地了解软件性能优化另一方面也可以更深入了解Spark的一些运行机制同时也可以了解Apache开源社区的运作模式。因为我们在使用各类大数据产品的时候一定会遇到各种问题想要解决这些问题你可以直接到官方的开源社区去求助并寻找答案。在使用过程中如果这些大数据产品不能满足你的需求你可以阅读源代码并直接对源代码进行修改和优化。因为你在实践过程中产生的需求可能其他人也会有你可以将你修改的源代码提交到开源社区请求合并到发布版本上供全世界开发者使用。这也是开源最大的魅力。
你可能已经注意到作为软件开发人员日常我们使用的大量软件基本上全部来自美国不管是免费开源的Linux、Java、Hadoop、PHP、Tomcat、Spring还是商业收费的Windows、WebLogic、Oracle大到编程语言、操作系统、数据库小到编程框架、日志组件几乎全部来自美国。
软件,特别是开源软件,是没有国界的,属于全人类的技术财富。但是,我觉得我们还要承认,中美之间的技术差距真的很惊人。在当前这样一个中美贸易摩擦不断的背景下,难免让人有些忧虑。缩短这种技术差距也许非一日之功,但是更多的中国工程师参与到开源软件的开发中,让中国在世界软件技术领域获得很多影响力,也许是当下就可以迈出的一步。
## Apache开源社区的组织和参与方式
Apache是一个以基金会方式运作的非盈利开源软件组织旗下有超过一百个各类开源软件其中不乏Apache、Tomcat、Kafka等知名的开源软件当然也包括Hadoop、Spark等最主流的大数据开源软件。
Apache每个项目的管理团队叫项目管理委员会PMC一般由项目发起者、核心开发者、Apache基金会指定的资深导师组成主导整个项目的发展。此外项目的主要开发者叫作committer是指有将代码合并到主干代码权限的开发者而其他没有代码合并权限的开发者叫作contributor。
一般说来参与Apache开源产品开发先从contributor做起。一般的流程是从GitHub项目仓库fork代码到自己的仓库在自己仓库修改代码然后创建pull request提交到Spark仓库后如果有committer认为没问题就merge到Spark主干代码里。
一旦你为某个Apache项目提交的代码被merge到代码主干你就可以宣称自己是这个项目的contributor了甚至可以写入自己的简历。如果能持续提交高质量的代码甚至直接负责某个模块你就有可能被邀请成为committer会拥有一个apache.org后缀的邮箱。
当然我希望你提交的是有质量的代码而不仅仅是对代码注释里某个单词拼写错误进行修改然后就号称自己是某个著名开源项目的contributor了。虽然修改注释也是有价值的但是如果你的pull request总是修改注释的拼写错误很难被认为是一个严肃的开发者。
除了ApacheLinux、以太坊等开源基金会的组织和运作方式也都类似。就我观察最近几年越来越多来自中国的开发者开始活跃在各种重要的开源软件社区里我希望你也成为其中一员。
## 软件性能优化
在熟悉开源社区的运作方式后,接下来我们就可以考虑开始进行性能优化了。但在上手之前,你是否清楚所谓性能优化具体要做些什么呢?
关于软件性能优化,有个著名的**论断**。
1.你不能优化一个没有经过性能测试的软件。
2.你不能优化一个你不了解其架构设计的软件。
不知你是否听过这个论断,我来解释一下。
如果没有性能测试,那么你就不会知道当前软件的主要性能指标有哪些。通常来说,软件的主要性能指标包括:
<li>
响应时间:完成一次任务(请求)花费的时间。
</li>
<li>
并发数:同时处理的任务数(请求数)。
</li>
<li>
吞吐量:单位时间完成的任务数(请求数、事务数、查询数……)。
</li>
<li>
性能计数器System Load线程数进程数CPU、内存、磁盘、网络使用率等。
</li>
如果没有性能指标,我们也就不清楚软件性能的瓶颈,优化前和优化后也是无从对比。这样的优化工作只能是主观臆断:别人这样做说性能好,我们也这样优化。
而如果不了解软件的架构设计,你可能根本无从判断性能瓶颈产生的根源,也不知道该从哪里优化。
所以性能优化的一般过程是:
1.做性能测试,分析性能状况和瓶颈点。
2.针对软件架构设计进行分析,寻找导致性能问题的原因。
3.修改相关代码和架构,进行性能优化。
4.做性能测试,对比是否提升性能,并寻找下一个性能瓶颈。
## 大数据软件性能优化
在大数据使用、开发过程的性能优化一般可以从以下角度着手进行。
**1. SQL语句优化**。使用关系数据库的时候SQL优化是数据库优化的重要手段因为实现同样功能但是不同的SQL写法可能带来的性能差距是数量级的。我们知道在大数据分析时由于数据量规模巨大所以SQL语句写法引起的性能差距就更加巨大。典型的就是Hive的MapJoin语法如果join的一张表比较小比如只有几MB那么就可以用MapJoin进行连接Hive会将这张小表当作Cache数据全部加载到所有的Map任务中在Map阶段完成join操作无需shuffle。
**2. 数据倾斜处理**。数据倾斜是指当两张表进行join的时候其中一张表join的某个字段值对应的数据行数特别多那么在shuffle的时候这个字段值Key对应的所有记录都会被partition到同一个Reduce任务导致这个任务长时间无法完成。淘宝的产品经理曾经讲过一个案例他想把用户日志和用户表通过用户ID进行join但是日志表有几亿条记录的用户ID是nullHive把null当作一个字段值shuffle到同一个Reduce结果这个Reduce跑了两天也没跑完SQL当然也执行不完。像这种情况的数据倾斜因为null字段没有意义所以可以在where条件里加一个userID != null过滤掉就可以了。
**3. MapReduce、Spark代码优化**。了解MapReduce和Spark的工作原理了解要处理的数据的特点了解要计算的目标设计合理的代码处理逻辑使用良好的编程方法开发大数据应用是大数据应用性能优化的重要手段也是大数据开发工程师的重要职责。
**4. 配置参数优化**。根据公司数据特点为部署的大数据产品以及运行的作业选择合适的配置参数是公司大数据平台性能优化最主要的手段也是大数据运维工程师的主要职责。比如Yarn的每个Container包含的CPU个数和内存数目、HDFS数据块的大小和复制数等每个大数据产品都有很多配置参数这些参数会对大数据运行时的性能产生重要影响。
**5. 大数据开源软件代码优化**。曾经和杭州某个SaaS公司的大数据工程师聊天他们的大数据团队只有5、6个人但是在使用开源大数据产品的时候遇到问题都是直接修改Hadoop、Spark、Sqoop这些产品的代码。修改源代码进行性能优化的方法虽然比较激进但是对于掌控自己公司的大数据平台来说效果可能是最好的。
## Spark性能优化
有了上面这些性能优化原则和过程我们在了解Spark架构和代码的基础上就可以进行性能优化了。
关于性能测试我们使用的是Intel为某视频网站编写的一个基于Spark的关系图谱计算程序用于计算视频的级联关系。我们使用5台服务器对样例数据进行性能测试程序运行总体性能如下图。
<img src="https://static001.geekbang.org/resource/image/2b/d0/2bf9e431bbd543165588a111513567d0.png" alt="">
这张图我在专栏Spark架构原理分析过。我们将4台Worker服务器上主要计算资源利用率指标和这张图各个job与stage的时间点结合就可以看到不同运行阶段的性能指标如何从而发现性能瓶颈。
<img src="https://static001.geekbang.org/resource/image/7a/cc/7af885b0492aa68ffbe05bee7e04cdcc.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/2f/12/2f8f43d795247f575e953a027070d012.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/86/56/86cb0d0beea4178cbf5f7031fec7a956.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/09/33/093c888a13a58802413f9d1e2eafcb33.png" alt="">
从这些图我们可以看到CPU、内存、网络、磁盘这四种主要计算资源的使用和Spark的计算阶段密切相关。后面我主要通过这些图来分析Spark的性能问题进而寻找问题根源并进一步进行性能优化。
下一期我们一起来看几个Spark性能优化的案例进一步了解Spark的工作原理以及性能优化的具体实践。
## 思考题
如果性能测试发现网卡是整个系统的瓶颈程序运行过程中网卡达到了最大I/O能力整个系统经常在等待网卡的数据传输请问你有什么性能优化建议呢
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,149 @@
<audio id="audio" title="20 | Spark的性能优化案例分析" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fe/6b/fe6d2b587455604761ef6a1f6963bc6b.mp3"></audio>
上一期我讲了软件性能优化必须经过进行性能测试并在了解软件架构和技术的基础上进行。今天我们通过几个Spark性能优化的案例看一看所讲的性能优化原则如何落地。如果你忘记了性能优化的原则可以返回上一期复习一下。
基于软件性能优化原则和Spark的特点Spark性能优化可以分解为下面几步。
1.性能测试观察Spark性能特性和资源CPU、Memory、Disk、Net利用情况。
2.分析、寻找资源瓶颈。
3.分析系统架构、代码,发现资源利用关键所在,思考优化策略。
4.代码、架构、基础设施调优,优化、平衡资源利用。
5.性能测试,观察系统性能特性,是否达到优化目的,以及寻找下一个瓶颈点。
下面我们一起进入详细的案例分析希望通过这几个案例可以帮助你更好地理解Spark的原理以及性能优化如何实践落地希望能对你有所启发。
## 案例1Spark任务文件初始化调优
首先进行性能测试发现这个视频图谱N度级联关系应用分为5个job最后一个job为保存结果到HDFS其余job为同样计算过程的反复迭代。但是发现第一个job比其他job又多了个计算阶段stage如图中红圈所示。
<img src="https://static001.geekbang.org/resource/image/6f/88/6fd436e3c6c11106cd7754792e78ee88.png" alt="">
通过阅读程序代码发现第一个job需要初始化一个空数组从而产生了一个stage但是这个stage在性能测试结果上显示花费了14秒的时间远远超出合理的预期范围。同时发现这段时间网络通信也有一定开销事实上只是内存数据初始化代码上看不出需要进行网络通信的地方。下图是其中一台计算节点的通信开销发现在第一个stage写通信操作几乎没有读通信操作大约每秒几十MB的传输速率。
<img src="https://static001.geekbang.org/resource/image/05/58/054abfc46ca040d3db8c441822a86558.png" alt="">
分析Spark运行日志发现这个stage主要花费时间并不是处理应用的计算逻辑而是在从Driver进程下载应用执行代码。前面说过Spark和MapReduce都是通过移动计算程序到数据所在的服务器节点从而节省数据传输的网络通信开销并进行分布式计算即移动计算比移动数据更划算而移动计算程序就是在这个阶段进行。
<img src="https://static001.geekbang.org/resource/image/f8/18/f8828271641cb854a0e1e79b75ab8218.png" alt="">
这个视频关系图谱计算程序因为依赖一个第三方的程序包整个计算程序打包后大小超过17MB这个17MB的JAR包需要部署到所有计算服务器上即Worker节点上。但是只传输17MB的数据不可能花费这么多时间啊
进一步分析Spark日志和代码后发现每个计算节点上会启动多个Executor进程进行计算而Spark的策略是每个Executor进程自己去下载应用程序JAR包当时每台机器启动了30个Executor进程这样就是4×30=120个进程下载而Driver进程所在机器是一块千兆网卡导致将这些数据传输完成花费了14秒的时间。
发现问题以后解决办法就显而易见了。同一台服务器上的多个Executor进程不必每个都通过网络下载应用程序只需要一个进程下载到本地后其他进程将这个文件copy到自己的工作路径就可以了。
<img src="https://static001.geekbang.org/resource/image/82/f0/823fb2e270b7031542edeafd088d06f0.jpg" alt="">
这段代码有个技术实现细节需要关注,就是多个进程同时去下载程序包的时候,如何保证只有一个进程去下载,而其他进程阻塞等待,也就是进程间的同步问题。
解决办法是使用了一个本地文件作为进程间同步的锁,只有获得文件锁的进程才去下载,其他进程得不到文件锁,就阻塞等待,阻塞结束后,检查本地程序文件是否已经生成。
这个优化实测效果良好第一个stage从14秒下降到不足1秒效果显著。
<img src="https://static001.geekbang.org/resource/image/ea/32/ea59ae5b5e70304ac6f1fcf1bacd3332.png" alt="">
这个案例的具体代码你可以参考:<br>
[https://github.com/apache/spark/pull/1616](https://github.com/apache/spark/pull/1616)
## 案例2Spark任务调度优化
继续前面的性能测试看看有没有新的性能瓶颈以及性能指标不合理的地方。我们将4台Worker机器的CPU使用率进行对比分析发现CPU使用率有些蹊跷的地方。
<img src="https://static001.geekbang.org/resource/image/49/38/498e4d3d7aa0c23b6fc5807eb87b7638.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/6e/64/6eb9b6f7ff05a9d521035898f830d964.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/b6/00/b6e5868d6af8ffbd3ddc99a0ad9e4b00.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/f8/5b/f82efd934ed0e1992cb7bb9460b9175b.png" alt="">
从图中看到在第一个job的第二个阶段第三台机器的CPU使用率和其他机器明显不同也就是说计算资源利用不均衡**这种有忙有闲的资源分配方式通常会引起性能问题**。
分析Spark运行日志和Spark源代码发现当有空闲计算资源的Worker节点向Driver注册的时候就会触发Spark的任务分配分配的时候使用轮询方式每个Worker都会轮流分配任务保证任务分配均衡每个服务器都能领到一部分任务。但是为什么实测的结果却是在第二个stage只有一个Worker服务器领了任务而其他服务器没有任何任务可以执行
<img src="https://static001.geekbang.org/resource/image/4c/63/4c69cb903334886ec12dc98b4af8b563.png" alt="">
进一步分析日志发现Worker节点向Driver注册有先有后先注册的Worker开始领取任务如果需要执行的任务数小于Worker提供的计算单元数就会出现一个Worker领走所有任务的情况。
而第一个job的第二个stage刚好是这样的情况demo数据量不大按照HDFS默认的Block大小只有17个Block第二个stage就是加载这17个Block进行初始迭代计算只需要17个计算任务就能完成所以当第三台服务器先于其他三台服务器向Driver注册的时候触发Driver的任务分配领走了所有17个任务。
同时为了避免这种一个Worker先注册先领走全部任务的情况我们考虑的一个优化策略是增加一个配置项只有注册的计算资源数达到一定比例才开始分配任务默认值是0.8。
```
spark.scheduler.minRegisteredResourcesRatio = 0.8
```
为了避免注册计算资源达不到期望资源比例而无法开始分配任务,在启动任务执行时,又增加了一个配置项,也就是最小等待时间,超过最小等待时间(秒),不管是否达到注册比例,都开始分配任务。
```
spark.scheduler.maxRegisteredResourcesWaitingTime = 3
```
启用这两个配置项后第二个stage的任务被均匀分配到4个Worker服务器上执行时间缩短了1.32倍。而4台Worker服务器的CPU利用率也变得很均衡了。
<img src="https://static001.geekbang.org/resource/image/80/c5/804e83b440d287343c49febe58b8c5c5.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/2a/c1/2a005427e41e5e78bb15d08c39f057c1.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/0c/4a/0ce1eab6a0d7800c80d8312b23cb854a.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/b5/70/b5557db2bcfad01dc9d6e5506d77ea70.png" alt="">
这个案例的具体代码你可以参考:[https://github.com/apache/spark/pull/900](https://github.com/apache/spark/pull/900)<br>
[https://github.com/apache/spark/pull/1525](https://github.com/apache/spark/pull/1525)
## 案例3Spark应用配置优化
看案例2的几张CPU利用率的图我们还发现所有4个Worker服务器的CPU利用率最大只能达到60%多一点。例如下图绿色部分就是CPU空闲。
<img src="https://static001.geekbang.org/resource/image/b5/70/b5557db2bcfad01dc9d6e5506d77ea70.png" alt="">
这种资源利用瓶颈的分析无需分析Spark日志和源代码根据Spark的工作原理稍加思考就可以发现当时使用的这些服务器的CPU的核心数是48核而应用配置的最大Executor数目是120每台服务器30个任务虽然30个任务在每个CPU核上都100%运行但是总的CPU使用率仍只有60%多。
具体优化也很简单设置应用启动参数的Executor数为48×4=192即可。
## 案例4操作系统配置优化
在性能测试过程中发现当使用不同服务器的时候CPU资源利用情况也不同某些服务器的CPU处于sys态即系统态运行的占比非常高如下图所示。
<img src="https://static001.geekbang.org/resource/image/2e/c7/2e95c4c900c6afb7918e9efa6341bac7.png" alt="">
图中紫色为CPU处于sys态某些时候sys态占了CPU总使用率的近80%这个比例显然是不合理的表示虽然CPU很忙但是没有执行用户计算而是在执行操作系统的计算。
那么操作系统究竟在忙什么占用了这么多CPU时间通过跟踪Linux内核执行指令发现这些sys态的执行指令和Linux的配置参数transparent huge pages有关。
当transparent huge pages打开的时候sys态CPU消耗就会增加而不同Linux版本的transparent huge pages默认是否打开是不同的对于默认打开transparent huge pages的Linux执行下面的指令关闭transparent huge pages。
```
echo never &gt; /sys/kernel/mm/transparent_hugepage/enabled
echo never &gt; /sys/kernel/mm/ transparent_hugepage/defrag
```
关闭以后对比前面的CPU消耗sys占比明显下降总的应用耗时也有明显下降。
<img src="https://static001.geekbang.org/resource/image/24/94/24b6e43e406ac4eae3f44a94ddd2fb94.png" alt="">
## 案例5硬件优化
分析网卡的资源消耗发现网络通信是性能的瓶颈对整个应用的影响非常明显。比如在第二个、第三个job网络通信消耗长达50秒的时间网络读写通信都达到了网卡的最大吞吐能力整个集群都在等待网络传输。
<img src="https://static001.geekbang.org/resource/image/7d/84/7ddc70b5388ebc8a0b05959cbbf6f384.png" alt="">
我们知道千兆网卡的最大传输速率是每秒125MB这样的速率和CPU内存固然没法比而虽然比单个磁盘快一些但是服务器磁盘是8块磁盘组成的阵列总的磁盘吞吐量依然碾压千兆网卡因此网卡传输速率的瓶颈就成为整个系统的性能瓶颈。
而优化手段其实很简单粗暴,就是升级网卡使用万兆网卡。
<img src="https://static001.geekbang.org/resource/image/44/0e/4495bc09fde62c856c2ff4316092c20e.png" alt="">
硬件优化的效果非常明显以前需要50多秒的网络通信时间缩短为10秒左右。从性能曲线上看网络通信在刚刚触及网卡最大传输速率的时候就完成了传输总的计算时间缩短了近100秒。
## 小结
一般说来大数据软件性能优化会涉及硬件、操作系统、大数据产品及其配置、应用程序开发和部署几个方面。当性能不能满足需求的时候先看看各项性能指标是否合理如果资源没有全面利用那么可能是配置不合理或者大数据应用程序包括SQL语句需要优化如果某项资源利用已经达到极限那么就要具体来分析是集群资源不足需要增加新的硬件服务器还是需要对某项硬件、操作系统或是JVM甚至是对大数据产品源代码进行调优。
## 思考题
关于目前的主要大数据产品你在学习、使用过程中从SQL写法、应用编程、参数配置到大数据产品自身的架构原理与源码实现你有没有发现有哪些可以进行性能优化的地方
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,69 @@
<audio id="audio" title="21 | 从阿里内部产品看海量数据处理系统的设计Doris的立项" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ca/78/cab1834b7604435e435cdf128244d278.mp3"></audio>
从今天开始我会分两期内容来讨论阿里巴巴的一个海量数据处理系统的设计这个系统的名字叫Doris它是阿里巴巴的一个内部产品。前面专栏曾经提到过2010年前后是各种NoSQL系统爆发的一个时期各种开源NoSQL在这个时期发布出来当时阿里巴巴也开发了自己的NoSQL系统Doris。
Doris的设计目标是支持海量的KV结构的数据存储访问速度和可靠性要高于当时主流的NoSQL数据库系统要易于维护和伸缩。和当时众多NoSQL系统相比Doris在架构设计上颇具独特性路由算法、失效转移、集群扩容也有自己的创新之处并成功申请三项技术专利。
**在我们开始讨论Doris项目前我想先跟你聊聊大公司是如何看待内部技术产品这件事**。事实上,阿里巴巴内部底层技术产品的研发决策思路也颇有值得借鉴之处,你可以吸收其中好的经验,并把它转化到你所开发的产品上。
我们知道一家互联网公司主要靠自己的互联网产品盈利比如阿里巴巴主要靠淘宝、天猫、阿里巴巴B2B网站等产品赚钱而公司的工程师主要也是开发这些产品但是这些产品通常都需要处理海量的用户请求和大规模的数据存储所以在系统底层通常用到很多基础技术产品比如分布式缓存、分布式消息队列、分布式服务框架、分布式数据库等。这些基础技术产品可以选择开源技术产品也可以选择自己研发。自己研发的优点是可以针对业务场景进行定制开发同时培养提高自己工程师的技术实力缺点是投入大、风险高。
通常公司到了一定规模,都会开始逐渐自主研发一些基础技术产品,既可以提升自己的产品研发能力,又可以提高自身在业界的地位,吸引更优秀的人才并提高竞争门槛,形成自己的竞争壁垒。
但是公司的资源毕竟是有限的,主要的资源又投入到业务产品开发去了,那剩下的资源到底应该投入到哪里呢?这需要形成公司内部一套竞争策略,以使优秀的项目能够得到资源。
另一方面,对工程师而言,业务产品的开发技术难度相对较低,如果要想更快提高自己的技术水平,去开发基础技术产品更能得到提升和锻炼,所以优秀的工程师更愿意去开发有难度有挑战的创新性基础技术产品,而不是去开发那些千篇一律的业务产品。
这样,在工程师和公司之间就形成了一种博弈:工程师想要开发基础技术产品,但是必须要得到公司管理层的支持;管理层资源有限,只愿意支持开发那些对业务有价值、技术有创新、风险比较低的基础技术产品。
所以事情就变成工程师需要说服公司管理层,想要做的就是对业务有价值、技术有创新、风险比较低的基础技术产品;而管理层则要从这些竞争者中选出最优秀的项目。
通过这种博弈,公司的资源会凝聚到最有价值的技术产品上,优秀的工程师也会被吸引到这些项目上,最后实现了公司价值和员工价值的统一和双赢。
下面我们进入正题我会拿出当时Doris开发立项时说服管理层用的PPT向你解读个中技巧以及Doris的创新设计。 需要提醒你的是你在学习这两期专栏时可以试着想象一个场景假设是在Doris项目的立项启动会今天你是老板看看你最关注一个项目的哪些技术指标又或者你是Doris项目的工程师可以想想哪些指标是老板关注的并且从技术上是可以实现的。这样把自己带入到一个角色中对于你更好理解这个数据处理系统很有帮助。
<img src="https://static001.geekbang.org/resource/image/60/05/604b240c9adaff2d84e9603d96e54905.png" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/05/b2/055f0ba8cfd561e306c7345e6c0cc7b2.png" alt="">
PPT开篇就是当前现状当时阿里巴巴没有统一的大数据NoSQL解决方案有的产品是自己在业务代码中实现数据分区逻辑从而实现海量KV数据的存储访问。这样做的主要问题有
<li>
开发困难。程序员在开发时要知道自己存储的数据在哪台服务器。
</li>
<li>
运维困难。增加服务器的时候,需要开发配合,故障的时候也很难排查问题。
</li>
现状一定是有问题的,需要我们去解决。有没有现成的解决方案?有,但是现成的方案也有问题,所以我们必须要自己开发一套系统才能解决问题。这样,后面想做的一切才能顺理成章。
当你想做一个新东西,它必须要能解决当前的问题,这是人类社会的基本运行规律。如果当前没有问题呢?你相信我,这个世界不可能没有问题的,重要的是你要能发现问题。就像你做的东西将来也一定会有问题,因为现在的产品在将来一定会落伍,但那已经不再是你的问题。
**技术只是手段,技术不落在正确的问题上一点用也没有,而落在错误的问题上甚至会搬起石头砸了自己的脚**。而什么是正确的问题,你需要自己去思考和发现。
<img src="https://static001.geekbang.org/resource/image/29/fd/2968c50bd69d1d7574d4eec40207b8fd.png" alt="">
前一页说完了当前存在的问题引出了我们必须要自己开发一个海量数据处理系统这一页就要说明这个产品的定位也就是“海量分布式透明KV存储引擎”这个引擎能够实现的业务价值就是能够支撑阿里巴巴未来各个主要产品的海量数据存储访问需求。
这两页是整个PPT的灵魂管理层如果对第一页提出的问题不认可又对第二页产品要实现的价值不以为然那基本上这个项目也就凉凉了。
如果到这里没有问题,得到认可,那下一步就要趁热打铁,**突出项目的创新和特点**。
<img src="https://static001.geekbang.org/resource/image/a5/58/a50720fdba66389dd7d75d2871e75f58.png" alt="">
产品的功能目标和非功能目标要清晰、要有亮点和业界主流产品比要有竞争优势用红色字体标出要更贴合公司的业务场景。Doris的主要功能目标是提供KV存储非功能目标包括在运维上要实现集群易于管理具有自我监控和自动化运维功能不需要专业运维人员维护要支持集群线性伸缩平滑扩容具有自动容错和故障转移的高可用性高并发情况下快速响应的高性能性支持未来功能持续升级的可扩展性。
<img src="https://static001.geekbang.org/resource/image/2c/43/2c86070b16950dd1e3976a9e20e42d43.png" alt="">
技术指标也要亮眼至少不能明显低于当前主流同类产品的指标。当时Doris根据阿里巴巴的内部使用需求场景支持所有的B2B业务的KV存储因此设计目标是未来部署一个10010000台服务器的集群规模并不支持无限伸缩。如果前面说过别的产品的缺点这里也要对应说明自己强在哪里。
设计指标的设定,既不能低,如果比目前主流同类产品的指标还要差,自己再开发这样的产品就没有意义;也不能太高,如果设定太高,过度承诺,让老板、用户对你未来交付的产品抱有太高的期望,将来稍有不慎,无法达到期望,不但对产品的发展造成不良影响,甚至大家对你的人品都会产生怀疑。做好对别人的期望管理,让大家对你既充满期待,又不至于不切实际,不但对你的职业发展大有帮助,应用到生活中也会获益良多。
到这里问题也说了、方向也有了、设计指标也定了究竟能不能开发出满足设计目标的产品就看后面的PPT把核心架构和关键设计讲清楚要证明自己有把握、有能力做到。
到底如何证明自己能做到,且听下回分解。
## 思考题
在你的工作环境中,哪些工作是更有技术挑战和难度的工作?现在是否有人在做?如果你想做,该如何说服上司支持你?
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,120 @@
<audio id="audio" title="22 | 从阿里内部产品看海量数据处理系统的设计(下):架构与创新" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f9/9c/f97451b08b0f9d3a2e8624e3c18a219c.mp3"></audio>
上一期Doris提出了目前阿里巴巴海量KV存储方面的问题给出了Doris的业务价值、设计目标和技术指标。但是Doris项目组还必须证明自己有已经经过论证的架构技术方案可以实现前面设定的目标立项后可以迅速启动执行不需要再去摸索尝试风险可以把控。
因此PPT后面的内容主要就是阐述Doris的架构方案和创新设计。
<img src="https://static001.geekbang.org/resource/image/eb/5b/eb949889c4fe1823ced433ea59123a5b.png" alt="">
Doris是一种支持Key、Value数据结构的分布式存储系统核心要解决的问题是分布式路由、分布式集群伸缩、分布式数据冗余与失效转移。所以Doris把分布式存储系统很重要的一块也就是数据存储部分转移出去使用第三方软件完成当时选择Berkeley DB作为Doris的底层存储StoreDoris自己专注于分布式技术实现。
Doris的主要访问模型是应用程序KV Client启动后连接控制中心Administration从控制中心获得整个Doris集群的服务器部署信息及路由算法Client使用Key作为参数进行路由计算计算得到集群中某些服务器作为当前Key、Value数据存储的服务器节点然后KV Client使用自定义的通信协议将数据和命令传输给服务器上的Data Server组件DataServer再调用本地的Berkeley DB将数据存储到本地磁盘。
Doris的核心技术就是这个架构模型上创新性地实现了自己独特的**分区路由算法、失效转移策略、集群伸缩设计方案**。并在项目开发过程中,将这个三个技术创新申请了技术专利。下面我们重点看下这三个技术创新。
## 分区路由算法
<img src="https://static001.geekbang.org/resource/image/01/d6/019cd0d87daf9d356bd7326cd2a928d6.png" alt="">
Doris采用一种基于虚拟节点的分区路由算法Key使用余数Hash算法计算得到虚拟节点下标。
```
虚拟节点下标 = hash(md5(key)) mod 虚拟节点个数
```
虚拟节点和物理服务器节点之间计算建立一个映射关系通过映射关系查找实际要访问的物理服务器IP地址。
路由算法在初始化的时候就预先设立一个较大的数字比如100000当存储服务器集群需要伸缩的时候要增加一个服务器虚拟节点和下标计算算法不变仅仅调整虚拟节点和物理服务器节点的映射关系就可以了如PPT中图2所示。
这种基于虚拟节点的分区路由算法相对于传统的一致性Hash路由算法可以获得更好的数据负载均衡即数据在各个服务器上的存储分布更加均衡。在集群伸缩、增加服务器的时候可以做到更少迁移数据。在实践中这种算法的一个更大优势是如果将物理存储的文件系统和虚拟节点关联即一个虚拟节点对应一个物理存储文件那么当集群扩容进行数据迁移的时候就可以以文件为单位进行数据拷贝这样迁移速度和运维成本都非常低。
这个基于虚拟节点的分区路由算法的关键难点是,如何计算虚拟节点与物理节点的映射关系,特别是在增加服务器的时候,如何重新计算这个映射关系,使新的映射关系依然处于负载均衡的状态,也就是每个物理节点映射的虚拟节点个数差不太多相同。
<img src="https://static001.geekbang.org/resource/image/0a/b8/0a9dde28106a7b279048d755390638b8.png" alt="">
项目组抽象了一个数学公式完成映射关系的计算你可以看上面PPT示例。
## 失效转移策略
在前面在技术指标上曾经承诺Doris的可用性为99.997%,保证数据可用性的策略主要是数据存储冗余备份和数据访问失效转移。
我们先看下Doris如何实现冗余备份。
<img src="https://static001.geekbang.org/resource/image/cd/5e/cd2bd7fc384155e29a2b0dad4c92575e.png" alt="">
Doris将存储服务器集群分成多个group默认情况下为2个group数据写操作的时候根据分区路由算法在每个group里计算一个服务器地址异步并发同时向多个group的服务器上写入数据以此保证数据有多个备份。
<img src="https://static001.geekbang.org/resource/image/eb/fc/eba8dc671ec1a750fae74221a0782cfc.png" alt="">
当KV Client访问某台服务器失败的时候Doris会启动失效转移策略。具体来说Doris将失效分为三种情况瞬时失效、临时失效、永久失效不同情况采用不同的失效转移策略。
<img src="https://static001.geekbang.org/resource/image/05/0d/0584b85e62b7917fce2f11f587ea8e0d.png" alt="">
当第一次不能访问服务器的时候Doris认为这是瞬时失效会进行访问重试如果三次重试后仍然失败就会把失败信息提交给控制中心。控制中心检测该服务器心跳是否正常并进行尝试访问如果访问失败就将该服务器标记为临时失效并通知所有KV Client应用程序。
<img src="https://static001.geekbang.org/resource/image/8f/e8/8fb946ae9879bfbfdf403a8b686605e8.png" alt="">
KV Client应用程序收到服务器失效通知的时候启动临时失效策略将原本需要写入到失效节点图中的物理节点2的数据写入临时日志节点图中的物理节点X而读操作则只访问正常的物理节点1。
当临时失效节点2恢复正常运行系统会将失效期间写入临时日志节点X的数据合并恢复到物理节点2这段时间物理节点2只提供写服务不提供读服务。当所有数据恢复完毕集群访问恢复正常。
<img src="https://static001.geekbang.org/resource/image/39/87/390216499d8a68f9f9f607bd18fc8987.png" alt="">
而对于永久失效的节点需要添加新的服务器以代替下线的服务器基本策略就是将另一个group正常使用的服务器数据拷贝到新添加的服务器上即可。
需要说明的是,上述三种失效转移过程,除了服务器永久失效后,需要工程师手动添加服务器,并到控制中心添加新服务器配置、激活启用外,其他情况不需要任何人工干预,全部自动化完成。
## 集群伸缩设计
分布式系统的一个重要设计目标是集群弹性可伸缩,如果当前的服务器数目不能满足业务的负载压力要求,那么就添加更多的服务器去增强处理能力。对于分布式数据存储服务器的伸缩性扩容而言,必然伴随着数据的迁移,就是将原先服务器中的部分数据迁移到新的服务器上。
<img src="https://static001.geekbang.org/resource/image/dd/fe/ddaf1e4c4e13be3bb1085f2dda9ecefe.png" alt="">
具体过程为:
1.向集群中一个分组group添加新的物理服务器部署并启动Doris服务器进程。
2.将这个group的所有服务器设置为临时失效。
3.使用路由算法重新计算加入服务器后的虚拟节点分布,并把需要迁移的虚拟节点对应的物理文件拷贝到新服务器上。
4.设置group所有服务器临时失效恢复将扩容期间的数据更新写回到这些服务器。
至此PPT最前面提出的设计目标经过一系列的关键技术设计分析证明是技术是可行的风险是可控的可以启动开发了。
实际上当时项目组大概花了半年的时间开发Doris系统部署上线以后阿里巴巴多个业务产品接入Doris并在极少运维的情况下无故障运行了数年。后来服务器集群经过几次扩容规模达到数百台服务器实践证明当时的设计是经得起考验的。
最后,我想再说一下关于专利的事。公司一般都是希望能够申请更多的技术专利,这样在跟其他公司进行专利大战的时候才能做到“手中有枪,心中不慌”,特别是在遇到“专利流氓”的时候。所以大部分公司对工程师申请技术专利都比较支持。
大一点的公司法务部门通常会有专门的知识产权律师,他们会帮助工程师申请技术专利,工程师只要按照一般写技术文档的写法写一个技术交底书给公司律师,律师审核后会让专门的专利代理公司帮助编写专门的技术专利申请书,所以工程师申请专利的工作量并不大。
很多公司为了支持申请技术专利,会有很多奖励,比如申请成功一个专利会有几万的奖励,这对于工程师也是一笔不错的收入。做技术的同学可以关注下自己公司的专利奖励政策,如果还没有相关的专利奖励,正好你也可以借此机会说服公司管理层在这方面增加一些激励,这是一件利国家、利公司、利自己的好事。
## 小结
分布式数据存储系统是分布式系统中最有技术挑战的领域之一。其他的各种分布式系统,由于对数据的一致性和系统的可用性要求并没有那么高 ,所以技术难度和挑战相对没有分布式存储系统这么高。自己参与设计、开发这样的系统,会对分布式系统,乃至大数据系统有更深刻地理解,希望这两期专栏能引导你从开发者的视角,看待分布式大数据系统是如何设计开发出来的,从而对大数据技术有新的认识和领悟。
如果你在工作中遇到有技术挑战的项目,可以尽量找机会去参与,你能收获的不仅仅是最终开发出来的产品和公司的认可,还有自己技术的提升和更有想象力的职业前景。
## 思考题
今天的文中提到Doris的分区路由算法在设计的时候提出了一个数学模型计算虚拟节点和物理节点的映射关系。但是最后在开发过程中项目组并没有使用这个数学模型进行计算你能想到的实现算法还有什么呢
你也可以在Doris的源代码中找到相关代码分析Doris的最终实现算法和你的思考有什么异同。
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
扩展阅读:
对专利感兴趣的同学可以进一步阅读Doris产品申请的三个技术专利
[http://www.soopat.com/Patent/201110325238](http://www.soopat.com/Patent/201110325238)
[http://www.soopat.com/Patent/201110294092](http://www.soopat.com/Patent/201110294092)
[http://www.soopat.com/Patent/201110285802](http://www.soopat.com/Patent/201110285802)
Doris源代码地址
[https://github.com/itisaid/Doris](https://github.com/itisaid/Doris)

View File

@@ -0,0 +1,122 @@
<audio id="audio" title="23 | 大数据基准测试可以带来什么好处?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/5a/73/5a7f6c76c651ac09f88de68ab36ab673.mp3"></audio>
2012年的时候Hadoop已经日趋成熟Intel的大数据团队也正准备寻找新的技术研究方向。当时我们对比测试了多个新出来的大数据技术产品最终选择了Spark重点跟进参与。现在看来这是一个明智的决定作出这个决定是基于大数据基准测试而使用的对比测试工具就是我今天要讲的大数据基准测试工具HiBench。
大数据作为一个生态体系不但有各种直接进行大数据处理的平台和框架比如HDFS、MapReduce、Spark还有很多周边的支撑工具而大数据基准测试工具就是其中一个大类。
## 大数据基准测试的应用
大数据基准测试的主要用途是对各种大数据产品进行测试,检验大数据产品在不同硬件平台、不同数据量、不同计算任务下的性能表现。
上面这样讲大数据基准测试的用途可能比较教条,我举两个例子你就能明白它的应用有多么重要了。
还是回到2012年当时Hive只能做离线的SQL查询计算无法满足数据分析师实时交互查询的需求业界需要一款更快的ad hoc query即席查询一种非预设查询的SQL访问工具。在这种情况下Cloudera推出了准实时SQL查询工具Impala。Impala兼容Hive的Hive QL语法和Hive MetaSotre也支持Hive存储在HDFS的数据表但是放弃了Hive较慢的MapReduce执行引擎而是基于MPPMassively Parallel Processing大规模并行处理的架构思想重新开发了自己的执行引擎从而获得更快的查询速度。
由于Cloudera在大数据领域的巨大权威加上人们对快速SQL查询的期待Impala在刚推出的时候受到大数据业界的极大瞩目。当时我也立即用四台服务器部署了一个小集群利用大数据基准测试工具HiBench对Impala和Hive做了一个对比测试。
<img src="https://static001.geekbang.org/resource/image/96/9b/961e6cc96cb0beb649d96bd21ed62b9b.png" alt="">
但是经过对比测试以后我发现情况并不乐观。Impala性能有优势的地方在于聚合查询也就是用group by查询的SQL语句而对于连接查询也就是用join查询的SQL语句性能表现很差。我进一步阅读Impala的源代码对设计原理和架构进行分析后得出了自己的看法我认为适合Impala的应用场景有两类
<li>
一类是简单统计查询,对单表数据进行聚合查询,查看数据分布规律。
</li>
<li>
一类是预查询在进行全量数据的SQL查询之前对抽样数据进行快速交互查询验证数据分析师对数据的判断方便数据分析师后续设计全量数据的查询SQL而全量数据的SQL还是要运行在Hive上。
</li>
这样Impala就有点尴尬了它的定位似乎只是Hive的附属品。这就好比Impala是餐前开胃菜和餐后甜点而正餐依然是Hive。
但是Cloudera却对Impala寄予厚望后来我和Cloudera的工程师聊天得知他们投入了公司近一半的工程师到Impala的开发上我还是有点担心。事实上这么多年过去了Impala经过不断迭代相比最开始的性能有了很大改进但是我想Impala依然没有承担起Cloudera对它的厚望。
跟Impala相对应的是同样是2012年Intel大数据团队用大数据基准测试工具HiBench对Spark和MapReduce做了对比测试后发现Spark运行性能有令人吃惊的表现。当时Intel大数据团队的负责人戴老师Jason Dai立即飞到美国跟当时开发Spark的UC Berkeley的AMP实验室交流表示Intel愿意参与到Spark的开发中。Spark也极其希望有业界巨头能够参与其中开发代码尚在其次重要的是有了Intel这样的巨头背书Spark会进一步得到业界的认可和接受。
所以Intel成了Spark最早的参与者加速了Spark的开发和发展。当2013年Spark加入Apache的开源计划并迅速成为Apache的顶级项目风靡全球的大数据圈子时Intel作为早期参与者也得到了业界的肯定使Intel在大数据领域可以保持持续的影响力。
在这个案例里所有各方都是赢家Spark、Intel、Apache乃至整个大数据行业我作为Intel参与Spark早期开发的工程师也都因此而受益。这也是我关于工作的一个观点好的工作不光是对公司有利对员工也是有利的。工作不是公司在压榨员工的过程而是公司创造价值同时员工实现自我价值的过程。
而如何才能创造出好的工作也不只是公司的责任主要还是要靠员工自己去发现哪些事情能够让自己、公司、社会都获益然后去推动这些事情的落实虽然有的时候推动比发现更困难。同时拥有发现和推动能力的人毫无例外都是一些出类拔萃的人比如专栏前面也提到的Intel的戴老师这些人都是我工作的榜样。
## 大数据基准测试工具HiBench
大数据基准测试工具有很多今天我重点为你介绍前面我多次提到的也是Intel推出的大数据基准测试工具[HiBench](http://github.com/intel-hadoop/HiBench)。
HiBench内置了若干主要的大数据计算程序作为基准测试的负载workload
<li>
Sort对数据进行排序大数据程序。
</li>
<li>
WordCount前面多次提到过词频统计大数据计算程序。
</li>
<li>
TeraSort对1TB数据进行排序最早是一项关于软件和硬件的计算力的竞赛所以很多大数据平台和硬件厂商进行产品宣传的时候会用TeraSort成绩作为卖点。
</li>
<li>
Bayes分类机器学习分类算法用于数据分类和预测。
</li>
<li>
k-means聚类对数据集合规律进行挖掘的算法。
</li>
<li>
逻辑回归,数据进行预测和回归的算法。
</li>
<li>
SQL包括全表扫描、聚合操作group by、连接操作join几种典型查询SQL。
</li>
<li>
PageRankWeb排序算法。
</li>
此外还有十几种常用大数据计算程序支持的大数据框架包括MapReduce、Spark、Storm等。
对于很多非大数据专业人士而言HiBench的价值不在于对各种大数据系统进行基准测试而是学习大数据、验证自己大数据平台性能的工具。
对于一个刚刚开始入门大数据的工程师而言在自己的电脑上部署了一个伪分布式的大数据集群可能并不复杂对着网上的教程顺利的话不到1个小时就可以拥有自己的大数据集群。
但是接下来呢开发MapReduce程序、打包、部署、运行可能这里每一步都会遇到很多挫折。即使一切顺利但顾名思义对于“大数据”来说需要大量的数据才有意义那数据从哪儿来呢如果想用一些更复杂的应用体验下大数据的威力可能遇到的挫折就更多了所以很多人在安装了Hadoop以后然后就放弃了大数据。
对于做大数据平台的工程师,如果等到使用者来抱怨自己维护的大数据平台不稳定、性能差的时候,可能就有点晚了,因为这些消息可能已经传到老板那里了。所以必须自己不停地跑一些测试,了解大数据平台的状况。
有了HiBench这些问题都很容易就可以解决HiBench内置了主要的大数据程序支持多种大数据产品。最重要的是使用特别简单初学者可以把HiBench当作学习工具可以很快运行起各种数据分析和机器学习大数据应用。大数据工程师也可以用HiBench测试自己的大数据平台验证各种大数据产品的性能。
HiBench使用非常简单只需要三步
1.配置,配置要测试的数据量、大数据运行环境和路径信息等基本参数。
2.初始化数据生成准备要计算的数据比如要测试1TB数据的排序那么就生成1TB数据。
3.执行测试,运行对应的大数据计算程序。
具体初始化和执行命令也非常简单比如要生成数据只需要运行bin目录下对应workload的prepare.sh就可以自动生成配置大小的数据。
```
bin/workloads/micro/terasort/prepare/prepare.sh
```
要执行大数据计算运行run.sh就可以了。
```
bin/workloads/micro/terasort/hadoop/run.sh
bin/workloads/micro/terasort/spark/run.sh
```
## 小结
同一类技术问题的解决方案绝不会只有一个技术产品也不会只有一个比如大数据领域从Hadoop到Spark再到Flink各种大数据产品层出不穷那么如何对比测试这些大数据产品在不同的应用场景中它们各自的优势是什么这个时候就需要用到基准测试工具通过基准测试工具用最小的成本得到我们想测试的结果。
所以除了大数据,在很多技术领域都有基准测试,比如数据库、操作系统、计算机硬件等。前几年手机领域的竞争聚焦在配置和性能上,各路发烧友们比较手机优劣的时候,口头禅就是“跑个分试试”,这也是一种基准测试。
因此基准测试对这些产品而言至关重要甚至攸关生死。得到业界普遍认可的基准测试工具就是衡量这些产品优劣的标准如果能使基准测试对自己的产品有利更是涉及巨大的商业利益。我在Intel开始做SQL引擎开发后来做Spark开发需要调查各种数据库和大数据的基准测试工具也就是在那个时候我发现华为这家公司还是很厉害的在很多基准测试标准的制定者和开发者名单中都能看到华为的名字而且几乎是唯一的中国公司。
有时候我们想要了解一个大数据产品的性能和用法看了各种资料花了很多时间最后得到的可能还是一堆不靠谱的N手信息。但自己跑一个基准测试也许就几分钟的事再花点时间看看测试用例从程序代码到运行脚本很快就能了解其基本用法更加省时、高效。
## 思考题
今天文章的Impala VS Hive的基准测试报告里发现当数量很大的时候做join查询Impala会失去响应是因为Impala比Hive更消耗内存当内存不足时就会失去响应。你能否从Impala的架构和技术原理角度分析为什么Impala比Hive更消耗内存
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,117 @@
<audio id="audio" title="24 | 从大数据性能测试工具Dew看如何快速开发大数据系统" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/55/d9/5582d9ae22eab104f5be3466f13b61d9.mp3"></audio>
我们在[Spark性能优化案例分析](http://time.geekbang.org/column/article/72056)这一期中通过对大量的Spark服务器的性能数据进行可视化分析发现了Spark在程序代码和运行环境中的各种性能问题并做了相应优化使Spark运行效率得到了极大提升。
<img src="https://static001.geekbang.org/resource/image/7a/cc/7af885b0492aa68ffbe05bee7e04cdcc.png" alt="">
很多同学也在问这些可视化的性能数据从何而来呢如何在图中将性能指标和任务进度结合起来可以一目了然看清应用在不同运行阶段的资源使用状况呢事实上当时为了进行Spark性能优化我和团队小伙伴们开发了一个专门的大数据性能测试工具[Dew](https://github.com/zhihuili/Dew)。
## Dew设计与开发
Dew自身也是一个分布式的大数据系统部署在整个Hadoop大数据集群的所有服务器上。它可以实时采集服务器上的性能数据和作业日志收集起来以后解析这些日志数据将作业运行时间和采集性能指标的时间在同一个坐标系绘制出来就得到上面的可视化性能图表。Dew的部署模型如下。
<img src="https://static001.geekbang.org/resource/image/7f/81/7f0cf1566ba2f7fccd41b036112e7f81.png" alt="">
从图中看Dew的核心进程有两种一种是Dew Master进程Herse另一种是管理集群中每台服务器的Dew Agent进程DewDropDew Agent监控整个Hadoop集群的每台服务器。Herse独立部署一台服务器而DewDrop则和HDFS的DataNode、Yarn的NodeManager部署在大数据集群的其他所有服务器上也就是每台服务器都同时运行DataNode、NodeManager、DewDrop进程。
Dew Master服务器上配置好Agent服务器的IP运行下面的命令就可以启动整个Dew集群。
```
sbin/start-all.sh
```
Master进程Herse和每一台服务器上的Agent进程DewDrop都会启动起来DewDrop进程会向Herse进程注册获取自身需要执行的任务根据任务指令加载任务可执行代码启动Drop进程内的service或者独立进程service即各种App。整个启动和注册时序请看下面这张图。
<img src="https://static001.geekbang.org/resource/image/41/6d/41bcd70f741ab4a445c368565a67586d.png" alt="">
所以我们看Dew的架构其自身也是一个典型的主从结构的大数据系统。跟所有其他的大数据系统一样Dew也要有一套底层通信体系和消息传输机制。
当时我们的目标只是想做大数据性能测试与分析进而优化Spark源代码。所以开发一个分布式大数据性能测试工具是辅助手段本身不是最主要的目标所以不可能花太多精力在系统开发上。所以需要寻找一个可以快速开发分布式底层通信体系和消息传输机制的编程框架。
很快我们将目标锁定在Akka这是一个可以同时支持并发编程、异步编程、分布式编程的编程框架提供了Java和Scala两种编程语言接口最关键的是Akka非常简单易用。
最后我们用Akka搭建了Dew的底层通信和消息传输机制核心代码只有不到100行花了大半天的时间就开发完成了。一个Master-Slave架构的大数据系统的基本框架就搭建起来了后面加入分布式集群性能数据采集、日志收集也没花多少时间很快就输出了我们前面看到的那些Spark性能图表接着就可以开始对Spark做优化了。
如果你不太熟悉Akka看完上面的内容肯定会对这个如此强大又简单的Akka充满好奇。接下来我们就来看看Akka的原理和应用。
## Akka原理与应用
Akka使用一种叫Actor的编程模型Actor编程模型是和面向对象编程模型平行的一种编程模型。面向对象认为一切都是对象对象之间通过消息传递也就是方法调用实现复杂的功能。
而Actor编程模型认为一切都是ActorActor之间也是通过消息传递实现复杂的功能但是这里的消息是真正意义上的消息。不同于面向对象编程时方法调用是同步阻塞的也就是被调用者在处理完成之前调用者必须阻塞等待给Actor发送消息不需要等待Actor处理消息发送完就不用管了也就是说消息是异步的。
面向对象能够很好地对要解决的问题领域进行建模但是随着摩尔定律失效计算机的发展之道趋向于多核CPU与分布式的方向而面向对象的同步阻塞调用以及由此带来的并发与线程安全问题使得其在新的编程时代相形见绌。而Actor编程模型很好地利用了多核CPU与分布式的特性可以轻松实现并发、异步、分布式编程受到人们越来越多的青睐。
事实上Actor本身极为简单下面是一个Scala语言的Actor例子。
```
class MyActor extends Actor {
val log = Logging(context.system, this)
def receive = {
case &quot;test&quot; ⇒ log.info(&quot;received test&quot;)
case _ ⇒ log.info(&quot;received unknown message&quot;)
}
}
```
一个Actor类最重要的就是实现receive方法在receive里面根据Actor收到的消息类型进行对应的处理。而Actor之间互相发送消息就可以协作完成复杂的计算操作。
Actor之间互相发送消息全部都是异步的也就是说一个Actor给另一个Actor发送消息并不需要等待另一个Actor返回结果发送完了就结束了自己继续处理别的事情。另一个Actor收到发送者的消息后进行计算如果想把计算结果返回给发送者只需要给发送者再发送一个消息就可以了而这个消息依然是异步的。
这种全部消息都是异步,通过异步消息完成业务处理的编程方式也叫**响应式编程**Akka的Actor编程就是响应式编程的一种。目前已经有公司在尝试用响应式编程代替传统的面向对象编程去开发企业应用和网站系统如果这种尝试成功了可能会对整个编程行业产生巨大的影响。
Akka实现异步消息的主要原理是Actor之间的消息传输是通过一个收件箱Mailbox完成的发送者Actor的消息发到接收者Actor的收件箱接收者Actor一个接一个地串行从收件箱取消息调用自己的receive方法进行处理。这个过程请看下面的图。
<img src="https://static001.geekbang.org/resource/image/26/13/269b28c63c69444dd9dcb0c3124e0713.png" alt="">
发送者通过调用一个Actor的引用ActorRef来发送消息ActorRef将消息放到Actor的Mailbox里就返回了发送者不需要阻塞等待消息被处理这是和传统的面向对象编程最大的不同对象一定要等到被调用者返回结果才继续向下执行。
通过这种异步消息方式Akka也顺便实现了并发编程消息同时异步发送给多个Actor这些Actor看起来就是在同时执行即并发执行。
当时Dew使用Akka主要用途并不是需要Akka的并发、异步特性而是主要用到它的分布式特性。
Akka创建Actor需要用ActorSystem创建。
```
val system = ActorSystem(&quot;pingpong&quot;)
val pinger = system.actorOf(Props[Pinger], &quot;pinger&quot;)
```
当Actor的Props配置为远程的方式就可以监听网络端口从而进行远程消息传输。比如下面的Props配置sampleActor监听2553端口。
```
akka {
actor {
deployment {
/sampleActor {
remote = &quot;akka.tcp://sampleActorSystem@127.0.0.1:2553&quot;
}
}
}
}
```
所以使用Akka编程写一个简单的Actor实现receive方法配置一个远程的Props然后用main函数调用ActorSystem启动就得到了一个可以远程通信的JVM进程。使用AkkaDew只用了100多行代码就实现了一个Master-Slave架构的分布式集群。
## 小结
现在微服务架构大行其道如果用Akka的Actor编程模型无需考虑微服务架构的各种通信、序列化、封装只需要将想要分布式部署的Actor配置为远程模式就可以了不需要改动任何一行代码。是不是很酷呢
此外Actor的交互方式看起来是不是更像人类的交互方式拜托对方一件事情说完需求就结束了不需要傻傻地等在那里该干嘛干嘛。等对方把事情做完了再过来跟你说事情的结果你可以根据结果决定下一步再做什么。
人类社会的主要组织方式是金字塔结构老板在最上面各级领导在中间最下面是普通干活的员工。所以一个理想的Actor程序也是同样采用金字塔的结构顶层Actor负责总体任务将任务分阶段、分类以后交给下一级多个Actor下一级Actor拆分成具体的任务交给再下一级更多的Actor众多的底层Actor完成具体的细节任务。
这种处理方式非常符合大数据的计算大数据计算通常都分成多个阶段每个阶段又处理一个数据集的多个分片这样用Actor模型正好可以对应上。所以我们看到有的大数据处理系统直接用Akka实现它们程序简单运行也很良好比如大数据流处理系统[Gearpump](http://gearpump.apache.org/overview.html)。
## 思考题
我们前面提到Akka的远程Actor可以实现分布式服务我在专栏第15期的思考题提到过基于消息的流式架构那么能否用Akka实现一个流式的分布式服务呢如果可以对于一个典型的Web请求比如注册用户这样的流式分布式服务处理过程是什么样的呢
欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,53 @@
<audio id="audio" title="25 | 模块答疑:我能从大厂的大数据开发实践中学到什么?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/91/3a/91740f59a5bd96456642982e345cdc3a.mp3"></audio>
你好,我是李智慧,又到了我们模块答疑的时间了。在这个模块里,我主要讲了大数据开发的实践,所以今天我想和你聊聊我在大厂里学到哪些经验。
软件编程大体上可以分成两种,一种是编写的程序直接供最终用户使用,针对用户需求进行开发,可以说绝大多数工程师开发的绝大多数程序都属于这一种;还有一种是编写的程序供其他工程师使用,大到全球通用的各种编程语言、编程框架、虚拟机、大数据系统,小到公司内部,甚至团队内部自己开发的各种工具、框架,以及应用系统内的非业务模块,都是属于这一种。
一般说来,后一种编程因为输出的程序要给其他工程师使用,接受专业同行的审视,而且被复用的次数更多,更偏向底层,所以通常技术难度更高一点,开发这样的软件对工程师的技能提升也更高一点。技术产品难度有难易之分,正如工程师水平也分高下,但是两者之间却没有必然联系。
这些年我在各种不同的公司工作过在几个人的小作坊开发过只有几个人使用的所谓ERP系统也在所谓的大厂参与过全球顶级的大数据系统的开发据我所见优秀的人哪里都有大厂里优秀工程师更多一些但是小作坊里有时候也卧虎藏龙。
导致工程师技术水平不同的不在于是大厂还是小作坊,大厂里有十几年如一日拧螺丝钉的人,在一个极其狭窄的技术产品里重复技术细节的工作,对这些年的技术进步几乎一无所知;小作坊也有自己开发整套技术框架的人,虽说是重复造轮子,但是因为造过,所以对软件开发的关键技术和架构设计有更深刻的领悟,软件设计能力和编程技巧通常也更胜一筹。
如果你有机会在大厂参与核心产品的开发固然好,如果没有,也大可不必遗憾,决定你技术水平和发展前景的最主要因素,不在于公司,而在于你所做的事。小厂因为人少事多,所以你反而可能有更多机会开发一些有技术难度的软件,比如为提高开发效率而给其他工程师开发一些工具,或者为公司开发一些框架供所有项目使用。
但是这些有技术难度的软件,能让你提高技术水平获得更好成长空间的开发工作,通常又不被公司重视,因为小公司做业务尚且忙不过来,去开发什么工具、框架,在老板看来简直是不务正业。而老板也很难慧眼识珠,安排你去做这些看起来不那么要紧的事。所以你需要自己去争取机会,有时候甚至要用自己的业余时间去做,等有了初步效果,能真正提高公司的效率后,你也会得到更多信任和机会去专门持续进行基础技术产品的开发。
大数据技术领域因为通常不用直接满足最终用户的需求所以大数据开发者有更多机会去做一些底层技术方面的开发工作比如开发大数据平台整合公司的数据和各类系统开发数据爬虫获取外部的数据资源开发ETL工具转换公司的各类数据这些技术也是专栏下一个模块的主要内容。通过开发这些软件一方面可以更好地利用大数据技术实现业务价值另一方面对自身的技术水平提升也大有帮助。
前面我说过身在大厂并不会保证你一定能参与开发有技术含量的产品更不能保证你的技术能力一定会得到提升。但是我自己在阿里巴巴、在Intel工作时还是学到了很多前面专栏分享的很多内容都是我在这些地方学习到的。这里我再和你分享一个我在Intel学到的关于学习的方法。
在Intel之前我学习技术主要就是从网上搜索各种乱七八糟的资料有的时候运气好资料比较好学习的速度和掌握的深度就好一些有时候运气差就会走很多弯路。但是在Intel我发现一些比较厉害的同事他们学习一样新技术的时候不会到处乱找资料而是直接读原始论文。通过原始论文掌握核心设计原理以后如果需要进一步学习就去官网看官方文档如果还需要再进一步参与开发就去读源代码。
我刚开始读论文时感觉很费劲,但是后面习惯以后,发现读论文真的是最快的学习方法,因为最核心的东西就在其中,一旦看懂,就真的懂了,而且可以触类旁通,整个软件从使用到开发,很多细节通过脑补就可以猜个八九不离十。而且越是优秀的产品,越是厉害的作者,论文反而越是容易读懂,可能是因为这些作者是真的高手,自己理得越清楚,写出来的论文越是脉络清晰、结构合理、逻辑严谨。
后来在学习区块链的时候,读原始论文很快就理解了个中关键,反而在跟一些所谓“资深”区块链人士交流的时候,发现他们在一些关键细节上常常犯迷糊,我就感到很诧异,中本聪、布特林在他们的论文中不是说得很清楚嘛。
下面我顺着今天的话题来回答一下“sunlight001”同学的问题。
<img src="https://static001.geekbang.org/resource/image/4f/be/4fc15e708f323bbe3685c1585051e4be.png" alt="">
我认为,软件开发是一个实践性活动,不管是学习还是应用,最终都需要落到实践中。大数据技术也不例外,没有实践,就不可能深入,想要学好大数据,一定要实践。
而实践可以分为几个不同的层次。
**第一个层次是练习实践**我的专栏剖析架构原理居多这是专栏定位决定的而且学习大数据真正的难度或者说决定你技术高度的依然是你是否理解了大数据技术的核心原理。但是大数据的学习一定要配合练习实践不管是Hadoop、Spark、Hive的部署还是编程练习实践网上的教程都有很多step by step入门学习的资料也很多。通过这些练习实践结合专栏的原理分析可以由表及里从如何上手操作到理解背后的原理机制最后能够做到融会贯通。我看到专栏评论里很多同学贴了代码上来一边学习一边实践我们向这些同学学习。
通过练习实践和原理学习,掌握的是大数据技术的核心关键,真正对一个技术的掌握是需要掌握其细节,没有经过时间的积累,没有在应用中踩过各种坑、遇到各种挑战,没有对各种大数据技术思考再思考、研究再研究,就不可能掌握细节。所以,**大数据实践的第二个层次是应用实践**,在应用中解决问题,在实践中训练自己。
关于公司没有接触大数据的机会,一般是两种情况,公司没有用大数据,或者公司用大数据技术,但是你接触不到。对于前一种情况,大数据的价值已经成为普遍共识,你要想办法给老板献计献策,同时在同事间鼓吹大数据的好处,让老板关注大数据、使用大数据。如果最后老板决定使用大数据,那么他想到的第一个应该就是你,你的机会也就来了。
对于后一种情况,如果你已经经过前面的学习和练习实践,掌握了一定的大数据技术知识,申请转岗也可以,在自己的项目中引入大数据和大数据团队展开更多合作也可以,具体也会有很多办法获得应用实践的机会。
大数据实践的**第三个层次是开发实践**大数据产品开发有两种一种是重新开发比如前面讲过的Doris、Dew自己从头设计开发一个大数据系统这样对学习的好处是可以更深刻、更全面理解大数据。另一种就是参与开源大数据产品的开发比如前面讲过的Spark源码优化这样的好处是可以和全世界最顶级的工程师一起讨论问题通过交流学习提高。我在参与Spark开发的时候跟Databricks、Cloudera的工程师交流这些人可能是大数据技术领域最顶级的工程师跟他们交流收获最深刻的不是技术而是对他们技术水平的判断以及进而对自己技术水平的判断并因此促使自己思考自己未来的技术发展之路与人生之路。
最后我想说的是,这个世界不是为你而存在的,别人根本不会在乎你的感受和你的问题,不会把你想要的东西装在精美的礼盒里打上蝴蝶结送到你的面前,也不会因为你想学习大数据而给你一个实践的机会。不过这样也好,你也不必在乎这个世界怎么看你,只要你想要,你就可以拼尽全力为自己去争取,你要为自己创造机会。
文章最后我将Dr.ZZZ、纯洁的憎恶、吴科、galen这几位同学的留言贴在今天的文稿里分享给你希望同学们的思考也能对你有所启发。
<img src="https://static001.geekbang.org/resource/image/95/77/95e4069baa174fa42602ee7f38a1cf77.png" alt=""> <img src="https://static001.geekbang.org/resource/image/d8/32/d82acc254cbfe5b60bcf2ee42460e232.png" alt=""><img src="https://static001.geekbang.org/resource/image/7b/5f/7beab95eb0ac29717950957573bf5b5f.png" alt=""><img src="https://static001.geekbang.org/resource/image/cf/d6/cfb14bd51f468d09703503a8acc18bd6.png" alt="">
如果你身边也有感到迷茫困惑的朋友,欢迎你点击“请朋友读”,把今天的文章分享给好友。也欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。