设为首页 收藏本站
查看: 1203|回复: 0

[经验分享] AWS Redshift ETL的几个性能最佳实践

[复制链接]

尚未签到

发表于 2019-2-22 11:10:36 | 显示全部楼层 |阅读模式
  Amazon Redshift 是一个支持SQL查询的、快速、可扩展的列式存储数据库,它支持PB级的数量查询,是适用于企业级的数据仓库。同时Redshift支持大规模并发查询、支持结果集缓存,响应查询时间最快至亚秒,比起其他数据仓库快将近十倍。借助 Redshift,您的等待时间更少,可将更多时间用于获取数据见解。
  ETL在计算机领域是一个很流行的概念,意指将数据从一个或多个源头复制到目标系统的一个过程,其中包含三个步骤:
1,Extract       从数据源中选择/提取需要导出的数据
2,Transform     将导出的数据根据业务需要进行必要的格式/表现形式上的转换
3,Load          将转换后的数据导入目标系统
  在使用Redshift之前需要将数据导入Redshift,即Redshift的ETL。例如数据库的迁移,将旧数据库中的数据转移到Redshift等等。
本文旨在分享我们bosicloud在日常工作中关于Redshift ETL方面的一些技巧及建议:
  1,使用COPY命令将多个、大小相当的文件加载到Redshift
Amazon Redshift是一个MPP数据库,即大规模并行处理数据库,Redshift的背后是一个EC2集群,每个计算节点(ec2)进一步细分为slice,所有slice平分计算节点的处理能力。 每个节点的slice数量取决于群集的节点类型。 例如,每个DS2.XLARGE计算节点都有两个slice,而每个DS2.8XLARGE计算节点有16个slice。

进行加载数据工作时,最好的情况是整个工作量平分给所有的计算节点(EC2 node)的slice。当只加载一个大文件,或者加载多个大小差异较大的文件时,都可能导致计算节点工作量分配不均等,进而导致整个Redshift加载数据时性能低下。例如,我们Redshift有两个计算节点,在加载一个大文件时每个节点的工作负载如下:

从上图可以看到,加载的任务落在了compute-0头上,而compute-1则是闲置的,这是一个木桶原理,Redshift最终花费的时间等于工作时间最长的那个计算节点。
所以我们最好将大文件切割为多个大小相同的小文件,并且文件总数量正好是计算节点的整倍数,从而每个计算节点可以分到数目相同的小文件。另外,我们还建议将这些小文件进行压缩,例如gzip, lzop, or bzip2因为Redshift加载及存储数据时都支持这几种压缩格式。显然,压缩后的数据更小了,加载的工作量也就更小了。
  2,使用workload management合理调整Redshift queue
Redshift通过workload management(WLM)管理着多个queue,用户提交SQL查询任务到Redshift时,SQL会根据提交者所在的group被分派到group对应的queue排队等候执行。Redshift的内存及计算能力被分成许多个单元/单位,一个slot代表一个单元的内存及计算能力,一个slot同一时间可以执行一个SQL查询任务,不同的queue拥有不同数量的slot,slot的数量决定该queue能够同时并发执行多少个SQL查询任务。因为ETL往往伴随着许多COMMIT 操作,而COMMIT 都很消耗计算资源。为了进行ETL的同时不影响普通用户提交SQL query,我们bosicloud建议将ETL和普通用户提交的SQL query分发到不同的queue中。否则普通用户query可能由于等待ETL COMMIT导致不能及时响应。

另外,为了加快Redshift的COPY ETL过程,我们还可以通过wlm_query_slot_count参数调整ETL queue的slot数量,从而增加queue的内存、计算能力及SQL查询并发数量。


                                             Redshift的WLM设置界面
  3,使用”BEGIN…COMMIT”减少COMMIT次数前面我们提到ELT是一个多步骤的任务,每个步骤最后往往需要执行一个COMMIT,而COMMIT又是一个昂贵的操作。所以我们bosicloud建议使用BEGIN…END 将能够合并的多个步骤尽量合并为一个步骤并只执行一次COMMIT,例如:
Begin
CREATE temporary staging_table;
INSERT INTO staging_table SELECT .. FROM source;
DELETE FROM table1 WHERE  ???=???;
INSERT INTO table1 SELECT .. FROM staging_table;
DELETE FROM table2 WHERE ???=???;
INSERT INTO table2 SELECT .. FROM staging_table;
Commit
  4,使用Redshift Spectrum for ad-hoc查询
在以往,我们可以会为了做ad-hoc查询而将S3上的数据ETL加载到Redshift进行查询。如果仅为了偶尔的一两次查询而进行ETL,这个ETL将显得非常昂贵、不划算。别忘了AWS最近推出了Redshift Spectrum新功能,即您可以直接利用Redshift Spectrum查询S3上的数据而无需将数据加载到Redshift中,虽然Specturm查询相比普通Redshift查询较慢,但比起ETL来说查询速度仍然是大大提升了。
  5,关于ETL健康检查的SQL实用脚本:
   返回过去1天内queue的统计信息,例如最大队列长度和队列时间
select startqueue,node, datediff(ms,startqueue,startwork) as queue_time, datediff(ms, startwork, endtime) as commit_time, queuelen
from stl_commit_stats
where startqueue >=  dateadd(day, -1, current_Date)
order by queuelen desc , queue_time desc;
   返回一个星期内所执行的COPY的相关信息,如COPY的开始时间(Starttime),所在queue的ID(query),SQL语句(querytxt),COPY的文件数量(n_files)及文件大小(size_mb)等等:
