本文简单记录一个学习过程,无技术含量,勿喷。
环境:
ambari:2.6.1
spark 2.1
python 3.6
oracle 11.2
sqoop 1.4
最近一直在测试数据采集、清洗、分析、导出、展示的一系列的工作,主要数据流程如下:
oracle 数据库-》hdfs-》hive-》oracle
总的设计:通过任务调度的方式执行各个阶段的任务,其中各个任务通过脚本的方式实现,扩展的时候只需要增加对应的脚本和调度任务就可以。
各个阶段的描述:
数据采集:主要是通过sqoop将oracle数据导入hdfs中。采集前,先列好采集清单和规则,以及采集后数据存放规则。
数据清洗:主要是通过pyspark将hdfs文件清洗拆分然后存放到HIVE数据库,通过将清洗后的数据移动到备份文件夹。
数据分析:通过pyspark读取数据清洗后的数据进行分析,将分析结果放到HIVE中。
数据导出:通过PYSPARK读取hive数据,然后通过python连接ORACLE数据进行插入。
数据展示:将分析后的数据通过web的方式提供展示。
数据导出按原设计是通过sqoop导出到oarcle,后面碰到一下问题就否决了。
1.数据只能全表导出,不支持增量和条件导出。
后想到的解决方案是:
1.数据分析的时候保存2份数据,一份是作为历史数据存储,一份是作为数据导出临时数据存储。导出的时候只导临时数据,导完删除。当然还有一些细节处理,比如如何解决多任务同时使用的问题。不做详细描写。
2.通过数据分析表记录分析数据的日期的日志,根据日志日期导出数据到oracle,导完后记录每个表导出的日期,下次导出时,只导出该表导出日志中最大日期之后的数据。
后来选择了第2种方案。原因个人喜好。
在第2中方案中,又出现一个选择,一个是通过spark sql直接保存数据到orcale,后发现一个问题,只能保存到oracle中不存在的表,比较怕麻烦,没有继续。
(本点后面发现,spark sql直接写oracle数据库的时候有个写入mode的设置,可以覆盖和追加:
durl = "jdbc:oracle:thin:@//127.0.0.1:1521/clearing" tmptable.write.jdbc(durl, Tablename,mode="append", properties={"user": "username", "password": "password"})
原来尝试过
tmptable.write.mode("append").jdbc(durl, Tablename, properties={"user": "username", "password": "password"})这样写数据库(oralce和mysql)mode不生效,但是写hdfs文件是生效的。
)
最终采用了通过spark sql读取hive数据,然后通过python将数据插入到oracle的方式,比较笨的方法,但是简单。
在这个过程中碰到的问题:
1.数据清洗出现空文件的时候,报RDD is empty的错误,导致任务失败。
原因:导入的文件夹下面存在一个空的文件,然后通过RDD.isEmpty的方法判断不生效,后改为rdd.count==0的判断。
2.清洗过程出现连接lntnn2/10.250.11.53:41574失败的警告,而且任务执行变慢
解决方案:查看namenode空间,发现只是2g空间,删除日志等文件,任务执行正常。
3.同时跑2个或以上任务的时候,容易出现以下警告:
javax.servlet.ServletException: Could not determine the proxy server for redirection
at org.apache.hadoop.yarn.server.webproxy.amfilter.AmIpFilter.findRedirectUrl(AmIpFilter.java:205)
at org.apache.hadoop.yarn.server.webproxy.amfilter.AmIpFilter.doFilter(AmIpFilter.java:145)
at org.spark_project.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1676)
at org.spark_project.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:581)
at org.spark_project.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1180)
at org.spark_project.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
at org.spark_project.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112)
at org.spark_project.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.spark_project.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:461)
at org.spark_project.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:213)
at org.spark_project.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
解决方法:
暂时未有明确的解决方法,怀疑是机器性能不够,将每个mapradue的最大内存设为2g,效果不明。
4。通过python插入oracle数据库数据,UnicodeEncodeError: 'ascii' codec can't encode characters in position 100-101: ordinal not in range(
解决方法:
根据数据库不同的编码设定,编写的python脚本中需要相对应的加入如下几句:
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' #或者os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.AL32UTF8'