-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.xml
More file actions
431 lines (299 loc) · 38.7 KB
/
index.xml
File metadata and controls
431 lines (299 loc) · 38.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>沙漠守望者</title>
<link>https://liming01.github.io/</link>
<description>Recent content on 沙漠守望者</description>
<generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator>
<language>en-us</language>
<copyright>&copy; 2017~2019 Ming LI</copyright>
<lastBuildDate>Thu, 23 Mar 2017 15:30:00 +0000</lastBuildDate>
<atom:link href="https://liming01.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Apache HAWQ的事务处理</title>
<link>https://liming01.github.io/talk/hawq-tx/hawq-tx/</link>
<pubDate>Thu, 23 Mar 2017 15:30:00 +0000</pubDate>
<guid>https://liming01.github.io/talk/hawq-tx/hawq-tx/</guid>
<description>
<p>这个是在3月23日举办的HAWQ技术研讨会中本人做的技术演讲,本次演讲首先为大家介绍了PostgreSQL的事务处理中的多版本并发控制,然后结合了HAWQ的应用场景,介绍在HAWQ怎么实现事务并发控制,以及并行插入优化等问题,并解释了一些HAWQ使用的注意事项和将来可以考虑实现的一些方案。</p>
<h1 id="追加评论-2019年5月30日">追加评论(2019年5月30日)</h1>
<p>需要说明一下:
PPT里面引用了第五、六、七页的例子是直接从Bruce Momjian的“MVCC Unmasked”的报告里通过图片拷贝过来的,原来是PPT格式,我在页面的注释处写了引用的出处了。但是在放到HAWQ的wiki之前,公司的人把它转换成PDF格式的,导致所有页面的注释没能导出来。</p>
<p>我负责公司的内部的tech talk,由于这周没有人分享,考虑到接下来的工作多个组可能都要涉及到这些知识,我就准备自己上去分享下相关的背景知识等。由于我们组活儿也比较紧,我在开会的前一天才有时间花了半天左右的时间准备PPT,所以我就从网上找些资料,把相关的东西串起来,有些图片直接从官方的公开文档里拷贝过来。</p>
<p>然后就发生了让我很郁闷的一件事情。有个同事过来跟我说,说所有的图片啥的不是自己画的都必须要有引用出处。还说我这个链接里的公开资料直接引用别人的东西,不注明出处涉及到剽窃行为。对此表示很气愤!先暂且不说我是写了引用出处的,也不是我的原因导致了这个结果。就算是我确实没写出处,我这次演讲的目的本来就是讲HAWQ的事务实现,只是介绍这个实现之前,必须先了解PostgreSQL的事务实现(本来PostgreSQL的事务实现也不是我实现的,根本就不是我原创的东西,何来剽窃一说?)也不知道达到剽窃这么高的一个高度吧?</p>
<p>说起这件事,让我想起来了5月21日华为老总任正非的访谈,说到自主创新的问题,他如是说:<strong>自主创新如果是一种精神,我支持;如果是一种行动,我就反对!</strong>
看到那个访谈,我立刻在微信的朋友圈转发,比附上我的留言:<strong>战略上藐视敌人,战术上要重视敌人!战略上自主创新,战术上还是要站在现有巨人的肩膀上,搞最前沿的创新!</strong></p>
<p>有些人以为要自主创新就要从每个螺丝钉开始,从最基础的每个东西都是自主的才行。殊不知我们的重心要放在最前沿的创新上,放在最需要我们花力气的地方!可惜这些人永远看不到别人的意图!只知道拿一些条条框框来限制你,不考虑时间、机会、成本,站在道德的制高点,扮成维护完美的圣斗士!我只想说:不要扮演圣人了,让你内部技术分享你不分享,别人分享你就在那边指指点点,你觉得合适吗?</p>
</description>
</item>
<item>
<title>从COPY的并行化到gpcopy工具的诞生</title>
<link>https://liming01.github.io/post/copy2gpcopy/</link>
<pubDate>Mon, 13 Mar 2017 11:00:00 +0000</pubDate>
<guid>https://liming01.github.io/post/copy2gpcopy/</guid>
<description>
<p>&mdash;&mdash; 作者:<a href="https://github.com/liming01" target="_blank">李明</a> (email: mli@apache.org)</p>
<p>由于公司战略调整,数据库的工作重心从HAWQ转向Greenplumn,我悻悻离开了奋斗好几年的HAWQ组,来到了gpdb大组下的unite组。</p>
<h1 id="copy的并行化-copy-on-segment">COPY的并行化(COPY ON SEGMENT)</h1>
<p>来到新组,除了做一些bug的修复工作,我开发的第一个feature是Copy On Segment, 即COPY的并行化。COPY是PostgreSQL支持的SQL语句,能够将数据批量地导入或者导出数据库。gpdb是基于pg开发,以前的版本在原有的单节点的COPY命令,修改成多节点协调,所有数据都可以通过master节点导入导出,master节点再将被处理的数据引导到对应的segment节点上处理,等处理完毕后将执行的结果(成功行数、失败行数等)都统一汇总给master,最后再由master反馈给客户端。由于修改流程比较复杂,导致src/backend/commands/copy.c的代码从pg里的5k多行一下涨到了gpdb的8k多行。</p>
<p>原先的这种处理方式,所有的数据交互都需要通过master节点来完成,对master节点的性能影响很大。更为重要的问题是COPY的性能不能满足需求,gpdb的处理的数据量比单节点pg的数量可以高出两个数量级,而COPY的这种处理方式很大程度限制了它所能处理的最大数据流量,特别是在segment数量很大(比如超过100时)表现更为明显。</p>
<p>而COPY ON SEGMENT这个新特性就是为了解决这个问题而提出的,它将要处理的数据直接在segment节点导入或者导出,master节点只负责整个命令的协调(比如命令的启停、报错等)和最后执行的结果的汇总。COPY &hellip; TO &hellip; ON SEGMENT比较简单,直接将数据导出到各个segment上的文件,并将结果汇报给master就可以。COPY &hellip; FROM &hellip; ON SEGMENT就比较复杂了,需要了解整个COPY在gpdb中怎么处理,特别是在master和segment之间如何相互分工协作,再搞清楚整个大背景之后,再去提出一个好的方案,通过小改动去实现整个COPY流程的整合。具体的细节可以参见<a href="https://github.com/greenplum-db/gpdb/commit/e254287ef997b2b33cdca5ec627bd9fc163d12e3" target="_blank">COPY &hellip; FROM &hellip; ON SEGMENT的commit</a></p>
<h1 id="工具gpcopy的诞生">工具gpcopy的诞生</h1>
<p>除了做COPY ON SEGMENT这个新特性之外,我们组的还负责维护gptransfer、gpload、gpfdist、External Table等相关的模块。由于gptransfer和gpfdist的bug很多时候都很难调试,特别是在开了很多并行任务时更难追踪。</p>
<p>当完成了COPY ON SEGMENT的特性之后,基于基本认识:COPY相对于External Table的性能更好,更适合于批量导入导出数据,我们就有基于这个新特性构建一个新的传输数据的工具的想法。随着我们多次讨论它的性能优势,并对他进行小规模的模拟性能测试(至少有三分之一的性能提升),我们更加坚定了这样做的必要性。</p>
<p>与此同时,gpdb组投入了很多人力在进行炉火如荼的pg kernel升级,但是由于人手资源的缺乏,没能及时抽出人手搞对原有旧版gpdb的版本升级工具。这时候不知道经过谁的推荐(是不是我们组的前PM:<a href="https://github.com/lij55" target="_blank">Jasper</a>?这里要感谢一下这个引荐人),我们得到上头的授权说我们可以投入人力和时间来搞gpcopy。于是我们组的<a href="https://github.com/adam8157" target="_blank">Adam</a>利用一个星期的时间用golang语言写了个prototype,于是这个项目就诞生了。同时,我们的项目从刚开始就被定位为闭源项目。</p>
<h1 id="追随gptransfer">追随gptransfer</h1>
<p>从与数据库的交互接口上来看,gptransfer和gpfdist是用External Table与gpdb进行交互的。External Table虽然是逐行处理数据,但是它走的是gpdb/pg的普通查询计划,所以可以很容易的修改计划添加motion节点,来支持数据的重分布(比如segment节点数不一样,需要将全部数据根据它的数据分布策略重新计算,从而分发到新的segment节点上)。而COPY ON SEGMENT衍生自pg的COPY SQL语句,语句的处理不是走普通的查询计划优化,所以要支持数据的重新分布非常困难(目前gpdb无法在不增加motion计划节点的情况下启用inter-connect去实现segment之间的数据交换,至少从代码的修改量上来看很难实现)。</p>
<p>由于刚开始这个项目时我们组的PM <a href="https://github.com/brianlugongyu" target="_blank">Brian</a>的定位是能够急迫解决gpdb的升级问题,我们就把相同segment数的gpdb之间的数据迁移作为我们的工作重点。除了重新实现gptransfer(用Python语言实现的,底层调用的gpfdist命令是用C写的)的所以相关功能,我们投入了很大的精力,在易用性、报错信息的容易理解性、性能等上面做出自己的亮点。特别值得一提的是gpcopy如果中间出现传输错误的表,会打印出重跑命令,用户可以通过拷贝来快速重新跑失败的任务,避免任务全部重新再跑一遍。另外由于gpcopy相对于gptransfer和gpfdist在并发控制和系统架构上要简单很多,这直接导致我们定位问题的难度降低很多、解决修复问题的速度也快了很多。</p>
<h1 id="超越gptransfer">超越gptransfer</h1>
<p>随着第一个版本的发布,用户的反馈非常好,很快用户就提出需求,希望全面替换gptransfer的功能。我们开始想办法支持不同segment数量的两个gpdb cluster之间的数据传输。期间很多好的想法被提出来,不断得尝试实现,特别是我们组的<a href="https://github.com/baotingfang" target="_blank">Bob</a>通过很简单的方案就窍门地解决了从segment数量少的gpdb cluster导到segment数量多的gpdb cluster。还有针对小表直接走master节点,不通过segment去启动多个并行任务,来减少启动的时间。</p>
<p>针对从segment数量少的gpdb cluster导到segment数量多的gpdb cluster的情况,我们实在是没有办法,最后又回到了利用External Table来实现的老路上来。</p>
<p>这里有篇文章介绍了这个时候的gpcopy:<a href="https://cloud.tencent.com/developer/news/355959" target="_blank">Greenplum数据迁移工具gpcopy升级到 1.1.0</a></p>
<p>从这篇文章可以看出gpcopy的性能在源gpdb和目标gpdb的segment数量一样的情况下,性格提升好几倍。读者可能对这个数据不是很直观,我举个例子:在国内最大客户的gpdb的最大数据量的gddb cluster上用gpcopy导到本地升级了的gpdb版本上,所花的时间要1天多点,这个时间在周末时候进行升级完全满足需要,但若是换成用gptransfer或者其他工具来导数据的话,那基本上这个在线系统需要停机一周以上,这样的维护时间,哪个公司能够承担得了呢?</p>
<p>除了这篇文章里介绍的,我觉得还有两点值得说一下:</p>
<ul>
<li><p>正则表达式的支持:通过制定正则表达式,将所有需要传输的表都列出来。</p></li>
<li><p>特殊字符的支持: 我和<a href="https://github.com/baotingfang" target="_blank">Bob</a>花了很多时间想要试着去解决gptransfer的特殊字符问题,但是由于启动gpfdist的路径与表名存在映射关系,导致特殊字符会出现在目录的路径上,这需要再加一层的转义,转义的规则也不一样,必须符合操作系统的目录的转义。而gpcopy的转义虽然也需要几层:比如Shell命令转义、SQL的字符串转义和标识符的转义,pg_dump的特殊字符处理等,这些转义相互套了好几层之后变得满目全非,问题调试起来也非常不容易,但是这些问题同样在gptransfer里也是一样存在的,如果它要实现特殊字符的支持,这些功能也是必要条件。</p></li>
</ul>
<p>有了这些更多的功能,再加上它更强的性能,更简单的问题发现和调试等优点,gpcopy牢牢占住了gptransfer的原来的位置。
以至于没过多久,PM们通过用户和技术支持团队的反馈,做出决定:不再支持gptransfer,同时将gptransfer的代码从gpdb中移除。(其实这点我是不赞成的,我觉得就算我们公司不想再对它技术支持,开源的源码也应该保留gptransfer。毕竟gpcopy是一个闭源项目)</p>
<h1 id="更上一层楼">更上一层楼</h1>
<p>自从pg的COPY支持SQL语句,gpdb随着pg内核版本升级,也轻而易举地支持COPY(SQL)TO&hellip;了,但是同样这个特性也是只支持SQL查询的数据收集到master再又master分发到各个segment再到出去。如何支持ON SEGMENT从句,从而使得SQL查询的结果不用汇总到master,而直接在各个segment上直接导出来呢?这看起来又成了一个大问题。</p>
<p>很多时候下班晚走,我和<a href="https://github.com/baobao0206" target="_blank">陈金豹</a>就常常聊起这个问题,聊起解决方案,他想到了可以参照CREATE TABLE AS SQL来实现。虽然我们都很憧憬着这个特性对gpcopy工具的新功能的影响,迫切期待,心急如焚得等待时机。那段时间<a href="https://github.com/baobao0206" target="_blank">陈金豹</a>一直在从事pg内核版本升级代码merge等工作,而当时我们组在忙于另一个新项目gp2gp(gpdb和gpdb之间的联邦并行查询)。终于<a href="https://github.com/baobao0206" target="_blank">陈金豹</a>自告奋勇,找了个机会抽出时间来自己完成了调研和实现。这是他实现的COPY (SQL) TO &hellip;ON SEGMENT语句中支持SQL的<a href="https://github.com/greenplum-db/gpdb/pull/6077" target="_blank">Pull Request</a>和<a href="https://github.com/greenplum-db/gpdb/commit/bad6cebc942ad2abc77b36b4d3a1d55236e33a18" target="_blank">Commit</a>。这里特别要感谢他做出的贡献,不单单是因为他是别的组,更要感谢他对技术实现的痴迷和对技术商业价值的敏感!</p>
<p>同时在他的帮助下,我们组的<a href="https://github.com/linwen" target="_blank">林文</a>和他一起努力将这个令人兴奋的特性backport到老版本gpdb5上。到这里,我们gpcopy就可以很容易支持针对特定表的特定查询(比如可以只查询某个特定时间段)进行并行导出了。有了这个功能,客户就可以用gpcopy来给数据做增量的数据迁移了。这个新功能一下子将gpcopy的从偶尔使用的工具变成了日常使用的工具,也是它从数据迁移的特性使用场景中拓展出其他的使用方法。</p>
<p>为了配合这个特性,我们组新来了<a href="https://github.com/JunfengYang" target="_blank">杨峻峰</a>很快实现了针对追加方式的验证,只要验证目标表中新插入的数据,而不是全部数据。另外我们还实现了重命名目标表:利用正则表达式的组概念进行对目标表的改名。另外我们组又来了<a href="https://github.com/beeender" target="_blank">Chen Mulong</a>,也开始加入对gpcopy进行精雕细琢。</p>
<p>通过这次新的版本发布,希望gpcopy能够迎来更广的使用场景,拥有有更好的未来!</p>
<p>最后,再次感谢为gpcopy项目做出贡献的同事们!</p>
</description>
</item>
<item>
<title>用packer创建Amazon AWS上的AMI</title>
<link>https://liming01.github.io/post/packer_ami/</link>
<pubDate>Mon, 13 Mar 2017 11:00:00 +0000</pubDate>
<guid>https://liming01.github.io/post/packer_ami/</guid>
<description>
<p>&mdash;&mdash; 作者:李明(email: mli@apache.org)</p>
<p>本文是工作中的日志:如何用packer创建Amazon AWS上的AMI。</p>
<h1 id="using-packer-to-generate-a-amazon-aws-ami">Using packer to generate a Amazon AWS AMI</h1>
<ol>
<li><p>Install packer on mac:</p>
<ul>
<li>Using command “brew install packer”</li>
<li>Or download packer from <a href="https://www.packer.io/" target="_blank">https://www.packer.io/</a></li>
</ul></li>
<li><p>Install awscli on mac:</p>
<ul>
<li>“pip install &ndash;upgrade &ndash;user awscli”</li>
<li>add aws path into $PATH : “export PATH=~/Library/Python/2.7/bin:$PATH”</li>
</ul></li>
<li><p>login aws web site: <a href="https://console.aws.amazon.com/console/home" target="_blank">https://console.aws.amazon.com/console/home</a></p>
<ul>
<li>create key-pair @ &ldquo;Service =&gt; Compute =&gt; EC2 =&gt; Key Pairs =&gt; Create Key Pair&rdquo;, and download the generated file &lsquo;user.pem&rsquo; into ~/.aws, and chmod 400 user.pem.</li>
<li>Add user access key @ &ldquo;Service =&gt; Security, Identity &amp; Compliance =&gt; IAM =&gt; User =&gt; click your username =&gt; Security credentials =&gt; Create access key&rdquo; and download the generated info file &lsquo;accessKeys.csv&rsquo;</li>
</ul></li>
<li><p>Set up awscli config:</p></li>
</ol>
<p>vi ~/.aws/credentials (Below info is generated by step 3(b))</p>
<pre><code> [default]
aws_access_key_id=XXXXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
</code></pre>
<p>vi ~/.aws/config</p>
<pre><code> [default]
region=us-west-2
output=json
</code></pre>
<ol>
<li><p>check awscli credential info setup correctly: aws ec2 describe-instances</p></li>
<li><p>Search source_ami for packer</p>
<ul>
<li>go to <a href="https://aws.amazon.com/mp/" target="_blank">https://aws.amazon.com/mp/</a>, click Continue to AWS marketplace.</li>
<li>&rdquo; Porpular Categories =&gt; Operating Systems =&gt; Search OS keyword&rdquo;</li>
<li>select one item, and click the &ldquo;continue&rdquo; button =&gt; Manual Launch =&gt; select your region ami id. e.g. centos7.2 is US West (Oregon) ami-775e4f16.</li>
</ul></li>
<li><p>Set credentials.json (which is same as step 4) for passing “&ndash;var-file credentials.json” to packer, or you can directly pass these value as shell param “-var &lsquo;aws_access_key=xxxxxx&rsquo;” to packer command.</p></li>
</ol>
<p>vi ~/.aws/credentials.json</p>
<pre><code class="language-json">{
&quot;aws_access_key_id&quot;:&quot;XXXXXXXXXXXXXXXXX&quot;,
&quot;aws_secret_access_key&quot;:&quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&quot;
}
</code></pre>
<ol>
<li><p>set “source_ami” below to the ID fetched at step 6&copy;.
vi /Users/gpadmin/workspace/hawq2ci/GPDB-HAWQ-DynamicProvisioning/packer/ami_test.json</p>
<pre><code class="language-json">{
&quot;variables&quot;: {
&quot;aws_access_key&quot;: &quot;&quot;,
&quot;aws_secret_key&quot;: &quot;&quot;,
&quot;name&quot;: &quot;HAWQ_RHEL7.2_HVM&quot;
},
&quot;builders&quot;: [{
&quot;type&quot;: &quot;amazon-ebs&quot;,
&quot;access_key&quot;: &quot;{{user `aws_access_key`}}&quot;,
&quot;secret_key&quot;: &quot;{{user `aws_secret_key`}}&quot;,
&quot;region&quot;: &quot;us-west-2&quot;,
&quot;source_ami&quot;: &quot;ami-775e4f16&quot;,
&quot;instance_type&quot;: &quot;t2.micro&quot;,
&quot;ssh_username&quot;: &quot;ec2-user&quot;,
&quot;ami_name&quot;: &quot;{{user `name`}} {{timestamp}}&quot;
}],
&quot;provisioners&quot;: [{
&quot;type&quot;: &quot;shell&quot;,
&quot;inline&quot;: [
&quot;sleep 30&quot;,
&quot;echo 'for test'&quot;
]
}]
}
</code></pre>
<ol>
<li>Run the command to validate the json file
<code>shell
cd /Users/gpadmin/workspace/hawq2ci/GPDB-HAWQ-DynamicProvisioning/packer
packer validate ami_test.json
</code></li>
</ol></li>
<li><p>Build AMI.</p>
<pre><code class="language-shell">packer build --var-file ~/.aws/credentials.json ami_test.json
</code></pre>
<h1 id="run-ec2-instance-from-a-ami">Run EC2 Instance from a AMI</h1>
<p>We use pre-exists vpc and subnet.</p>
<ol>
<li>Create security group
<code>shell
aws ec2 create-security-group --group-name mli_sg --description &quot;My security group for testing&quot; --vpc-id vpc-4ef3972a
aws ec2 describe-security-groups --group-ids sg-7c143b04
</code></li>
</ol></li>
<li><p>Add Inbound SSH access</p>
<pre><code class="language-shell">aws ec2 authorize-security-group-ingress --group-id sg-7c143b04 --protocol tcp --port 22 --cidr 10.34.0.0/16
</code></pre>
<ol>
<li>Run EC2 Instance
<code>shell
aws ec2 run-instances --image-id ami-d9e26eb9 --count 1 --instance-type t2.micro --key-name mli --security-group-ids sg-a398b7db --subnet-id subnet-a65cc3c2
</code></li>
</ol></li>
</ol>
</description>
</item>
<item>
<title>强者更强:HAWQ性能的思考</title>
<link>https://liming01.github.io/post/hawq_new_feature/</link>
<pubDate>Wed, 20 Apr 2016 11:00:00 +0000</pubDate>
<guid>https://liming01.github.io/post/hawq_new_feature/</guid>
<description>
<p>&mdash;&mdash; 作者:李明(email: mli@apache.org)</p>
<p>SQL on Hadoop产品非常繁多,从性能角度来看,比较好的有HAWQ、Impala。虽然目前HAWQ还是大幅领先于Impala(参见:<a href="https://blog.pivotal.io/big-data-pivotal/products/performance-benchmark-pivotal-hawq-beats-impala-apache-hive-part-1" target="_blank">pivotal公布的hawq性能测试</a>),但是从最近的Impala的<a href="https://www.cloudera.com/documentation/enterprise/release-notes/topics/impala_new_features.html#new_features_250" target="_blank">新版本发布公告</a>来看,它最近一直集中精力实现各种新的优化手段。为了使HAWQ继续保持竞争力,我们有必要学习其他竞争对手的优点,才能做到“知彼知己者,百战不殆”。</p>
<div class="alert alert-note">
<div>
本文的观点仅代表本人观点,用于学习探讨交流。若因此出现经济、法律等方面的,与本人无关。
</div>
</div>
<h2 id="hawq-to-do-list">HAWQ TO DO LIST</h2>
<ul>
<li><p>Data skipping for I/O bound query:</p>
<ul>
<li>parquet/orc index( min/max/bloom filter) usage<br /></li>
<li>Runtime filter</li>
<li>Dynamic partition pruning
<br /></li>
</ul></li>
<li><p>Intra-Operator parallel processing vs vSeg number:</p>
<ul>
<li>IO intensive operator: base table scan: thread number = disk rotationar number</li>
<li>CPU intensive operator: joins/aggregations/sort/top-N, thread number = cpu core number
<br /></li>
</ul></li>
<li><p>LLVM Codegen for CPU bound query:</p>
<ul>
<li>Function call unrolling and branch pruning: Expression/loop/no switching</li>
<li>CPU intensive operator: joins/aggregations/sort/top-N</li>
<li>more hotspots: counting the elements of a complex column, Checking for overflow in DECIMAL multiplication, &hellip;</li>
</ul></li>
<li><p>Use HDFS caching feature to &ldquo;pin&rdquo; entire tables or individual partitions in memory, to speed up queries on frequently accessed data and reduce the CPU overhead of memory-to-memory copying.</p></li>
<li><p>Duplicate small table to all segments to speed up join with other distributed tables.</p></li>
<li><p>streaming pre-aggregation: decides at run time whether it is more efficient to do an initial aggregation phase and pass along a smaller set of intermediate data, or to pass raw intermediate data back to next phase of query processing to be aggregated there.</p></li>
<li><p>Optimization for small queries let Impala process queries that process very few rows without the unnecessary overhead of parallelizing and generating native code.</p></li>
<li><p>more parallel processing: SIMD, vectorization</p></li>
<li><p>Distributed by hash is one kind of partition?</p></li>
<li><p>better info for different level: explain/SUMMARY/profile</p></li>
</ul>
</description>
</item>
<item>
<title>大数据数据库的技术对垒:MapReduce vs. MPP</title>
<link>https://liming01.github.io/post/mpp_mp/</link>
<pubDate>Fri, 20 Nov 2015 12:00:00 +0000</pubDate>
<guid>https://liming01.github.io/post/mpp_mp/</guid>
<description>
<p>&mdash;&mdash; 作者:李明(email: mli@apache.org)</p>
<p>这些年大数据概念已经成为IT界的热门,我们经常也会在新闻和报纸中看到。大数据概念中最为关键的技术就是数据库管理系统,伴随着Hadoop和MapReduce技术的流行,大数据的数据库中Hive和Spark等新型数据库脱颖而出;而另一个技术流派是基于传统的并行数据库技术演化而来的大规模并行处理(MPP)数据库比如GreenPlum和HAWQ也在最近几年突飞猛进,这两种流派都有对应的比较知名的产品,他们都已得到了市场的认可。</p>
<p>然而对于一个不是搞大数据的门外汉,如何理解大数据概念,如何根据自身的需求来选择对应的数据库管理系统,就成了很多用户很关心的话题。本文将采用比较通俗易懂的介绍,让大家从本质上认识这些大数据库管理系统的技术实现和应用场景。</p>
<h2 id="map-reduce技术">Map Reduce技术</h2>
<p>大数据概念,顾名思义就是要解决数据量很大的情况下的数据库处理问题,所以在数据量增长很快的情况下,如何让处理的时间不能增长太多就成了关键。学习过算法的同学们很快能够举出例子,比如对半查找法,在一个已排序好的数据集中如何找到和指定数相等的位置?</p>
<ul>
<li>最笨的方法是从头到尾查找一遍,这个时间复杂度跟数据量是1:1的关系;</li>
<li>比较好的方法是,讲这个数据分成几段,每段由单独的计算机去算,这样效率能提高n倍(n为分为的段数),时间复杂度跟数据量是1:n的关系;</li>
<li>而对半查找法则是根据已知数据集是排好序的,所以我们只要在数据集的中间位置比较一下,就能知道我们要找的数据是在前半段还是后半段,然后选取有效的半段递归下去,直到有效半段只含一个数值就找到值相等的位置了,这个时间复杂度是1:2^m(m为递归循环的次数)。</li>
</ul>
<p>假设我们有1024个数,那么用这三个方法的处理时间比值为:1024:1024/n:10。从这个比值上很容易看出,随着数据量的增大,第三种方法的优势越发明显。</p>
<p>如何让普通的数据处理也能像对半查找法一样高效,Google发表的论文提出了Map Reduce编程模型。该模型比较抽象复杂,接下来我用生活中的例子来说明该模型设计的原理。比如在一个大学里的大课堂里,老师想要知道上课的学生总数(实际上就是数据库的count操作),于是他让学生做如下事情:</p>
<ol>
<li>所有的学生都站起来,同时每个学生记住自己的人数为1</li>
<li>每个同学都各自寻找站着的学生,找到后进行如下操作(假设学生A找到学生B):
<ul>
<li>A的最新人数=A的旧人数+B的人数</li>
<li>B坐下,A站着,继续步骤2.直到最后站着的人只剩下一个,那么该人持有的人数就是这堂课学生的总数。</li>
</ul></li>
</ol>
<p>通过上面这个方式来算总人数,实际上是上面介绍的对半查找法的逆操作:</p>
<ol>
<li>当只有一个学生站着的时候,改学生拿到的数就是总人数(计算结果);对应到对半查找法输入待查找的数据集(算法初始状态)</li>
<li>当最后只剩下最后2名学生站着的时候,它正要把两个学生各自持有的总人数相加,它就像是对半查找法的第一次,找到中间的位置,判断相等的数应该是在前半段还是在后半段里。</li>
<li>当最后剩下4名学生站着的时候,他们会分成两组来处理,每组算出各自组的总人数,并每组只留一个同学站着;而对半查找法里则是在步骤2里选择出来的半段里,再坐对半查找。</li>
<li>……</li>
<li>当最后剩下2^n名学生站着的时候(假设此时每个学生都站着),各自记住人数为1;对应到对半查找法里就是在n-1步骤处理完后选择的半段数据集个数只为1,找到要查找的数据。</li>
</ol>
<p>通过上面的对比我们不难发现,无论是从计算方式来看,还是从数据处理/搜索空间来看,这两个算法是互逆的。唯一的不同是对半查找法不需要再对已经判断舍弃的半段不用在运行,比如3)步骤中,对边查找继续搜索前半段或者后半段,但是学生点人数确实两组学生都要进行报数计算。</p>
<p>学生点人数的方法看起来真的非常完美,可是这里面忽略了一个问题,那就是计算资源的问题,上面的每个学生都可以作为一个计算资源。而在现实中计算资源不会像这个例子一样那么多。所以还需要考虑如何讲这些步骤放到有限的计算资源上运行的问题。Map Reduce编程模型就是为了实现将很多复杂运算,以上面学生算总人数的方式去执行的一种编程模型。学生点人数中步骤1抽象为Map(每个学生都map成一个人数1),步骤2中的1)和2)就是Reduce操作,(将学生A和B两个学生站着处理完变成只有一个A站着)。同时考虑到在计算资源有限的情况下如何进行性能优化的问题,该编程模型还会将很多人的map操作,变为一个集合的map操作,讲多次Reduce操作变为一次集合的reduce操作。这样每个map或reduce就可以很方便地在一个计算资源(比如一个计算机)上进行运算了。</p>
<h2 id="大规模并行处理-mpp-技术">大规模并行处理(MPP)技术</h2>
<p>Mpp技术是从原来的并行数据库发展而来的,基于关系数据库的成熟技术,伴随着分布式与并行数据库技术的发展而来的。其中最为关键的技术就是它能够判断出数据之间的相互依赖关系,将可以并行的部分分发到各个节点上并行运行,针对关系数据库中最为常用的等值比较和等值联接(Join)等操作做出特别的优化,将待比较的列按照某种规律进行hash,根据不同的hash值分发到不同的节点上去进行比较处理(它可以被看做是Hash Join的分布式版本)。将查询中能并行的操作和操作产生的中间结果,通过这样的方式分发到不同的节点上去运算,从而最大程度地并行处理,来达到提高性能的方法。</p>
<p>回到前面讲的学生点人数的例子,MPP的思路就是,根据现有的计算资源,将全班学生先按照简单规则分组排队,比如现有n台计算节点,我们就可以把全班学生分成n队,然后每队放到一个计算节点上去计算,计算完讲每队的计算结果再进行相加得到最后全班的总人数。</p>
<h2 id="数据库管理系统中两种技术的优劣分析">数据库管理系统中两种技术的优劣分析</h2>
<h3 id="性能比较">性能比较</h3>
<p>可能细心的读者已经发现,MPP的学生点人数的处理方式不就是我在前面介绍的查找指定数例子中的第二个方法嘛;而Map Reduce对应的第三种方法看起来更高效啊。这句话在理想状态下是成立的,不过回到数据库管理系统里来看,采用这两种方式的性能比较就得另说了。</p>
<p>根据前面论述的理论处理时间比值:“假设我们有1024个数,那么用这三个方法的处理时间比值为:1024:1024/n:10”,似乎很难让我们觉得这样的方法针对大数据处理有何优势。但是也正如我前面所说的,如果考虑计算资源的个数是有限的情况下,这个理想的比值又得重新改写了。</p>
<p>试想一下,采用Map Reduce方式处理的学生点人数例子,在有限的计算资源下的模型应该添加一条这样的流程:
1.每两个站着的学生要相加持有的人数时,需要到一个专门的地方去排队认证(每个认证的地方就是一个计算资源)。</p>
<p>在这样的规则下,我们再来讨论Map Reduce和MPP的性能对比。比如我们就只有3个计算资源,那么Map Reduce这种修改后的点人数流程能够发挥的最大性能,跟MPP先分3队,再点人数的性能已经没有区别了。更何况如何协调两个站着的学生去认证处排队,也比MPP现通过简单方法分队再处理更耗时间,这样会导致每次数据库查询的初始化等准备时间增加很多。</p>
<p>而且目前所有的数据库管理系统一般都是部署到特定的节点上的,所以能利用计算资源都是一定的。所以Map Reduce在这种情况下很难发挥优势。更为糟糕的是,因为一般的数据库查询,可能会涉及到很多操作及其他们之间的依赖关系(在关系数据库中,查询一般都会被转化为查询树,用来表示操作节点之间的先后顺序),这样很多情况是无法做到并行处理的。而MPP数据库能够利用传统的关系数据库技术,更容易根据这些依赖关系来规则执行计划,达到最大程度的并行处理。</p>
<h3 id="其他方面的因素">其他方面的因素</h3>
<p>由于Map Reduce模型与传统的数据库处理技术相去甚远,很难将传统数据库支持的所有操作都毫无差异地用它重新实现一遍,所以通过它实现的数据库管理系统在支持传统的数据库复杂查询时就显得力不从心了。另外在语言数据库的接口,SQL标准的支持,性能调优配置等方面也因为不能继承关系数据库的成熟技术,而导致学习门槛增高,易用性难于保证。</p>
<h3 id="真实的tpc-ds测试比较">真实的TPC-DS测试比较</h3>
<p>根据上面的分析,我们不难看出MPP数据库的优势,下面我们选取同样都是底层文件系统采用Hadoop的HDFS分布式文件系统作为数据存储,上层采用MPP技术的HAWQ与采用Map Reduce的Hive在TPC-DS基准测试中的对比结果吧(数据来自:<a href="https://blog.pivotal.io/big-data-pivotal/products/performance-benchmark-pivotal-hawq-beats-impala-apache-hive-part-1" target="_blank">pivotal公布的hawq性能测试</a>):</p>
<ul>
<li>性能:简单查询性能相当;HAWQ在处理复杂语句的性能是Hive的三四倍左右。</li>
<li>对复杂查询的支持:Hive只支持基准测试99条语句中的66条,而HAWQ支持全部。</li>
</ul>
<h2 id="总结">总结</h2>
<p>Map Reduce计算模型在计算资源无限、数据无相关性的情况下很容易具有良好的扩展性,特别适用于计算网格等领域或者简单数据库查询的处理上。但是就目前而言,在实现数据库管理系统领域,它仍然受限与资源分配、数据相关性等因素的制约,很难达到MPP发展的高度。不过技术发展日新月异,也许不出时日,它就能突破这些障碍,或者与MPP技术结合,或许有新技术助力,追平甚至超越MPP数据库也是很有可能的。</p>
</description>
</item>
<item>
<title>Apache HAWQ</title>
<link>https://liming01.github.io/project/hawq/</link>
<pubDate>Sun, 27 Apr 2014 00:00:00 +0000</pubDate>
<guid>https://liming01.github.io/project/hawq/</guid>
<description></description>
</item>
<item>
<title>Greenplum Database</title>
<link>https://liming01.github.io/project/gpdb/</link>
<pubDate>Sun, 27 Apr 2014 00:00:00 +0000</pubDate>
<guid>https://liming01.github.io/project/gpdb/</guid>
<description></description>
</item>
</channel>
</rss>