select q.starttime,  s.query, substring(q.querytxt,1,120) as querytxt,
s.n_files, size_mb, s.time_seconds,
s.size_mb/decode(s.time_seconds,0,1,s.time_seconds)  as mb_per_s
from (select query, count() as n_files,
sum(transfer_size/(1024
1024)) as size_MB, (max(end_Time) -
min(start_Time))/(1000000) as time_seconds , max(end_time) as end_time
from stl_s3client where http_method = 'GET' and query > 0
and transfer_time > 0 group by query ) as s
LEFT JOIN stl_Query as q on q.query = s.query
where s.end_Time >=  dateadd(day, -7, current_Date)
order by s.time_Seconds desc, size_mb desc, s.end_time desc
limit 50;
     建立view视图查看每个表空间使用情况,请考虑将空间增长较快的表的内容unload到S3.
  CREATE OR REPLACE VIEW admin.v_space_used_per_tbl
AS with info_table as ( SELECT TRIM(pgdb.datname) AS dbase_name
,TRIM(pgn.nspname) as schemaname
,TRIM(pgc.relname) AS tablename
,id AS tbl_oid
,b.mbytes AS megabytes
,CASE WHEN pgc.reldiststyle = 8
THEN a.rows_all_dist
ELSE a.rows END AS rowcount
,CASE WHEN pgc.reldiststyle = 8
THEN a.unsorted_rows_all_dist
ELSE a.unsorted_rows END AS unsorted_rowcount
,CASE WHEN pgc.reldiststyle = 8
THEN decode( det.n_sortkeys,0, NULL,DECODE( a.rows_all_dist,0,0, (a.unsorted_rows_all_dist::DECIMAL(32)/a.rows_all_dist)100))::DECIMAL(20,2)
ELSE decode( det.n_sortkeys,0, NULL,DECODE( a.rows,0,0, (a.unsorted_rows::DECIMAL(32)/a.rows)
100))::DECIMAL(20,2) END
AS pct_unsorted
FROM ( SELECT
db_id
,id
,name
,MAX(ROWS) AS rows_all_dist
,MAX(ROWS) - MAX(sorted_rows) AS unsorted_rows_all_dist
,SUM(rows) AS rows
,SUM(rows)-SUM(sorted_rows) AS unsorted_rows
FROM stv_tbl_perm
GROUP BY db_id, id, name
) AS a
INNER JOIN
pg_class AS pgc
ON pgc.oid = a.id
INNER JOIN
pg_namespace AS pgn
ON pgn.oid = pgc.relnamespace
INNER JOIN
pg_database AS pgdb
ON pgdb.oid = a.db_id
INNER JOIN (SELECT attrelid,
MIN(CASE attisdistkey WHEN 't' THEN attname ELSE NULL END) AS "distkey",
MIN(CASE attsortkeyord WHEN 1 THEN attname ELSE NULL END) AS head_sort,
MAX(attsortkeyord) AS n_sortkeys,
MAX(attencodingtype) AS max_enc,
SUM(case when attencodingtype  0 then 1 else 0 end)::DECIMAL(20,3)/COUNT(attencodingtype)::DECIMAL(20,3)  100.00 as pct_enc
FROM pg_attribute
GROUP BY 1) AS det ON det.attrelid = a.id
LEFT OUTER JOIN
( SELECT
tbl
,COUNT(
) AS mbytes
FROM stv_blocklist
GROUP BY tbl
) AS b
ON a.id=b.tbl
WHERE pgc.relowner > 1)
select info.*
,CASE WHEN info.rowcount = 0 THEN 'n/a'
WHEN info.pct_unsorted  >= 20 THEN 'VACUUM SORT recommended'
ELSE 'n/a'
END AS recommendation
from info_table info;
     找出本周内最费时间的前50个SQL查询(多个相同的sql查询时间合并计算)
-- query runtimes
select trim(database) as DB, count(query) as n_qry, max(substring (qrytext,1,80)) as qrytext, min(run_seconds) as "min" , max(run_seconds) as "max", avg(run_seconds) as "avg", sum(run_seconds) as total,  max(query) as max_query_id,
max(starttime)::date as last_run, aborted,
listagg(event, ', ') within group (order by query) as events
from (
select userid, label, stl_query.query, trim(database) as database, trim(querytxt) as qrytext, md5(trim(querytxt)) as qry_md5, starttime, endtime, datediff(seconds, starttime,endtime)::numeric(12,2) as run_seconds,
aborted, decode(alrt.event,'Very selective query filter','Filter','Scanned a large number of deleted rows','Deleted','Nested Loop Join in the query plan','Nested Loop','Distributed a large number of rows across the network','Distributed','Broadcasted a large number of rows across the network','Broadcast','Missing query planner statistics','Stats',alrt.event) as event
from stl_query
left outer join ( select query, trim(split_part(event,':',1)) as event from STL_ALERT_EVENT_LOG where event_time >=  dateadd(day, -7, current_Date)  group by query, trim(split_part(event,':',1)) ) as alrt on alrt.query = stl_query.query
where userid  1
-- and (querytxt like 'SELECT%' or querytxt like 'select%' )
-- and database = ''
and starttime >=  dateadd(day, -7, current_Date)
)
group by database, label, qry_md5, aborted
order by total desc limit 50;
  【关于博思云为】
作为一家专业的云计算服务型企业,博思云为专为客户提供 AWS 上的运营服务:包括架构咨询服务、迁移服务、云安全集成服务、混合云管理服务、大数据服务以及 DevOps 服务。目前,博思云为在大数据、DevOps、架构、数据库以及操作系统等都已取得厂商认证,在上海、南京、杭州、武汉等地设有分公司。为创新服务模式、引领 IT 服务业的发展,博思云为将持续投入资源开展智能混合云管理平台、图数据库的研发等。





运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-675733-1-1.html 上篇帖子: 您如何创建AWS图表? 下篇帖子: AWS System Manger 批量操作EC2 实例
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表