数据专栏

智能大数据搬运工,你想要的我们都有

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

「深度学习福利」大神带你进阶工程师,立即查看>>>
 
 8 月 27 日晚上八点,七牛云高级解决方案架构师程雪松在 IT 大咖说进行了题为《挖掘传统行业日志大数据的无限价值》的直播,对传统行业运维常见困境和统一日志管理的必要性进行了深入解析,并通过 Pandora 的一些真实用户案例和大家详细阐述了如何挖掘传统行业日志大数据的无限价值。本文是对直播内容的整理。 

下篇主要剖析了日志管理平台建设关注的要点以及分享了 Pandora 的一些真实用户案例,并针对听众的提问进行了解答。 
  
监控与告警

 数据分析过后,需要形成相关的数据的监控和告警。比如把一些我关心的重要的指标监控固化下来,定期地对这些数据进行监控,一旦它出现问题,我需要及时地反映出来,形成一些告警方面的通知。最好是能够把搜索结果直接保存为告警设置。比如说我搜索出一个结果出来之后,我觉得这个结果很重要,这个分析出来的结果,我不仅只是想查这一次,需要它一直能够被监控起来。一旦这个监控值出现问题,我就能够报警。那么就可以另存为报警以后去设置相关的一些策略,比如说我要去监控这个指标的最大值、最小值、平均值等等,然后这个值一旦突破了某个阈值,就能够通过短信或者邮件的方式,来进行及时的报警,这就是监控报警的一个功能,它是必须要有的。 
  
开箱即用的报表

    
 然后就是可视化的展现,能够支持各种各样的图表,把一些比较难懂的文本型的日志,或者数据型的日志,变成更易读更直观的一些报表,制作成一些大家比较能够理解的比如说饼图,柱状图,折线图,甚至你可能会遇到像中国地图,世界地图等等。我预先要支持这样的图表,能够很方便的去定义这些报表的功能,把数据输入进去,选择相关的图表的格式,自动去生成这样的一些报表。这样的话你就能够很方便地去体现你的日志分析结果和相关参数的监控。 
  
大屏展示

    
 而且最终也能支持大屏展示,能够投射到指挥台或者监控大屏。让我们的 IT 运维人员或者 IT 部门的领导,或者甚至是公司的老板,能够方便看到信息化平台的情况,内部系统是如何运行的,现在的状态是什么样,这就是一个大屏的展示。 
  
机器学习(异常检测)
 
现在对于日志分析,仅仅是对已有的数据进行固化分析或是已有的一些策略进行分析已经无法满足运维日新月异的要求,其实很多 IT 的问题,最开始的时候都是未知的。甚至在一开始对业务进行监控的时候,我可能都很难去预想到监控策略应该怎么样去设计,或者很难在一开始就提出来监控指标的阈值应该是多少。   
历史数据分析
 
 所以如果说日志分析平台能够引入现在一些新的大数据的技术,比如说深度学习或者机器学习,就能够很方便的去对历史数据进行分析,告诉我中间的异常值。举一个例子,下面的这一个截图其实是一个企业的数据流量的变化情况,然后我们会发现,代表实际数据的蓝色线其实并不是平缓的,而是呈现一个周期变化的规律。传统的我们对于流量的监控就是画两条平行线,把所有的流量夹在里面,这样的话一旦出现流量的实时值超过我的阈值的时候就会报警。然后会推送相对应的邮件或者短信的方式去告知我的运维人员。但是我们会发现,类似中间小箭头的地方就会出现漏报,就是说,看起来它其实并没有突破整个所有历史周期里面的峰值和最低值,但是我们看到它其实是不符合历史数据的变化规律的。 
 那么这个时候如果我们能够基于不同时段,灵活动态的去调整阈值,这样的话就能够很方便的发现这些虽然没有突破历史阈值但是并不符合周期性变化规律的一个数据。这样其实是能够很方便的去找到原来可能遗漏的一些数据异常点。而且这些漏报的异常点很可能会成为未来很大的风险,那么我们如果能够在这个时候及时地发现这些异常点,及时地去介入,把这样的风险,甚至是未来的一些故障防患于未然。这是一个历史数据分析的比较经典的一个场景。 
  
预测未来

 我们既然能够基于历史数据做全面的学习和分析,那么我们也希望能够去配合实时数据的增量学习,去准确预测未来的趋势,去支持更多的一些智能的特性。这个在什么场景会用到呢? 
 比如说我们在未来的几天之内想做一个业务的变更或者升级,但是我不知道哪个时间点最合适影响最小,那往常可能我们都会选择深夜例如半夜十二点来做系统交割或者新系统上线,这个对于大家来讲熬夜的压力很大。但如果我们能够通过机器学习预测未来的整个流量变化情况,我们就能够很方便的去找到一个流量低,又不需要给大家带来太多身体负担的时间点来做我们的系统变更。 
  
极简使用
 
 机器学习固然好,但大家很多时候会认为机器学习是一个特别高大上的东西,觉得算法模型是个特别复杂的东西。那么会想我有没有能力玩,能不能玩得转,能不能很方便地去使用这样一些机器学习的功能和特性。那能否自动化的、灵活化的、智能化的选择算法,自动生成相关的模型,让我们的运维人员能够低门槛甚至零门槛来使用这个机器学习的功能就变得很重要。机器学习也是现在大家在选择日志管理平台的时候可能需要去考虑的一个方向。 
  
开放性(API)

    
 最后是开放性 api,其实很多时候运维人员在日常使用日志管理平台的过程当中不只是简单的登录到平台上面通过你的可视化界面去使用你的功能。日志分析平台是需要和业务系统,分析系统或者用户已有的监控平台进行对接的。甚至很多时候对日志分析平台的使用,并不是直接点进你的界面,而是要通过接口的方式来去使用你的能力。所以整个日志分析平台的开放性会是大家在日常使用过程中必须要考虑的一个问题。考虑到我们会去对接非常多的,不同的应用开发商开发的不同的业务系统,甚至说不同的监控软件,所以开放性的 api 的丰富程度其实是一个非常重要的指标。那现在基本上主流的语言包括像 Java,php,python,C,C++,JavaScript,Go 等等这样的一些语言,最好都需要支持到。所以开放性也是大家在去对日志分析平台进行选择时必须考虑的一个问题。 
七牛云日志分析平台 Pandora

 那么有没有这样一个平台能够解决之前提到的所有问题呢?有,就是七牛的日志分析平台 Pandora。它能够实现对于日志的全生命周期的智能管理,比如之前提到的数据的收集、清洗、存储、搜索、监控告警、分析、报表、开放等等相关方面,我们都有相关的技术和产品能够去满足用户的需求。Pandora 能够实现对于日志全生命周期的智能管理,适用于像运维分析,安全审计,业务数据分析等等各种场景,针对像互联网,智能硬件,智能制造等行业,都能够提供良好的支撑和价值。 
  
 这张图是现在 Pandora 能力的全景图,对应之前提到的八个方面,能够发现其实 Pandora 已经覆盖了用户对于日志分析平台的所有要求。 logkit 是我们的数据采集平台,能够支持数据的采集、解析、转换、发送,然后 pipeline 就是基于大数据的技术,能够帮助用户进行实时和离线分析的一个大数据平台。insight 就是数据分析平台,支持对日志统一的存储,搜索,报表,监控告警,api,分析与预测,包括机器学习等等相关的功能。 
 总结一下 Pandora 的优势就是六点:数据规模大,处理速度快,开放接口巧,生态支持多,用户体验爽,公有云经验足。Pandora 不仅支持公有云的服务,我们也可以做私有化的部署。这个可以根据用户实际的情况来灵活选择。 
   数据规模大 Pandora 现在支持在公有云上完全横向扩展的存储和计算设计。现在累计在云上的存储数据超过了 40 个 pb,累计的计算数据超过 500 个 pb,传统的 ELK 的方式是无法满足这么大体量的数据的要求。 
   处理速度快 Pandora 支持实时计算能够做到毫秒到秒级的响应。所有的日志能够做到入库打点毫秒级的响应。例如说系统端或者数据源端能够实时产生的日志,我们就能够实时把这些日志采集到我们的平台上来,而且保证数据不丢失不冗余。 
   开放接口巧 我们所有的操作都有对应的 api 的支持,能够很容易的去跟第三方的系统进行结合,这是我们的第三个优势叫做开放接口巧。 
   生态支持多 我们支持现在业界主流的绝大多数的关系型数据库,非关系型数据库,消息队列及一些大数据相关组件。具体的列表大家可以在我们的官网上看到。 
   用户体验爽 比如刚刚我们提到的字段自动统计、划词分析、联合搜索、机器学习等等细节功能。我们都为用户预先考虑到了,这些所有的易用性细节我们超过 200 项,我们所有的开发的目标和要求就是降低用户的心智负担,不要把日志分析看成是特别复杂的一个事情,让大家能够低门槛甚至零门槛的来使用我们的日志分析产品。简单的把你的日志导入平台,然后方便的得到日志分析的结果,能够给用户带来业务方面的价值和提升。这个是 Pandora 希望能够去实现的事情。 
   公有云经验足 最后一个优势,我们通过一些数据来证明我们的能力。第一个是现在每天向公有云上流入的数据超过 250 个 tb,超过 3650 亿条日志。现在我们服务的客户超过 200 家,每天参与的日志的计算量能够达到 3.2 个 pb。我们每天也能够对外提供超过一万次的有效报警,这是一个非常健壮的平台。所有的功能我们在公有云上完全向用户开放,而且用户也可以选择将我们的平台以私有化的方式部署在你本地的机房里面。 

案例分享

 最后还有一些时间我给大家分享一些案例。然后再来回答刚刚大家提到的一些问题。 
  
七牛云
第一个案例就是七牛云,七牛云所有产品线产生的日志都会导入我们的日志分析平台里面来,统一的汇聚、清洗、存储、搜索等等,然后支撑我们内部的不同部门去使用这些日志。比如说商业运营部会去针对用户日常的使用消费行为,去做用户的画像;产品研发部用来排查线上错误;技术支持部用来客服;质量保障部用来做质量分析与复盘;运维部用来做运维监控告警与成本分析。 
  
银行
第二个是一个大型银行,该银行拥有多个大型数据中心,且每个数据中心既有物理机提供服务,也有虚拟机提供服务,他们碰到的痛点是针对物理机和虚拟机、不同的网络设备、不同的操作系统及不断增加的海量业务数据,无法做到统一的收集、存储与分析。 该银行最后采用 Pandora 平台,利用 logkit 统一收集各种设备的 metric,最后在平台上做监控告警;同时也采用 logkit 让业务方来收集业务日志,供业务方相关人员对这些日志进行检索与分析,从而更快的定位问题,并且持续挖掘数据价值。  
  
制造企业
第三个是华东的一个大型制造企业,也是我们刚才提到的物联网的一个场景代表。客户会把很多生产线上部署的传感器的数据导入 Pandora。客户整个车间和厂房非常大,所有的传感器每秒钟能产生百万级别的数据。这样百万级别的数据需要实时地传送到我的平台上面来,然后对数据进行实时处理,在做实时监控的同时,也会生成一些多维度的报表,方便用户对整个生产线的实时工作情况,包括生产线一段时间内的整体表现,进行一个精确分析。 
  
互联网公司
第四个案例是一个大型互联网公司,主要业务是对外提供视频点播类的服务。他们购买了七牛云的 cdn 服务,因此产生大量的 cdn 的日志,包括用户来源于哪个地方,他访问了哪些资源,他的整个访问情况,和他平均打开视频的时长等等。这样的一些数据其实都在我们的 cdn 日志里面并且蕴含了很大的价值。该用户基于我们的 cdn 日志,再结合我们的日志分析平台,能够分析出非常多的应用质量以及运营的指标,来对后续的业务进行支撑和决策分析。 
 大家如果有兴趣的话可以去我们的官方网站上面看我们的产品介绍。下方有两个网站,一个是七牛云的官网,上面可以去免费申请注册账户来试用我们的平台。第二个是我们的文档站,大家在里面可以看到所有产品的具体介绍,而且他们也会提供典型的产品的场景描述和分析,能够帮助大家更好地去理解对我们平台的使用。 
 · 免费注册: http://www.qiniu.com · 快速了解: https://developer.qiniu.com/insight/ 
  
 最后 one more thing,我们预计会在 9 月份推出这三个功能,第一个是多维分析,我们叫它 datacube。它能够对用户很多日常的关键运营指标做预计算,当你去查询一些你关心的关键指标时,能够更快地去输出相关的结果。第二个是针对日常的运维监控,全链路的监控分析解决方案。第三个是我们针对具体故障做的一个根因分析。这个我们也会都在 9 月份推出来。请大家关注七牛云的官网,我们一有相关的消息就会及时通知大家。 
 感谢大家来聆听我的一个简单的分享。 
 
 Q&A 
 Q 有私有化部署案例吗? 答:私有化部署案例是有的,我们遇到的很多传统行业的客户都是采用私有化部署方式来使用 Pandora 平台,包括我们一些银行案例,也是私有化部署的。事实上从 Pandora 诞生的第一天起,私有部署场景就是我们最关注的点之一。 
 Q 对于容器模块的负载,能够定位到某一个具体的进程吗? 答:可以的,我们现在支持针对 k8s 的容器日志采集,可以针对容器模块进行负载监控,能够定位到具体的进程。 
 Q 可以自定义日志分析规则吗? 答:可以的,我们支持非常灵活的日志分析的规则,你可以采用划词的方式来做日志的解析,并且将解析结果保存为规则,后续可以方便的为日志配置这些规则。 
 Q 如果使用云空间,日志量又很大,如何解决流量问题? 答:一些用户在使用日志分析平台的时候,会遇到类似担心,如果日常业务和日志管理分析服务不在一个云上,会不会产生很多中间的流量费用。针对性这样的情况我们有两种解决方案: 一、七牛 Pandora 所有的日志采集传输都是有压缩加密的,压缩率在 10 倍以上,极大降低流量负担; 二、如果有空闲的计算资源,可以是本地虚拟机或者云主机,我们也支持将日志分析服务以私有化部署的方式部署在本地或是第三方云平台上,这样在一个统一平台里面,日志传输流量可以变成内部流量,一般来说内部流量的成本是很低的。 
 Q Pandora 和 ELK 有什么区别? 答: 我们全托管,开箱即用,按需付费,成本低
 Pandora 的数据收集产品 logkit 无论是从体验还是性能看,都远好于 logstash/filebeat
 我们支持灵活的企业级数据总线
 我们在 「采集」的稳定性及功能丰富性上的表现远好于 ES
 在大规模数据量(十亿条日志以上、TB 级别以上)的情况下系统稳定性及性能的表现好于 ES
 ES 不支持数据脱敏
 ES 不支持多租户
 ES 不支持用户权限,安全审计等关键功能
 ES 无内置机器学习支持
 ES 无各种丰富解决方案的支持 
 总结来说,用 ELK 的场景都可以使用 Pandora 来完成,Pandora 提供了优秀的产品体验。 而从功能集的角度考虑,Pandora 是 ELK 的超集,如可以轻松完成流式计算与多维分析等场景。 
   牛人说 
 「牛人说」专栏致力于技术人思想的发现,其中包括技术实践、技术干货、技术见解、成长心得,还有一切值得被发现的内容。我们希望集合最优秀的技术人,挖掘独到、犀利、具有时代感的声音。
大数据
2018-09-05 14:33:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Urllib库介绍
1.什么是Urllib
①Python内置的HTTP请求库
②urllib.request 请求模块
③urllib.error 异常处理模块
④urllib.parse url解析模块
⑤urllib.robotparser robots.txt解析模块
2.相比Python2变化
Python2 import urllib2 response = urllib2.urlopen('http://www.baidu.com')
Python3 import urllib response = urllib.request.urlopen('http://www.baidu.com')
urllib
1.urlopen urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None) import urllib.request response = urllib.request.urlopen('http://www.baidu.com') print(response.read().decode('utf-8')) import urllib.parse import urllib.request data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8') response = urllib.request.urlopen('http://httpbin.org/post', data=data) print(response.read()) import urllib.request response = urllib.request.urlopen('http://httpbin.org/get', timeout=1) print(response.read()) import socket import urllib.request import urllib.error try: response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1) except urllib.error.URLError as e: if isinstance(e.reason, socket.timeout): print('TIME OUT')
响应
1.响应类型 import urllib.request response = urllib.request.urlopen('https://www.python.org') print(type(response))
2.状态码、响应头 import urllib.request response = urllib.request.urlopen('https://www.python.org') print(response.status) print(response.getheaders()) print(response.getheader('Server')) import urllib.request response = urllib.request.urlopen('https://www.python.org') print(response.read().decode('utf-8'))
Request import urllib.request request = urllib.request.Request('https://python.org') response = urllib.request.urlopen(request) print(response.read().decode('utf-8')) from urllib import request, parse url = 'http://httpbin.org/post' headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Host': 'httpbin.org' } dict = { 'name': 'Germey' } data = bytes(parse.urlencode(dict), encoding='utf8') req = request.Request(url=url, data=data, headers=headers, method='POST') response = request.urlopen(req) print(response.read().decode('utf-8')) from urllib import request, parse url = 'http://httpbin.org/post' dict = { 'name': 'Germey' } data = bytes(parse.urlencode(dict), encoding='utf8') req = request.Request(url=url, data=data, method='POST') req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)') response = request.urlopen(req) print(response.read().decode('utf-8'))
Handler
1.代理 import urllib.request proxy_handler = urllib.request.ProxyHandler({ 'http': 'http://127.0.0.1:9743', 'https': 'https://127.0.0.1:9743' }) opener = urllib.request.build_opener(proxy_handler) response = opener.open('http://httpbin.org/get') print(response.read())
2.Cookie import http.cookiejar, urllib.request cookie = http.cookiejar.CookieJar() handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') for item in cookie: print(item.name+"="+item.value) import http.cookiejar, urllib.request filename = "cookie.txt" cookie = http.cookiejar.MozillaCookieJar(filename) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') cookie.save(ignore_discard=True, ignore_expires=True) import http.cookiejar, urllib.request filename = 'cookie.txt' cookie = http.cookiejar.LWPCookieJar(filename) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') cookie.save(ignore_discard=True, ignore_expires=True) import http.cookiejar, urllib.request cookie = http.cookiejar.LWPCookieJar() cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') print(response.read().decode('utf-8'))
异常处理 from urllib import request, error try: response = request.urlopen('http://jzfblog.com/index.htm') except error.URLError as e: print(e.reason) from urllib import request, error try: response = request.urlopen('http://jzfblog.com/index.htm') except error.HTTPError as e: print(e.reason, e.code, e.headers, sep='\n') except error.URLError as e: print(e.reason) else: print('Request Successfully') import socket import urllib.request import urllib.error try: response = urllib.request.urlopen('https://www.baidu.com', timeout=0.01) except urllib.error.URLError as e: print(type(e.reason)) if isinstance(e.reason, socket.timeout): print('TIME OUT')
URL解析
1.urlparse urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True) from urllib.parse import urlparse result = urlparse('http://www.baidu.com/index.html;user?id=5#comment') print(type(result), result) from urllib.parse import urlparse result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https') print(result) from urllib.parse import urlparse result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', scheme='https') print(result) from urllib.parse import urlparse result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', allow_fragments=False) print(result) from urllib.parse import urlparse result = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False) print(result)
urlunparse from urllib.parse import urlunparse data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment'] print(urlunparse(data))
2.urljoin from urllib.parse import urljoin print(urljoin('http://www.baidu.com', 'FAQ.html')) print(urljoin('http://www.baidu.com', 'https://cuiqingcai.com/FAQ.html')) print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html')) print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html?question=2')) print(urljoin('http://www.baidu.com?wd=abc', 'https://cuiqingcai.com/index.php')) print(urljoin('http://www.baidu.com', '?category=2#comment')) print(urljoin('www.baidu.com', '?category=2#comment')) print(urljoin('www.baidu.com#comment', '?category=2'))
3.urlencode from urllib.parse import urlencode params = { 'name': 'germey', 'age': 22 } base_url = 'http://www.baidu.com?' url = base_url + urlencode(params) print(url)
大数据
2018-09-05 13:39:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
在本月的重庆云栖大会飞天技术汇专场中,阿里云高级算法专家黄海宇分享了题为《超大规模直播码率控制》的议题,从生产的链路角度来说世界杯怎么让观众看到更加清晰的视频。
这一次的世界杯,与以往世界杯最大的区别在于,有很多互联网用户观看直播,而不是在电视上。在互联网观看直播,互联网的网络条件不一样,观众会看不同码率的视频。所以主要分享下阿里云在直播中怎么做码率控制。
分享分三个部分,首先讨论一下为什么要关注码率控制、其次是宏观上怎么做码率控制,最后是介绍下微观上怎么做码率控制。
为什么我们要关注码率控制
我们先看一下个直播的一个简单的过程。
世界杯通常会拿到一个非常高清的直播源,它的码率非常大,不太适合在互联网上直接传输。所以整条链路中会有一个视频内容的再生产的过程,这个再生产的过程最重要的就是视频的转码,将这个转成不同分辨率的几个档位。比如说我们看视频有流畅的、标清、高清、超清的视频,这些都是为了让不同网络的用户可以流畅的观看视频。在进行转码以后,视频流会经过CDN放大,很多用户会进行观看。
其中,码率控制是发生在转码这个环节,就是把高清视频进行解码再进行重新编码,视频的转码是一个有损的压缩的过程,把原来的视频进行处理,将里面的细节进行忽略,这样能够以一个更低的带宽去满足用户播放流畅的需求。
大数据
2018-09-05 11:40:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 梯度下降的场景假设 梯度 梯度下降算法的数学解释 梯度下降算法的实例 梯度下降算法的实现 Further reading
本文将从一个下山的场景开始,先提出梯度下降算法的基本思想,进而从数学上解释梯度下降算法的原理,最后实现一个简单的梯度下降算法的实例!
梯度下降的场景假设 梯度下降法的基本思想可以类比为一个下山的过程。假设这样一个场景:一个人被困在山上,需要从山上下来(i.e. 找到山的最低点,也就是山谷)。但此时山上的浓雾很大,导致可视度很低。因此,下山的路径就无法确定,他必须利用自己周围的信息去找到下山的路径。这个时候,他就可以利用梯度下降算法来帮助自己下山。具体来说就是,以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着山的高度下降的地方走,同理,如果我们的目标是上山,也就是爬到山顶,那么此时应该是朝着最陡峭的方向往上走。然后每走一段距离,都反复采用同一个方法,最后就能成功的抵达山谷。
image.png
我们同时可以假设这座山最陡峭的地方是无法通过肉眼立马观察出来的,而是需要一个复杂的工具来测量,同时,这个人此时正好拥有测量出最陡峭方向的能力。所以,此人每走一段距离,都需要一段时间来测量所在位置最陡峭的方向,这是比较耗时的。那么为了在太阳下山之前到达山底,就要尽可能的减少测量方向的次数。这是一个两难的选择,如果测量的频繁,可以保证下山的方向是绝对正确的,但又非常耗时,如果测量的过少,又有偏离轨道的风险。所以需要找到一个合适的测量方向的频率,来确保下山的方向不错误,同时又不至于耗时太多!
梯度下降
梯度下降的基本过程就和下山的场景很类似。
首先,我们有一个可 微分 的函数。这个函数就代表着一座山。我们的目标就是找到这个函数的最小值,也就是山底。根据之前的场景假设,最快的下山的方式就是找到当前位置最陡峭的方向,然后沿着此方向向下走,对应到函数中,就是找到给定点的 梯度 ,然后朝着梯度相反的方向,就能让函数值下降的最快!因为梯度的方向就是函数之变化最快的方向(在后面会详细解释)
所以,我们重复利用这个方法,反复求取梯度,最后就能到达局部的最小值,这就类似于我们下山的过程。而求取梯度就确定了最陡峭的方向,也就是场景中测量方向的手段。那么为什么梯度的方向就是最陡峭的方向呢?接下来,我们从微分开始讲起
微分
看待微分的意义,可以有不同的角度,最常用的两种是: 函数图像中,某点的切线的斜率 函数的变化率
几个微分的例子:
image.png
上面的例子都是单变量的微分,当一个函数有多个变量的时候,就有了多变量的微分,即分别对每个变量进行求微分

image.png
梯度
梯度实际上就是多变量微分的一般化。
下面这个例子:

image.png
我们可以看到,梯度就是分别对每个变量进行微分,然后用逗号分割开,梯度是用<>包括起来,说明梯度其实一个向量。
梯度是微积分中一个很重要的概念,之前提到过梯度的意义 在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率 在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向
这也就说明了为什么我们需要千方百计的求取梯度!我们需要到达山底,就需要在每一步观测到此时最陡峭的地方,梯度就恰巧告诉了我们这个方向。梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点下降最快的方向,这正是我们所需要的。所以我们只要沿着梯度的方向一直走,就能走到局部的最低点!

image.png
梯度下降算法的数学解释
上面我们花了大量的篇幅介绍梯度下降算法的基本思想和场景假设,以及梯度的概念和思想。下面我们就开始从数学上解释梯度下降算法的计算过程和思想!

image.png

此公式的意义是:J是关于Θ的一个函数,我们当前所处的位置为Θ0点,要从这个点走到J的最小值点,也就是山底。首先我们先确定前进的方向,也就是梯度的反向,然后走一段距离的步长,也就是α,走完这个段步长,就到达了Θ1这个点!

image.png
下面就这个公式的几个常见的疑问: α是什么含义?
α在梯度下降算法中被称作为 学习率 或者 步长 ,意味着我们可以通过α来控制每一步走的距离,以保证不要步子跨的太大扯着蛋,哈哈,其实就是不要走太快,错过了最低点。同时也要保证不要走的太慢,导致太阳下山了,还没有走到山下。所以α的选择在梯度下降法中往往是很重要的!α不能太大也不能太小,太小的话,可能导致迟迟走不到最低点,太大的话,会导致错过最低点!
image.png 为什么要梯度要乘以一个负号?
梯度前加一个负号,就意味着朝着梯度相反的方向前进!我们在前文提到,梯度的方向实际就是函数在此点上升最快的方向!而我们需要朝着下降最快的方向走,自然就是负的梯度的方向,所以此处需要加上负号
梯度下降算法的实例
我们已经基本了解了梯度下降算法的计算过程,那么我们就来看几个梯度下降算法的小实例,首先从单变量的函数开始
单变量函数的梯度下降
我们假设有一个单变量的函数

image.png

函数的微分

image.png
初始化,起点为
image.png

学习率为

image.png
根据梯度下降的计算公式
image.png
我们开始进行梯度下降的迭代计算过程:
image.png
如图,经过四次的运算,也就是走了四步,基本就抵达了函数的最低点,也就是山底
image.png
多变量函数的梯度下降
我们假设有一个目标函数

image.png

现在要通过梯度下降法计算这个函数的最小值。我们通过观察就能发现最小值其实就是 (0,0)点。但是接下来,我们会从梯度下降算法开始一步步计算到这个最小值!
我们假设初始的起点为:

image.png
初始的学习率为:
image.png

函数的梯度为:

image.png
进行多次迭代:
image.png
我们发现,已经基本靠近函数的最小值点
image.png
梯度下降算法的实现
下面我们将用python实现一个简单的梯度下降算法。场景是一个简单的 线性回归 的例子:假设现在我们有一系列的点,如下图所示
image.png

我们将用梯度下降法来拟合出这条直线!
首先,我们需要定义一个代价函数,在此我们选用 均方误差代价函数
image.png

此公示中 m是数据集中点的个数 ½是一个常量,这样是为了在求梯度的时候,二次方乘下来就和这里的½抵消了,自然就没有多余的常数系数,方便后续的计算,同时对结果不会有影响 y 是数据集中每个点的真实y坐标的值 h 是我们的预测函数,根据每一个输入x,根据Θ 计算得到预测的y值,即
image.png
我们可以根据代价函数看到,代价函数中的变量有两个,所以是一个多变量的梯度下降问题,求解出代价函数的梯度,也就是分别对两个变量进行微分

image.png
明确了代价函数和梯度,以及预测的函数形式。我们就可以开始编写代码了。但在这之前,需要说明一点,就是为了方便代码的编写,我们会将所有的公式都转换为矩阵的形式,python中计算矩阵是非常方便的,同时代码也会变得非常的简洁。
为了转换为矩阵的计算,我们观察到预测函数的形式

image.png

我们有两个变量,为了对这个公式进行矩阵化,我们可以给每一个点x增加一维,这一维的值固定为1,这一维将会乘到Θ0上。这样就方便我们统一矩阵化的计算

image.png
然后我们将代价函数和梯度转化为矩阵向量相乘的形式

image.png
coding time
首先,我们需要定义数据集和学习率 import numpy as np # Size of the points dataset. m = 20 # Points x-coordinate and dummy value (x0, x1). X0 = np.ones((m, 1)) X1 = np.arange(1, m+1).reshape(m, 1) X = np.hstack((X0, X1)) # Points y-coordinate y = np.array([ 3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12, 11, 13, 13, 16, 17, 18, 17, 19, 21 ]).reshape(m, 1) # The Learning Rate alpha. alpha = 0.01
接下来我们以矩阵向量的形式定义代价函数和代价函数的梯度 def error_function(theta, X, y): '''Error function J definition.''' diff = np.dot(X, theta) - y return (1./2*m) * np.dot(np.transpose(diff), diff) def gradient_function(theta, X, y): '''Gradient of the function J definition.''' diff = np.dot(X, theta) - y return (1./m) * np.dot(np.transpose(X), diff)
最后就是算法的核心部分,梯度下降迭代计算 def gradient_descent(X, y, alpha): '''Perform gradient descent.''' theta = np.array([1, 1]).reshape(2, 1) gradient = gradient_function(theta, X, y) while not np.all(np.absolute(gradient) <= 1e-5): theta = theta - alpha * gradient gradient = gradient_function(theta, X, y) return theta
当梯度小于1e-5时,说明已经进入了比较平滑的状态,类似于山谷的状态,这时候再继续迭代效果也不大了,所以这个时候可以退出循环!
完整的代码如下 import numpy as np # Size of the points dataset. m = 20 # Points x-coordinate and dummy value (x0, x1). X0 = np.ones((m, 1)) X1 = np.arange(1, m+1).reshape(m, 1) X = np.hstack((X0, X1)) # Points y-coordinate y = np.array([ 3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12, 11, 13, 13, 16, 17, 18, 17, 19, 21 ]).reshape(m, 1) # The Learning Rate alpha. alpha = 0.01 def error_function(theta, X, y): '''Error function J definition.''' diff = np.dot(X, theta) - y return (1./2*m) * np.dot(np.transpose(diff), diff) def gradient_function(theta, X, y): '''Gradient of the function J definition.''' diff = np.dot(X, theta) - y return (1./m) * np.dot(np.transpose(X), diff) def gradient_descent(X, y, alpha): '''Perform gradient descent.''' theta = np.array([1, 1]).reshape(2, 1) gradient = gradient_function(theta, X, y) while not np.all(np.absolute(gradient) <= 1e-5): theta = theta - alpha * gradient gradient = gradient_function(theta, X, y) return theta optimal = gradient_descent(X, y, alpha) print('optimal:', optimal) print('error function:', error_function(optimal, X, y)[0,0])
运行代码,计算得到的结果如下

image.png
所拟合出的直线如下

image.png
小结
至此,我们就基本介绍完了梯度下降法的基本思想和算法流程,并且用python实现了一个简单的梯度下降算法拟合直线的案例!
最后,我们回到文章开头所提出的场景假设:
这个下山的人实际上就代表了 反向传播算法 ,下山的路径其实就代表着算法中一直在寻找的参数Θ,山上当前点的最陡峭的方向实际上就是代价函数在这一点的梯度方向,场景中观测最陡峭方向所用的工具就是 微分 。在下一次观测之前的时间就是有我们算法中的学习率α所定义的。
可以看到场景假设和梯度下降算法很好的完成了对应!

作者:六尺帐篷
链接:https://www.jianshu.com/p/c7e642877b0e
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
大数据
2018-09-05 10:12:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
正则表达式
1.正则表达式概述
①正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE)
②正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串
③在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
2.表示字符(正则表达式的单字符匹配)
字符 功能
[ ] 匹配[ ]中列举的字符,[^]取方括号内没有的字符
\d 匹配数字,即0-9[0-9]
\D 匹配非数字,即不是数字[^0-9]
\s 匹配空白,即 空格,tab键
\S 匹配非空白
\w 匹配单词字符,即a-z、A-Z、0-9、_[a-zA-Z0-9_]
\W 匹配非单词字符[^a-zA-Z0-9_]
3.表示数量
字符 功能
* 匹配前一个字符出现0次或者无限次,即可有可无
+ 匹配前一个字符出现1次或者无限次,即至少有1次
? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m} 匹配前一个字符出现m次
{m,} 匹配前一个字符至少出现m次
{m,n} 匹配前一个字符出现从m到n次
4.原始字符串
①Python中字符串前面加上 r 表示原生字符串
②正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠
5.表示边界
字符 功能
^ 匹配字符串开头
$ 匹配字符串结尾
\b 匹配一个单词的边界
\B 匹配非单词边界
6.匹配分组
字符 功能
| 匹配左右任意一个表达式
(ab) 将括号中字符作为一个分组
=\num 引用分组num匹配到的字符串
(?P) 分组起别名
(?P=name) 引用别名为name分组匹配到的字符串
re模块高级用法
1.实际上爬虫一共有四个主要步骤:
①明确目标 (要知道你准备在哪个范围或者网站去搜索)
②爬 (将所有的网站的内容全部爬下来)
③取 (去掉对我们没用处的数据)
④处理数据 (按照我们想要的方式存储和使用)
当使用了爬虫程序把网页爬取下来的时候,有些数据可能是根本就不需要的,如一些html文本,可能还带有css样式。所以要想过滤出想要的数据就要用到Python的re模块,也就是爬虫过程的第三步,取。
下面就仔细地将re模块的使用做一个总结:
2.re 模块的一般使用步骤如下:
①使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
②通过 Pattern 对象提供的一系列方法对文本进行匹配查找,获得匹配结果,一个 Match 对象。
③最后使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作 import re # 将正则表达式编译成 Pattern 对象 pattern = re.compile(r'\d+')
在上面,我们已将一个正则表达式编译成 Pattern 对象,接下来,我们就可以利用 pattern 的一系列方法对文本进行匹配查找了。
3.Pattern 对象的一些常用方法主要有:
①match 方法:从起始位置开始查找,一次匹配
②search 方法:从任何位置开始查找,一次匹配
③findall 方法:全部匹配,返回列表
④finditer 方法:全部匹配,返回迭代器
⑤split 方法:分割字符串,返回列表
⑥sub 方法:替换
match 方法
1.match 方法用于查找字符串的头部 (也可以指定起始位置),它是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果。它的一般使用形式如下: match(string[, pos[, endpos]])
其中,string是待匹配的字符串,pos和endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是0 和 len (字符串长度)。因此,当你不指定 pos 和 endpos 时,match 方法默认匹配字符串的头部
2.当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回None >>> import re >>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字 >>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配 >>> print m None >>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配 >>> print m None >>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配 >>> print m # 返回一个 Match 对象 <_sre.SRE_Match object at 0x10a42aac0> >>> m.group(0) # 可省略 0 '12' >>> m.start(0) # 可省略 0 3 >>> m.end(0) # 可省略 0 5 >>> m.span(0) # 可省略 0 (3, 5)
在上面,当匹配成功时返回一个 Match 对象,其中:
①group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
②start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
③end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
④span([group]) 方法返回 (start(group), end(group))。
再看看一个例子: >>> import re >>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写 >>> m = pattern.match('Hello World Wide Web') >>> print m # 匹配成功,返回一个 Match 对象 <_sre.SRE_Match object at 0x10bea83e8> >>> m.group(0) # 返回匹配成功的整个子串 'Hello World' >>> m.span(0) # 返回匹配成功的整个子串的索引 (0, 11) >>> m.group(1) # 返回第一个分组匹配成功的子串 'Hello' >>> m.span(1) # 返回第一个分组匹配成功的子串的索引 (0, 5) >>> m.group(2) # 返回第二个分组匹配成功的子串 'World' >>> m.span(2) # 返回第二个分组匹配成功的子串 (6, 11) >>> m.groups() # 等价于 (m.group(1), m.group(2), ...) ('Hello', 'World') >>> m.group(3) # 不存在第三个分组 Traceback (most recent call last): File "", line 1, in IndexError: no such group
search 方法
1.search方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果,它的一般使用形式如下: search(string[, pos[, endpos]])
其中,string 是待匹配的字符串,pos和endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是0和len (字符串长度)。
2.当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。
让我们看看例子: >>> import re >>> pattern = re.compile('\d+') >>> m = pattern.search('one12twothree34four') # 这里如果使用 match 方法则不匹配 >>> m <_sre.SRE_Match object at 0x10cc03ac0> >>> m.group() '12' >>> m = pattern.search('one12twothree34four', 10, 30) # 指定字符串区间 >>> m <_sre.SRE_Match object at 0x10cc03b28> >>> m.group() '34' >>> m.span() (13, 15)
再来看一个例子: # -*- coding: utf-8 -*- import re # 将正则表达式编译成 Pattern 对象 pattern = re.compile(r'\d+') # 使用 search() 查找匹配的子串,不存在匹配的子串时将返回 None # 这里使用 match() 无法成功匹配 m = pattern.search('hello 123456 789') if m: # 使用 Match 获得分组信息 print 'matching string:',m.group() # 起始位置和结束位置 print 'position:',m.span() 执行结果: matching string: 123456 position: (6, 12)
findall 方法
1.上面的match和search方法都是一次匹配,只要找到了一个匹配的结果就返回。然而,在大多数时候,我们需要搜索整个字符串,获得所有匹配的结果。
2.findall方法的使用形式如下: findall(string[, pos[, endpos]])
其中,string 是待匹配的字符串,pos 和 endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。
3.findall 以列表形式返回全部能匹配的子串,如果没有匹配,则返回一个空列表。
看看例子: import re pattern = re.compile(r'\d+') # 查找数字 result1 = pattern.findall('hello 123456 789') result2 = pattern.findall('one1two2three3four4', 0, 10) print result1 print result2 执行结果: ['123456', '789'] ['1', '2']
再先看一个例子: import re # re模块提供一个方法叫compile模块,提供我们输入一个匹配的规则 # 然后返回一个pattern实例,我们根据这个规则去匹配字符串 pattern = re.compile(r'\d+\.\d*') # 通过partten.findall()方法就能够全部匹配到我们得到的字符串 result = pattern.findall("123.141593, 'bigcat', 232312, 3.15") # findall 以 列表形式 返回全部能匹配的子串给result for item in result: print item 运行结果: 123.141593 3.15
finditer 方法
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每一个匹配结果 Match 对象的迭代器。
看看例子: # -*- coding: utf-8 -*- import re pattern = re.compile(r'\d+') result_iter1 = pattern.finditer('hello 123456 789') result_iter2 = pattern.finditer('one1two2three3four4', 0, 10) print type(result_iter1) print type(result_iter2) print 'result1...' for m1 in result_iter1: # m1 是 Match 对象 print 'matching string: {}, position: {}'.format(m1.group(), m1.span()) print 'result2...' for m2 in result_iter2: print 'matching string: {}, position: {}'.format(m2.group(), m2.span()) 执行结果: result1... matching string: 123456, position: (6, 12) matching string: 789, position: (13, 16) result2... matching string: 1, position: (3, 4) matching string: 2, position: (7, 8)
split 方法
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下: split(string[, maxsplit])
其中,maxsplit 用于指定最大分割次数,不指定将全部分割。
看看例子: import re p = re.compile(r'[\s\,\;]+') print p.split('a,b;; c d') 执行结果: ['a', 'b', 'c', 'd']
sub 方法
1.sub 方法用于替换。它的使用形式如下: sub(repl, string[, count])
2.其中,repl 可以是字符串也可以是一个函数:
①如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
②如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
③count 用于指定最多替换次数,不指定时全部替换。
看看例子: import re p = re.compile(r'(\w+) (\w+)') # \w = [A-Za-z0-9] s = 'hello 123, hello 456' print p.sub(r'hello world', s) # 使用 'hello world' 替换 'hello 123' 和 'hello 456' print p.sub(r'\2 \1', s) # 引用分组 def func(m): return 'hi' + ' ' + m.group(2) print p.sub(func, s) print p.sub(func, s, 1) # 最多替换一次 执行结果: hello world, hello world 123 hello, 456 hello hi 123, hi 456 hi 123, hello 456 # 将匹配到的阅读次数加1 ret = re.sub(r"\d+", '998', "python = 997") print ret # 也可以用函数的方法替换998: def add(temp): strNum = temp.group() num = int(strNum) + 1 return str(num) ret = re.sub(r"\d+", add, "python = 997")
匹配中文
1.在某些情况下,我们想匹配文本中的汉字,有一点需要注意的是,中文的 unicode 编码范围 主要在 [u4e00-u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。
2.假设现在想把字符串 title = u'你好,hello,世界' 中的中文提取出来,可以这么做: import re title = u'你好,hello,世界' pattern = re.compile(ur'[一-龥]+') result = pattern.findall(title) print result 注意到,我们在正则表达式前面加上了两个前缀 ur,其中 r 表示使用原始字符串,u 表示是 unicode 字符串。 执行结果: [u'你好', u'世界']
注意:贪婪模式与非贪婪模式
贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 ( * );
非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 ( ? );
Python里数量词默认是贪婪的。
大数据
2018-09-04 23:05:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
今天将时间几乎花在了爬虫的Handler处理器和代理设置上,据说现在的反爬虫机制会发现爬虫程序,然后封掉爬虫程序请求的IP地址。这就糟糕了,所以还是要好好学习一下IP的代理设置,学完之后就可以使用代理来访问目标网址,可以避免封掉我IP了。还真是问题不愁找不到解决的人啊,我给大家推荐一些免费短期的代理网址: 西刺免费代理IP 快代理免费代理 全网代理IP
先写一个基本的HTTPHandler处理器,这是没有使用代理的情况,是使用真实IP访问的 #!/usr/bin/env python # coding=utf-8 import urllib2 # 构建一个HTTPHandler处理器对象,支持处理HTTP的请求 #http_handler = urllib2.HTTPHandler() # 在HTTPHandler增加参数"debuglevel=1"将会自动自动打开Debug log模式 # 程序在打印的时候就会显示此时接收和发送包的信息 http_handler = urllib2.HTTPHandler(debuglevel=1) # 调用build_opener()方法构建一个自定义的opener对象,参数是构建的处理器对象 opener = urllib2.build_opener(http_handler) request = urllib2.Request("http://www.baidu.com/") # 主要是将urllib2.urlopen改成了自定义的opener对象,使用方法open response = opener.open(request) print response.read()
这段代码中,需要总结的就是真实IP访问创建的是HTTPHandler,使用的方法也是urllib2的HTTPHandler方法,这个方法可以跟一个参数,debuglevel=1,功能是网络调试,它会返回在屏幕上接收和发送包的信息。创建好一个处理器对象后,就不能使用urllib2.urlopen方法打开一个网址了,而是要自定义一个opener,用opener.open来访问目标网址。创建方法是使用urllib2包下的build_opener来创建一个opener对象,参数是之前创建好的处理器对象,也就是http_handler,然后就可以使用opener.open来请求了
如果是想使用代理IP的话,创建处理器的方法就不是urllib2.HTTPHandler了,而是通过urllib2.ProxyHandler来创建一个IP代理处理器对象,代码如下: #!/usr/bin/env python # coding=utf-8 import urllib2 import random # 启用代理开关,可判断后面是否需要使用代理 proxyswitch = True # 创建一个代理处理器对象,参数是一个字典类型,包含了代理类型和代理服务器IP+端口号 httpproxy_handler = urllib2.ProxyHandler({"http": "119.188.162.165:8081"}) # 创建一个没有代理的处理器对象,注意没有代理不代表没有参数,而要填写一个{} nullproxy_handler = urllib2.ProxyHandler({}) if proxyswitch: opener = urllib2.build_opener(httpproxy_handler) else: opener = urllib2.build_opener(nullproxy_handler) # 创建了一个全局的opener,之后都可以使用urlopen()方式去发送,也附带Handler的功能 urllib2.install_opener(opener) request = urllib2.Request("http://www.baidu.com/") response = urllib2.urlopen(request) print response.read()
与第一个不是代理访问的区别是,ProxyHTTPHandler必须加上IP和端口,参数是一个字典形式,以http作键,IP:端口为键值,如 {"http": "119.188.162.165:8081"},而且要注意的是,如果在ProxyHTTPHandler处理器方法下不想使用代理IP也要必须加上{},也就是说这个参数必须带,可以为空。另外之前没有使用创建处理器时是可以使用urllib2.urlopen方法打开网址的,但是使用了处理器就无法直接使用该方法,需要做的步骤就是在代码层面上装一个opener,这个可以用urllib.install_opener实现,参数就是创建好的opener,且无返回值
当然了,如果自己测试过的可用代理IP够多的话,也可以像随机获得User-Agent一样,可以随机选择一个IP访问,这样就更不容易被发现这是一个爬虫程序了,可以伪装的更好 import random proxy_list = [ {"http" : "124.88.67.81:80"}, {"http" : "124.88.67.81:80"}, {"http" : "124.88.67.81:80"}, {"http" : "124.88.67.81:80"}, {"http" : "124.88.67.81:80"} ] # 随机选择一个代理 proxy = random.choice(proxy_list)
当然还有一种代理叫做私密代理,免费的代理因为使用的人多,不是很稳定,很可能上一秒还在正常访问,下一秒就出现了无法访问的故障。所以又出现了一种叫做私密代理的代理,这种代理需要用户名和密码,具体代码实现如下: #!/usr/bin/env python # coding=utf-8 import urllib2 authproxy_handler = urllib2.ProxyHandler({"host": "用户名:密码@IP:端口"}) opener = urllib2.build_opener(authproxy_handler) request = urllib2.Request("http://www.baidu.com/") response = opener.open(request) print response.read()
大数据
2018-09-04 22:44:06
「深度学习福利」大神带你进阶工程师,立即查看>>>
场景
现在有如下数据格式 图书分类,图书名,数量
现在想统计全部分类中数量最多的书名以及数量
场景解析
如果不基于spark,我们来思考这个问题,数据量大内存是放不下,分类也不确定有多少类,图书名可能有重复,还需要合并计算。这种情况只能是分治,首先分类,把文件首先按照分类拆分成多个文件,每个文件中的数据都是图书名数量,然后根据图书名对数量进行合并,最后进行排序。
spark思维转化
上面的思路单独写这个程序没问题,但是如果基于spark就有点问题了,首先是分区的事情,想把数据准确落在不同的分区,且不重复,必须要先知道到底有多少分区。所以首先要统计分类种类,帮助以后分区。
分区器 //data是已经读取进来的图书分类的集合 data.distinct().collect()
有了数据就要应用分区器 class MyPartioner extends Partitioner { private Map part = new HashMap<>(); public MyPartioner(List data) { int count = 0; for (String s : data) { part.put(s, count++); } } @Override public int numPartitions() { return part.size(); } @Override public int getPartition(Object o) { Keys info = (Keys) o; return part.get(((Keys) o).type); } }
直接根据已经生成好的数据来进行分区。保证1个分类1个分区,这样就可以以后的部分就只关注排序即可。
数据合并
分区,分区器都准备好了,按照以前的思路,是不是应该把数据分散在不同的分区了。想法挺好,但是在分布式存储中,数据移动的成本很高,所以都是先对本地数据进行处理合并,减小数据量然后才进行数据的shuffle等分区操作,所以这里我们要做的其实是合并同类数据。 textFile.mapToPair(lines -> new Tuple2(name,count)) .reduceByKey((x, y) -> x + y);
这里是一个典型的单词计数的案例。
接下来就是想着分区,然后排序,如果你查查api的话,你会发现并没用按照value排序的算子。如果要排序的话,一定是key。这里发生了一个冲突点,就是你是按照type分区,次数的type就是key,接下来排序,其实就是按照type来排。 发现了我们要依赖key完成两件事,一个是分区,一个是排序。分区靠type,排序靠count。这里的解决方案就是用对象。计数之后,得到的结果会是一个的tuple。这个明显无法继续下去了,你连分区的条件都没了。 bookname和type是一一对应的,所以这里合并统计的是bookname+type的结构体。这样就满足了分区的条件了。 为了把排序的因子给加上,我们做个map操作,把type和count组织成一个对象。 class Keys implements Serializable{ String type; Integer count; public Keys(String type, Integer count) { this.type = type; this.count = count; } }
这样就给了我们很大的空间,在分区器里,取出key来进行操作,在排序的时候,写一个比较器,按照count来进行排序。 .repartitionAndSortWithinPartitions(new MyPartioner(collect), new KeyCompare());
直接使用分区并且排序的算子帮我解决这个问题。
小结
在大数据环境下,数据的shuffle操作的代价很大,所以优先考虑合并数据,然后再进行分区等等。spark的算子大部分都是对key进行生效的,例如排序等等,对value的操作大部分是合并和迭代,并没有单独的排序出来。所以要合理利用java对象来组合key值,完成功能。
大数据
2018-09-04 21:25:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
附上:
喵了个咪的博客: w-blog.cn
cloudera官网: https://www.cloudera.com/
官方文档地址: https://www.cloudera.com/documentation/enterprise/latest.html
一 , 监控
可以在管理页面看到默认的监控
点击进入莫个具体的组件
也有与之对应的监控指标
二, 自定义监控
可以在管理菜单上方的图表里面找到dashboards
在具体的页面可以添加和导入仪表盘
通过拖动就可以打造出自己的监控大屏
如果需要增加监控指标可以在操作菜单点击<从图表生成器增加>
通过语句可以简单的进行搜索
关于图表的类型也可以自己定义,指标也可以自由定义
大数据
2018-09-04 16:00:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1.概述
在CDH的默认安装包中,是不包含Kafka,Kudu和Spark2的,需要单独下载特定的Parcel包才能安装相应服务。本文档主要描述在离线环境下,在CentOS6.5操作系统上基于CDH5.12.1集群,使用Cloudera Manager通过Parcel包方式安装Kudu、Spark2和Kafka的过程。 内容概括 Kudu安装 Spark2安装 Kafka安装 服务验证 测试环境 操作系统版本:CentOS6.5 CM和CDH版本5.12.1 使用CM管理员admin用户 操作系统采用root用户操作 前置条件 CDH集群运行正常
2.Kudu安装
CDH5.12.1打包集成Kudu1.4,并且Cloudera提供官方支持。不再需要安装Kudu的csd文件,安装完Kudu,Impala即可直接操作Kudu。
以下安装步骤描述如何使用Cloudera Manager来安装和部署Kudu1.4
2.1Kudu的Parcel部署
1.从Cloudera官网下载Kudu的Parcel包,下载地址如下 http://archive.cloudera.com/kudu/parcels/5.12.1/KUDU-1.4.0-1.cdh5.12.1.p0.10-el6.parcel http://archive.cloudera.com/kudu/parcels/5.12.1/KUDU-1.4.0-1.cdh5.12.1.p0.10-el6.parcel.sha1 http://archive.cloudera.com/kudu/parcels/5.12.1/manifest.json
2.将以上3个文件下载到http服务所在服务器的/var/www/html/kudu1.4目录 [root@ip-172-31-6-148~]# cd /var/www/html/ [root@ip-172-31-6-148 html]# mkdir kudu1.4 [root@ip-172-31-6-148 html]# cd kudu1.4/ [root@ip-172-31-6-148 kudu1.4]# ll total 474140 -rw-r--r-- 1 rootroot 485506175 Aug 30 14:55 KUDU-1.4.0-1.cdh5.12.1.p0.10-el6.parcel -rw-r--r-- 1 rootroot 41 Aug 30 14:55KUDU-1.4.0-1.cdh5.12.1.p0.10-el6.parcel.sha1 -rw-r--r-- 1 rootroot 2646 Aug 30 14:55 manifest.json [root@ip-172-31-6-148 kudu1.4]#
3.验证http是否能够正常访问
2.2安装Kudu服务
1.通过CM界面配置Kudu的Parcel地址,并下载,分发,激活Kudu。

已分配激活
2.回到CM主页,添加Kudu服务
选择Kudu服务,点击“继续”
选择Master和Tablet Server,点击“继续”
配置相应的目录,注:无论是Master还是Tablet根据实际情况,数据目录(fs_data_dir)应该都可能有多个,以提高并发读写,从而提高Kudu性能。
启动Kudu服务
安装完毕
2.3配置Impala
从CDH5.10开始,安装完Kudu后,默认Impala即可直接操作Kudu进行SQL操作,但为了省去每次建表都需要在TBLPROPERTIES中添加kudu_master_addresses属性,建议在Impala的高级配置项中设置KuduMaster的地址和端口:--kudu_master_hosts=ip-172-31-6-148.fayson.com:7051
多个master可以以“,”分割如:
--kudu_master_hosts=ip-172-31-6-148.fayson.com:7051,ip-172-31-6-148.fayson.com:7051
3.Spark2安装
集群的jdk版本为jdk1.7.0_67,从Spark2.2.0版本后不再支持Java7、Python2.6和Hadoop2.6.5之前的版本,所以此处选择Spark 2.1.0版本部署。
3.1安装csd文件
1.下载csd文件,下载地址如下: http://archive.cloudera.com/spark2/csd/SPARK2_ON_YARN-2.1.0.cloudera1.jar
2.将csd文件移动至/opt/cloudera/csd目录下 [root@ip-172-31-6-148csd]# pwd /opt/cloudera/csd [root@ip-172-31-6-148 csd]#ll total 16 -rw-r--r-- 1 rootroot 16109 Mar 29 06:58 SPARK2_ON_YARN-2.1.0.cloudera1.jar [root@ip-172-31-6-148 csd]#
如果csd目录不存在,则创建 [root@ip-172-31-6-148cloudera]# mkdir csd [root@ip-172-31-6-148 cloudera]# chown cloudera-scm:cloudera-scm csd/
3.重启Cloudera Manager服务 [root@ip-172-31-6-148~]# service cloudera-scm-serverrestart Stopping cloudera-scm-server: [ OK ] Starting cloudera-scm-server: [ OK ] [root@ip-172-31-6-148 ~]#
3.2Spark2的Parcel部署
1.下载Spark2的Parcel包,下载地址如下 http://archive.cloudera.com/spark2/parcels/2.1.0/SPARK2-2.1.0.cloudera1-1.cdh5.7.0.p0.120904-el6.parcel http://archive.cloudera.com/spark2/parcels/2.1.0/SPARK2-2.1.0.cloudera1-1.cdh5.7.0.p0.120904-el6.parcel.sha1 http://archive.cloudera.com/spark2/parcels/2.1.0/manifest.json
2.将上述3个文件下载至/var/www/html/spark2.1.0目录下 [root@ip-172-31-6-148html]# cd /var/www/html/ [root@ip-172-31-6-148 html]# mkdir spark2.1.0 [root@ip-172-31-6-148 html]# cd spark2.1.0/ [root@ip-172-31-6-148 spark2.1.0]# ll total 173052 -rw-r--r-- 1 rootroot 4677 Mar 29 06:58 manifest.json -rw-r--r-- 1 rootroot 177185276 Mar 29 06:58 SPARK2-2.1.0.cloudera1-1.cdh5.7.0.p0.120904-el6.parcel -rw-r--r-- 1 rootroot 41 Mar 29 06:58SPARK2-2.1.0.cloudera1-1.cdh5.7.0.p0.120904-el6.parcel.sha1 [root@ip-172-31-6-148 spark2.1.0]#
3.验证是否部署成功
3.3安装Spark2
1.通过CM管理界面配置Spark2的Parcel地址并保存

2.点击下载、分配并激活
3.回到CM主页,添加Spark2
4.选择Spark2,点击“继续”
5.为新的Spark2选择一组依赖,点击“继续”
6.选择History Server和Gateway节点,点击“继续”
7.启动Spark2服务,服务启动完成后,点击“继续”
8.Spark2安装完成
4.Kafka安装
4.1Kafka版本选择
Kafka版本 版本特性 最低支持CM版本 支持CDH版本 是否集成到CDH 2.2.x Cloudera Manager 5.9.x CDH 5.9.x and higher 否
2.1.x Sentry authorization Cloudera Manager 5.9.x CDH 5.9.x and higher
2.0.x
1.4.x 1.3.x 1.2.x
Enhanced security
Distributed both as package and parcel Includes Kafka Monitoring
Cloudera Manager 5.5.3
Cloudera Manager 5.2.x Cloudera Manager 5.2.x Cloudera Manager 5.2.x
CDH 5.4.x and higher
CDH 5.4.x, 5.5.x, 5.6.x CDH 5.4.x, 5.5.x, 5.6.x CDH 5.4.x, 5.5.x, 5.6.x
参考官网: https://www.cloudera.com/documentation/enterprise/release-notes/topics/rn_consolidated_pcm.html#pcm_kafka
4.2Kafka的Parcel部署
1.从Cloudera官网下载Kafka的Parcel包,下载地址如下 http://archive.cloudera.com/kafka/parcels/2.1.1.18/KAFKA-2.1.1-1.2.1.1.p0.18-el6.parcel http://archive.cloudera.com/kafka/parcels/2.1.1.18/KAFKA-2.1.1-1.2.1.1.p0.18-el6.parcel.sha1 http://archive.cloudera.com/kafka/parcels/2.1.1.18/manifest.json
2.将上述3个文件下载至/var/www/html/kafka2.1.1.18目录下 [root@ip-172-31-6-148html]# cd /var/www/html/ [root@ip-172-31-6-148 html]# mkdir kafka2.1.1.18 [root@ip-172-31-6-148 html]# cd kafka2.1.1.18/ [root@ip-172-31-6-148 kafka2.1.1.18]# ll total 66536 -rw-r--r-- 1 rootroot 68116503 Mar 27 17:39 KAFKA-2.1.1-1.2.1.1.p0.18-el6.parcel -rw-r--r-- 1 rootroot 41 Mar 27 17:39KAFKA-2.1.1-1.2.1.1.p0.18-el6.parcel.sha1 -rw-r--r-- 1 rootroot 5252 Mar 27 17:40 manifest.json [root@ip-172-31-6-148 kafka2.1.1.18]#
3.验证是否部署成功
4.3安装Kafka服务
1.通过CM配置Kafka的Parcel包地址并保存

2.点击下载、分配并激活
3.回到CM主页,添加Kafka服务
4.选择Kafka服务,点击“继续”
5.为Kafka选择一组依赖关系,点击“继续”
6.选择Kafka Broker和Gateway,点击“继续”
7.根据集群环境修改Kafka配置,点击“继续”
8.Kafka安装完成
9.修改Kafka Broker的heap大小,默认为50M,可能会导致Kafka启动失败
保存配置,重新部署客户端并重启相应服务。
5.服务验证
5.1Kudu验证
建表语句如下: CREATE TABLE my_first_table( id BIGINT, name STRING, PRIMARY KEY(id) ) PARTITION BY HASH PARTITIONS 16 STORED AS KUDU;
通过Impala-shell创建Kudu表 [impala@ip-172-31-6-148root]$ impala-shell -iip-172-31-10-118.fayson.com ... [ip-172-31-10-118.fayson.com:21000] > show tables; Query: show tables +------------+ | name | +------------+ | test | | test_table | +------------+ Fetched 2 row(s) in 0.06s [ip-172-31-10-118.fayson.com:21000] > CREATE TABLEmy_first_table( > id BIGINT, > name STRING, > PRIMARY KEY(id) > ) >PARTITION BY HASH PARTITIONS 16 > STORED AS KUDU; Query: create TABLE my_first_table( id BIGINT, name STRING, PRIMARY KEY(id) ) PARTITION BY HASH PARTITIONS 16 STORED AS KUDU Fetched 0 row(s) in 2.43s [ip-172-31-10-118.fayson.com:21000] >
插入数据并查询 [ip-172-31-10-118.fayson.com:21000]> insert into my_first_table values(1,'fayson'); Query: insert into my_first_table values(1,'fayson') ... Modified 1 row(s), 0 row error(s) in 3.92s [ip-172-31-10-118.fayson.com:21000] >select * from my_first_table; ... +----+--------+ | id | name | +----+--------+ | 1 | fayson | +----+--------+ Fetched 1 row(s) in 1.02s [ip-172-31-10-118.fayson.com:21000] >
通过Kudu Master Web UI查看
5.2Spark2验证 [root@ip-172-31-6-148~]# spark2-shell Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). ForSparkR, use setLogLevel(newLevel). 17/09/11 09:46:22 WARN spark.SparkContext: Support for Java 7 is deprecated as of Spark 2.0.0 Spark context Web UI available at http://172.31.6.148:4040 Spark context available as 'sc' (master = yarn, app id =application_1505121236974_0001). Spark session available as 'spark'. Welcome to ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/__/ '_/ /___/ .__/\_,_/_//_/\_\ version 2.1.0.cloudera1 /_/ Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_67) Type in expressions tohave them evaluated. Type :help for more information. scala> var textFile=sc.textFile("/fayson/test/a.txt") textFile: org.apache.spark.rdd.RDD[String] =/fayson/test/a.txt MapPartitionsRDD[1] at textFile at :24 scala> textFile.count() res0: Long = 3 scala>
5.3Kafka验证
1.创建一个test的topic [root@ip-172-31-6-148hive]# kafka-topics --create--zookeeper ip-172-31-6-148.fayson.com:2181 --replication-factor 3 --partitions1 --topic test
2.向topic发送消息 [root@ip-172-31-6-148hive]# kafka-console-producer--broker-list ip-172-31-10-118.fayson.com:9092 --topic test
3.消费topic的消息 [root@ip-172-31-6-148hive]# kafka-console-consumer --zookeeperip-172-31-6-148.fayson.com:2181 --topic test --from-beginning
4.查看topic描述信息 [root@ip-172-31-6-148hive]# kafka-topics --describe--zookeeper ip-172-31-6-148.fayson.com:2181 --topic test


大数据
2018-09-04 14:54:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
2018年国内大数据公司50强榜单排名已经公布了出来,大快以黑马之姿闯入50强,并摘得多项桂冠。Hanlp自然语言处理技术也荣膺了“2018中国数据星技术”奖。对这份榜单感兴趣的可以找一下看看。本篇承接上一篇《DKM平台监控参数说明》,继续就大快的大数据一体化处理架构中的平台监控参数进行介绍和说明。 DKhadoop大数据处理平台架构的安装相关文章已经分享过,详细的内容可以找一下看看。在上一篇中已经就集群平均负载、集群磁盘使用情况、HDFS监控界面、Hbase监控界面等监控参数进行说明。今天就把剩下的一些监控参数一起介绍完,关于大快大数据处理平台监控参数的介绍就完整了。 1、Yarn监控界面 (1) 执行失败的应用程序 监控 yarn资源管理中总执行失败的应用程序数量 纵轴表示应用程序数量,单位个 横轴表示时间,单位分钟 (2)已提交的应用程序 监控 yarn资源管理中已提交的应用程序数量 纵轴表示应用程序数量,单位个 横轴表示时间,单位分钟
(3)正在运行的应用程序
监控 yarn资源管理中正在运行的应用程序数量 纵轴表示应用程序数量,单位个 横轴表示时间,单位分钟 (4) 等待执行的应用程序
监控 yarn资源管理中等待执行的应用程序数量 纵轴表示应用程序数量,单位个 横轴表示时间,单位分钟
(5)已完成的应用程序
监控 yarn资源管理中已完成的应用程序数量 纵轴表示应用程序数量,单位个 横轴表示时间,单位分钟 (6)被kill的应用程序
监控 yarn资源管理中被杀死的应用程序数量 纵轴表示应用程序数量,单位个 横轴表示时间,单位分钟 2、Spark监控界面 注意:(spark 运行任务后才有监控数据) (1) 最大可使用内存
监控 Spark 集群中最大可使用的内存 纵轴表示内存容量,单位MB 横轴表示时间,单位分钟 (2)已使用的内存 监控 Spark 集群中已经使用的内存 纵轴表示内存容量,单位MB 横轴表示时间,单位分钟 (3)剩余内存
监控 Spark 集群中剩余的内存 纵轴表示内存容量,单位(MB) 横轴表示时间,单位分钟 (4)Spark中任务数量 监控 Spark 集群中任务数量 纵轴表示内存容量,单位MB 横轴表示时间,单位分钟 (5)Spark中正在运行的任务数量 监控 Spark中正在运行的任务数量 纵轴表示内存容量,单位MB 横轴表示时间,单位分钟 (6)正在运行的stage数量
监控 Spark集群中正在运行的stage数量 纵轴表示stage数量,单位个 横轴表示时间,单位分钟
(7)失败的stage数量 监控 Spark集群中运行失败的stage数量 纵轴表示stage数量,单位个 横轴表示时间,单位分钟 (8)准备就绪的stage数量 监控 Spark集群中准备就绪的stage数量 纵轴表示stage数量,单位个 横轴表示时间,单位分钟 备注: (横轴的时间表示采集时间,一般是1分钟一次)
大数据
2018-08-15 14:42:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
不知道大家发现没,我们在实现hive表 交集的时候,使用sql 语句中的 union 和 intersect 会失败。这是因为该版本的hive并不支持 select id from t1 union select id from t2 select id from t1 intersect select id from t2
所以我们想到了另一种思路 select id from t1 inner join t2 on t1.id = t2.id
好了,大家有需要拿去用吧 ,还有, 因为在hive 不支持直接嵌套查询,所以需要在select 嵌套查询的时候 设置一个临时表
大数据
2018-08-14 15:55:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、我真的确定用户是这样搜的吗? ( 词根都穷尽了没 ?)(蕾丝,露肩,上衣,婚纱。。。)
2、竞争对手是谁?都有哪些?它有专门针对这批词去做的吗?还是无意中杀死对手。。。。
3、竞品分析,比如亚马逊,流量最大来源是产品页,还是列表页?为什么?
4.1、产品词, 从整体上看,我们50万产品页,产品词都有排名了吗? 没有,为什么?
https://www.amazon.com/HDE-Non-Contact-Thermometer-Temperature-Functional/dp/B00QYX6F5G
https://www.amazon.com/Infrared-Thermometer-Contact-Temperature-Measurement/dp/B002OD0NCG
https://www.homedepot.com/p/Milwaukee-Laser-Temperature-Gun-Infrared-10-1-Thermometer-2267-20/206260202
https://www.amazon.com/dp/B00DMI62HM/ref=sspa_dk_detail_5?psc=1&pd_rd_i=B00DMI62HM&pf_rd_m=ATVPDKIKX0DER&pf_rd_p=a54d13fc-b8a1-4ce8-b285-d77489a09cf6&pf_rd_r=XXM1M9PJ15H9VP4RKK05&pd_rd_wg=6c0wE&pf_rd_s=desktop-dp-sims&pf_rd_t=40701&pd_rd_w=m9eoA&pf_rd_i=desktop-dp-sims&pd_rd_r=ecd9878a-a9af-11e8-8742-1712fd196554
4.2 产品词, 从整体上看,我们50万产品页,产品词都有排名了吗?没有!为什么?
因为页面质量不够好。搜索真正匹配的内容有多少?可以用搜索指数来匹配的。结巴分词还是啥搜索引擎有。
https://www.alibaba.com/showroom/infrared-thermometer.html

这里可以找到原因,这是搜索temp gun排到最前面位置的页面,页面起码跟temp gun是非常强相关的。但由于我们没有这么多相关产品,所以这页面上相关内容很少。

比如我要做一批导航站,我2万个导航品牌词,一搜下来,大都有排名的一定会是 导航站 ,因为“整体”上不会有其他网站专门做这么多品牌导航。那么从整体上来讲,他拿了多少流量,这些是不是应该他拿的,有没有可能所有页面都不应该是他该拿的流量呢?比如品牌词+评论,可以,品牌词+产品,这个好像有点难。,。。。。

品牌词+产品,有没有这搜索习惯? 用几个大品牌,就可以确定这搜索习惯了: overseas+online


自己网站的数据:
1.最近 某个目录 流量涨了,可以确定是新增tag页面收录了导致上涨,因为整体排名,点击率没涨,只是展示涨了(验证需要批量查收录)
2.最近详情页没涨,但单个页面曝光率非常高,这说明列表页曝光太低?还是详情页还可以做些优化?比如哪些词应该放在靠前、重要位置?
3.某一单一的页面,最近30天没有多少曝光,什么原因?怎么改善页面达到整体更高的曝光率?
大数据
2018-08-14 11:49:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
hive函数—-集合统计函数
集合统计函数1. 个数统计函数 : count
语法: count(*), count(expr), count(DISTINCT expr[, expr_.])
返回值: int
说明: count(*)统计检索出的行的个数,包括NULL值的行;count(expr)返回指定字段的非空值的个数;count(DISTINCTexpr[, expr_.])返回指定字段的不同的非空值的个数举例: hive> select count(*) from lxw_dual; 20 hive> select count(distinct t) from lxw_dual; 10
2. 总和统计函数 : sum
语法: sum(col), sum(DISTINCT col)
返回值: double
说明: sum(col)统计结果集中col的相加的结果;sum(DISTINCT col)统计结果中col不同值相加的结果
举例: hive> select sum(t) from lxw_dual; 100 hive> select sum(distinct t) from lxw_dual; 70
3. 平均值统计函数 : avg
语法: avg(col), avg(DISTINCT col)
返回值: double
说明: avg(col)统计结果集中col的平均值;avg(DISTINCT col)统计结果中col不同值相加的平均值
举例: hive> select avg(t) from lxw_dual; 50 hive> select avg (distinct t) from lxw_dual; 30
4. 最小值统计函数 : min
语法: min(col)
返回值: double
说明: 统计结果集中col字段的最小值
举例: hive> select min(t) from lxw_dual; 20
5. 最大值统计函数 : max
语法: maxcol)
返回值: double
说明: 统计结果集中col字段的最大值
举例: hive> select max(t) from lxw_dual; 120
6. 非空集合总体变量函数:var_pop
语法: var_pop(col)
返回值: double
说明: 统计结果集中col非空集合的总体变量(忽略null)
举例:
7. 非空集合样本变量函数 :var_samp
语法: var_samp (col)
返回值: double
说明: 统计结果集中col非空集合的样本变量(忽略null)
举例:
8. 总体标准偏离函数 :stddev_pop
语法: stddev_pop(col)
返回值: double
说明: 该函数计算总体标准偏离,并返回总体变量的平方根,其返回值与VAR_POP函数的平方根相同
举例:
9. 样本标准偏离函数 :stddev_samp
语法: stddev_samp (col)
返回值: double
说明: 该函数计算样本标准偏离
举例:
10.中位数函数 :percentile
语法: percentile(BIGINT col, p)
返回值: double
说明: 求准确的第pth个百分位数,p必须介于0和1之间,但是col字段目前只支持整数,不支持浮点数类型
举例:
11. 中位数函数 :percentile
语法: percentile(BIGINT col, array(p1 [, p2]…))
返回值: array
说明: 功能和上述类似,之后后面可以输入多个百分位数,返回类型也为array,其中为对应的百分位数。
举例: select percentile(score,<0.2,0.4>) from lxw_dual;
取0.2,0.4位置的数据
12. 近似中位数函数 :percentile_approx
语法: percentile_approx(DOUBLE col, p [, B])
返回值: double
说明: 求近似的第pth个百分位数,p必须介于0和1之间,返回类型为double,但是col字段支持浮点类型。参数B控制内存消耗的近似精度,B越大,结果的准确度越高。默认为10,000。当col字段中的distinct值的个数小于B时,结果为准确的百分位数
举例:
13. 近似中位数函数 :percentile_approx
语法: percentile_approx(DOUBLE col, array(p1 [, p2]…) [, B])
返回值: array
说明: 功能和上述类似,之后后面可以输入多个百分位数,返回类型也为array,其中为对应的百分位数。
举例:
14. 直方图 :histogram_numeric
语法: histogram_numeric(col, b)
返回值: array
说明: 以b为基准计算col的直方图信息。
举例: hive> select histogram_numeric(100,5) from lxw_dual; [{"x":100.0,"y":1.0}]
大数据
2018-08-13 17:08:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
目前啊,都知道,大数据集群管理方式分为 手工方式(Apache hadoop)和工具方式(Ambari + hdp 和Cloudera Manger + CDH) 。
  手工部署呢 ,需配置太多参数,但是,好理解其原理,建议初学这样做,能学到很多。该方式啊,均得由用户执行,细节太多,切当设计多个组件时,用户须自己解决组件间版本兼容问题。
  工具部署呢 ,比如Ambari或Cloudera Manger。(当前两大最主流的集群管理工具,前者是Hortonworks公司,后者是Cloudera公司)使用工具来,可以说是一键操作,难点都在工具Ambari或Cloudera Manger本身部署上。


               手工方式                    工具方式
难易度        难,几乎不可能成功              简单,易行
兼容性        自己解决组件兼容性问题            自动安装兼容组件
组件支持数      支持全部组件                 支持常用组件
优点         对组件和集群管理深刻             简单、容易、可行
缺点         太复杂,不可能成功              屏蔽太多细节,妨碍对组件理解


工具名        所属机构      开源性        社区支持性      易用性、稳定性      市场占有率
Cloudera Manger   Cloudera      商用          不支持        易用、稳定         高
Ambari      Hortonwork      开源          支持         较易用、较稳定       较高


常见的情况是,Cloudera Manger 去部署CDH
       Ambari去部署HDP,
       当然,两者也可以互相,也可以去部署Apache Hadoop
Cloudera Manager安装之利用parcels方式安装3节点集群(包含最新稳定版本或指定版本的安装)(添加服务)
Ambari安装之部署3个节点的HA分布式集群

Hadoop在大数据领域的应用前景很大,不过因为是开源技术,实际应用过程中存在很多问题。于是出现了各种Hadoop发行版,国外目前主要是三家创业公司在做这项业务:Cloudera、Hortonworks和MapR
Cloudera和MapR的发行版是收费的,他们基于开源技术,提高稳定性,同时强化了一些功能,定制化程度较高,核心技术是不公开的,营收主要来自软件收入。
  这类公司,如果一直保持技术领先性,那么软件收入溢价空间很大。但一旦技术落后于开源社区,整个产品需要进行较大调整。
  Hortonworks则走向另一条路,他们将核心技术完全公开,用于推动Hadoop社区的发展。这样做的好处是,如果开源技术有很大提升,他们受益最大,因为定制化程度较少,自身不会受到技术提升的冲击。

cdh

(1)CDH3版本是基于Apache hadoop 0.20.2改进的,并融入了最新的patch,CDH4版本是基于Apache hadoop 2.X改进的,CDH总
是并应用了最新Bug修复或者Feature的Patch,并比Apache hadoop同功能版本提早发布,更新速度比Apache官方快。
(2)安全CDH支持Kerberos安全认证,apache hadoop则使用简陋的用户名匹配认证
(3)CDH文档清晰,很多采用Apache版本的用户都会阅读CDH提供的文档,包括安装文档、升级文档等。
(4)CDH支持Yum/Apt包,Tar包,RPM
包,Cloudera Manager四种方式安装,Apache hadoop
只支持Tar包安装。
1、联网安装、升级,非常方便
2、自动下载依赖软件包
3、Hadoop生态系统包自动匹配,不需要你寻找与当前Hadoop匹配的Hbase,Flume,Hive等软件,Yum/Apt会根据当前安装Hadoop版本自动寻找匹配版本的软件包,并保证兼容性。
4、自动创建相关目录并软链到合适的地方(如conf和logs等目录);自动创建hdfs, mapred用户,hdfs用户是HDFS的最高权限用户,mapred用户则负责mapreduce执行过程中相关目录的权限。

hortonworks

Hortonworks这个名字源自儿童书中一只叫Horton的大象。雅虎主导Hadoop开发的副总裁,带领二十几个核心成员成立Hortonworks。
Hortonworks有两款核心产品:HDP和HDF
Hortonworks没有对产品收费,而是将这两款产品完全开放,将核心技术放在Hadoop开源社区中,每个人都可以看到并使用这两款产品
企业客户自己开发难度较大的话,就会选择合作。这就是Hortonworks的盈利模式,通过提供支持服务和后期维护,向企业级客户收费。
支持服务主要是通过订阅的方式,客户需要就某些功能预定一年或者几年的服务,提前付费。支持服务覆盖整个周期,从最初的开发和POC阶段,到中间的质量测试,直至产品交付。维护服务主要是对企业级客户的培训和一些咨询业务。


mapr

Marp是一个比现有Hadoop分布式文件系统还要快三倍的产品,并且也是开源的。Mapr配备了快照,并号称不会出现SPOF单节点故障,且被认为是与现有HDFS的API兼容。因此非常容易替换原有的系统。

原文: https://www.dezyre.com/article/cloudera-vs-hortonworks-vs-mapr-hadoop-distribution-comparison-/190
(译文):
对于企业而言,不管过去是否曾使用过Hadoop,正确选择Hadoop商业发行版都很重要。当企业准备投入巨大的财力在Hadoop平台的硬件和解决方案上时,选择某个商业版的Hadoop系统就变得特别重要了。根据业务需要选择正确的Hadoop商业发行版可以带来更多的数据解决方案并且可以获得业界专业人士的认可。这篇文章将从成本、技术细节、部署和维护等几个方面比较Cloudera、Hortonworks和MapR发布的Hadoop版本。
Hadoop 是一个开源项目,先后有许多公司在其框架基础上进行了增强并且发布了商业版本。Hadoop项目的最大诱惑在于使用者可以根据自身的业务需要定制差异化的功能。在Apache开源社区,Hadoop把所有的相关项目组成一个完整的生态系统,用户几乎不费吹灰之力就可以通过搭配一些组件来实现一个完整功能。
哪些人需要Hadoop分布式系统?
l 需要学习和临时使用Hadoop的各行业专业人士
l 需要在大数据的背景下推进业务解决方案演进的各类机构
l 需要在Hadoop生态系统中开发新工具的人员

商业版本的Hadoop有哪些改进?
Hadoop商业发行版的提供者们通过优化核心代码、增强易用性、提供技术支持和持续版本升级为Hadoop平台实现了许多新功能。市场上受认可的Hadoop商业发行版的提供者主要有Cloudera,MapR和Hortonworks。 他们发行的Hadoop商业版本都能与Apache社区开源版本兼容,但它们之间有哪些区别呢? l 框架核心 :Cloudera,MapR和Hortonworks这三家公司都把Hadoop核心框架打包到了他们的商业版本中;在这基础上,他们都提供了技术支持服务和定制化开发服务。
l 系统集成 :MapR 的商业版Hadoop可靠地支持一系列功能,包括:实时流数据处理,与已有系统集成的内嵌的连接器,数据安全保护,企业级工程品质。
l 系统管控 :Cloudera和MapR 商业发行版中都包含了为系统管理员提供了配置、监控和优化的管控平台。
Cloudera,Hortonworks和MapR异同之处分析
版本 优点 缺点
CDH CDH有一个友好的用户界面及一些实用的工具,比如:Impala CDH相对MapR Hadoop来说,运行效率显著降低
MapR Hadoop
HDP
运行效率高;节点之间可以通过NFS直接访问
唯一一个能运行在Windows上的Haoop系统
MapR Hadoop没有像CDH那样的用户界面
Ambari管控界面功能比较简单,不够丰富
相似性: l Cloudera, Hortonworks 和MapR三家公司都专注于Hadoop平台开发,商业版本的Hadoop系统是他们的全部收入来源。 l 这三家公司都是中等规模的公司,都拥有一些优质客户和来自其他行业的投资伙伴。 l 这三家公司都提供了免费版本的下载,不同的是,MapR和Cloudera 还为付费客户提供功能增强版本。 l 这三家公司都建立了技术支持社区帮助用户解决遇到的问题以及在用户需要时提供系统演示。 l 这三家公司都通过测试保证发行版本满足用户业务对稳定性和安全性需求。

下面我们会在对比每一个商业版本功能的基础上分析其差异性:
Cloudera — CDH
Cloudera 是Hadoop领域知名的公司和市场领导者,提供了市场上第一个Hadoop商业发行版本。它拥有350多个客户并且活跃于Hadoop生态系统开源社区。在多个创新工具的贡献着排行榜中,它都名列榜首。它的系统管控平台——Cloudera Manager,易于使用、界面清晰,拥有丰富的信息内容。Cloudera 专属的集群管控套件能自动化安装部署集群并且提供了许多有用的功能,比如:实时显示节点个数,缩短部署时间等。同时,Cloudera 也提供咨询服务来解决各类机构关于在数据管理方案中如何使用Hadoop技术以及开源社区有哪些新内容等疑虑。美国电商“高朋”公司是CDH的用户。
CDH的主要特性: l 在线不停机添加新组件
l 多集群统一管理
l 提供差异化配置的节点模板。用户不必使用单一配置的Hadoop集群,可以依此创建差异化配置的集群。
l Hortonworks 和Cloudera都依赖于HDFS的DataNode 和NameNode架构来做数据切分。

MapR — Hadoop
MapR的Hadoop商业发行版紧盯市场需求,能更快反应市场需要。一些行业巨头如思科、埃森哲、波音、谷歌、亚马逊都是MapR的Hadoop的用户。与Cloudera和Hortonworks不同的是, MapR Hadoop不依赖于Linux文件系统,也不依赖于HDFS,而是在MapRFS文件系统上把元数据保存在计算节点,快速进行数据的存储和处理。
MapR Hadoop的主要特性: l 由于它基于MapRFS,它是唯一一个能不依赖于Java而提供Pig,Hive和Sqoop的Hadoop。
l MapR Hadoop是最适合应用于生产环境的Hadoop版本,它包含了许多易用性、高效和可信赖的增强功能。
l MapR Hadoop集群节点可以通过NFS直接访问,因此用户可以像使用Linux文件系统一样在NFS上直接挂载MapR文件。
l MapR Hadoop提供了完整的数据保护,方便使用并且没有单点故障。
l MapR Hadoop被认为是运行最快的Hadoop版本。
尽管从集群规模来说,MapR Hadoop还不如Hortonworks 和Cloudera,只能暂列第三,但相对其它版本的Hadoop来说,它易用性最强,运行最快。因此,如果用户想选择带有足够创意和学习资料的Hadoop,那么MapR Hadoop将是不二之选。

Hortonworks — HDP
Hortonworks是由一些雅虎的工程师创立的公司,提供针对Hadoop的技术服务。与其它公司不同的是,它提供完全开源的Hadoop数据平台并且用户可以免费使用。用户可以很方便得下载Hortonworks 的Hadoop发行版HDP并把它集成到各种应用中。Ebay、三星、彭博、Spotify 都是HDP的用户。Hortonworks 也是第一个基于Hadoop 2.0提供满足生产环境需要的Hadoop版本。尽管CDH在其早期的版本中包含了Hadoop 2.0的部分功能,但这些功能无法满足生产环境需要。HDP 也是目前唯一能支持Windows的Hadoop版本。用户可以在Azure 上通过HDInsight 服务部署Windows上的 Hadoop。
HDP的主要特性:
l HDP 通过Stinger项目提升了Hive的性能
l HDP 通过新的Hadoop分支来避免用户被厂商绑定
l 聚焦于提升Hadoop平台的实用性

通过对Hadoop市场上的这三家公司的产品战略和功能分析后,我们很难简单说谁更胜一筹。各类机构需要根据自身业务程度需要来选择Hadoop商业版本。回答下面这些问题可以帮助用户做出选择: 1. 是否会使系统管理员工作更加高效?
2. 是否便于Hadoop开发人员和业务分析人员访问数据?
3. 是否满足机构内部关于数据安全的规章制度要求?
4. 是否适合机构内部的系统运行环境?
5. 是否需要Hadoop提供的所有组件和能力?
6. 是否需要大数据的整体解决方案来支撑业务盈利?以及是否需要紧跟开源以减少被厂商绑定?
7. 系统可靠性、技术支持、扩展功能等是否非常重要?

用户如果期望得到一个像样的产品,那选择MapR Hadoop比较适合;如果需要紧跟开源,那么就应该选择Hortonworks;如果用户的业务需求需要介于二者之间,那么Cloudera 就是个不错的选择了。
如何选择Hadoop发行版完全取决于用户在实施Hadoop平台中遇到了什么样的困难。Hadoop商业发行版可以帮助用户把Hadoop平台和其他异构数据分析平台灵活、可靠、可视化地连接起来。每个Hadoop发行版都有其各自的优点和缺点。在选择时,不仅要平衡风险和成本,也要考虑各种发行版的附加功能是否符合实际业务场景需要。
一 、Hadoop版本综述

目前Hadoop发行版非常多,有华为发行版、Intel发行版、Cloudera发行版(CDH)等,所有这些发行版均是基于Apache Hadoop衍生出来的,之所以有这么多的版本,完全是由Apache Hadoop的开源协议决定的:任何人可以对其进行修改,并作为开源或商业产品发布/销售。(http://www.apache.org/licenses/LICENSE-2.0)。

国内绝大多数公司发行版是收费的,比如Intel发行版、华为发行版等,尽管这些发行版增加了很多开源版本没有的新feature,但绝大多数公司选择Hadoop版本时会将把是否收费作为重要指标,不收费的Hadoop版本主要有三个(均是国外厂商),分别是:
Cloudera版本 (Cloudera’s Distribution Including Apache Hadoop,简称“ CDH ”)、
Apache基金会hadoop 、
Hortonworks版本 (Hortonworks Data Platform,简称“ HDP ”)--------按顺序代表了,在国内的使用率,CDH和HDP虽然是收费版本,但是他们是开源的,只是收取服务费用。

对于国内而言,绝大多数选择CDH版本,主要理由如下:

(1) CDH对Hadoop版本的划分非常清晰,只有两个系列的版本(现在已经更新到CDH5.20了,基于hadoop2.x),分别是cdh3和cdh4,分别对应第一代Hadoop(Hadoop 1.0)和第二代Hadoop(Hadoop 2.0),相比而言,Apache版本则混乱得多;
(2) CDH文档清晰,很多采用Apache版本的用户都会阅读cdh提供的文档,包括安装文档、升级文档等。

CDH与Apache版本的对应:
cdh3版本是基于apache hadoop 0.20.2
cdh3u6对应到apache hadoop最新版本(Hadoop 1.x)
cdh4对应apache hadoop 2.x

HDP版本是比较新的版本,目前与apache基本同步,因为Hortonworks内部大部分员工都是apache代码贡献者,尤其是Hadoop 2.0的贡献者。
二、社区版本与第三方发行版本的比较

1.Apache社区版本

优点:
完全开源免费。
社区活跃
文档、资料详实

缺点:
----复杂的版本管理。版本管理比较混乱的,各种版本层出不穷,让很多使用者不知所措。
----复杂的集群部署、安装、配置。通常按照集群需要编写大量的配置文件,分发到每一台节点上,容易出错,效率低下。
----复杂的集群运维。对集群的监控,运维,需要安装第三方的其他软件,如ganglia,nagois等,运维难度较大。
----复杂的生态环境。在Hadoop生态圈中,组件的选择、使用,比如Hive,Mahout,Sqoop,Flume,Spark,Oozie等等,需要大量考虑兼容性的问题,版本是否兼容,组件是否有冲突,编译是否能通过等。经常会浪费大量的时间去编译组件,解决版本冲突问题。

2.第三方发行版本(如CDH,HDP,MapR等)

优点:
----基于Apache协议,100%开源。
----版本管理清晰。比如Cloudera,CDH1,CDH2,CDH3,CDH4等,后面加上补丁版本,如CDH4.1.0 patch level 923.142,表示在原生态Apache Hadoop 0.20.2基础上添加了1065个patch。
----比Apache Hadoop在兼容性、安全性、稳定性上有增强。第三方发行版通常都经过了大量的测试验证,有众多部署实例,大量的运行到各种生产环境。
----版本更新快。通常情况,比如CDH每个季度会有一个update,每一年会有一个release。
----基于稳定版本Apache Hadoop,并应用了最新Bug修复或Feature的patch
----提供了部署、安装、配置工具,大大提高了集群部署的效率,可以在几个小时内部署好集群。
----运维简单。提供了管理、监控、诊断、配置修改的工具,管理配置方便,定位问题快速、准确,使运维工作简单,有效。

缺点:
----涉及到厂商锁定的问题。(可以通过技术解决)

三、第三方发行版本的比较

Cloudera:最成型的发行版本,拥有最多的部署案例。提供强大的部署、管理和监控工具。Cloudera开发并贡献了可实时处理大数据的Impala项目。
Hortonworks: 不拥有任何私有(非开源)修改地使用了100%开源Apache Hadoop的唯一提供商。Hortonworks是第一家使用了Apache HCatalog的元数据服务特性的提供商。并且,它们的Stinger开创性地极大地优化了Hive项目。Hortonworks为入门提供了一个非常好的,易于使用的沙盒。Hortonworks开发了很多增强特性并提交至核心主干,这使得Apache Hadoop能够在包括Windows Server和Windows Azure在内的Microsft Windows平台上本地运行。
MapR :与竞争者相比,它使用了一些不同的概念,特别是为了获取更好的性能和易用性而支持本地Unix文件系统而不是HDFS(使用非开源的组件)。可以使用本地Unix命令来代替Hadoop命令。除此之外,MapR还凭借诸如快照、镜像或有状态的故障恢复之类的高可用性特性来与其他竞争者相区别。该公司也领导着Apache Drill项目,本项目是Google的Dremel的开源项目的重新实现,目的是在Hadoop数据上执行类似SQL的查询以提供实时处理。

四、版本选择
当我们决定是否采用某个软件用于开源环境时,通常需要考虑以下几个因素:
(1)是否为开源软件,即是否免费。
(2) 是否有稳定版,这个一般软件官方网站会给出说明。
(3) 是否经实践验证,这个可通过检查是否有一些大点的公司已经在生产环境中使用知道。
(4) 是否有强大的社区支持,当出现一个问题时,能够通过社区、论坛等网络资源快速获取解决方法。
题外篇:
市场,场景,策略及上市的步调不同
三家马车中,Hortonwork和Cloudera先后上市,MapR也加快了上市步伐。
2014年,Hortonworks成功IPO在纳斯达克上市。该公司以每股16美元的价格发行625万股股票,募集1亿美元资金,开盘首日上涨幅度达到60%,市值接近11亿美元。
2017年4月底,Cloudera以每股15美元的定价在纽约证券交易所上市,股价一日上涨超20%至18.09美元。这一价格也超出了此前公司12到14美元的预期范围。Cloudera目前市值约为23亿美元,远低于2014年英特尔给出的41亿美元估值。
MapR于2009年成立,曾在五轮风险投资里拿到1.14亿美元。公司的风投支持者通常希望看到两个结果,其一是上市,另一个是被收购。但是媒体2017年6月报道,公司MapR的首席执行官米尔斯说不愿说上市的日期,但表示上市已提到议事日程上。米尔斯表示,“我想上市,但我也想尊重上市的步骤。”
赢利还是亏损
三大公司的营收情况怎么样?这可以说是Hadoop 商业化世界的一个风向标。
Hortonworks于2017年5月公布的消息现实,公司2017年第一季度收入5600万美元,同比增长35%,利润率更高,经营亏损收窄。但是目前依然是亏损。
Cloudera的收入正在增长,截止到1月份的上一财年营收达到2.61亿美元,亏损为1.86亿美元;2015财年营收为1.66亿美元,亏损2.03亿美元。Cloudera的多数营收都来自订阅收入,订阅期通常为1至3年,但他们还通过服务获取营收,包括专业服务、培训和教育等。
MapR公司的CEO米尔斯认为,MapR的销售额在不断增长,平均交易规模大于10万美元,但他不愿评论成本或亏损。
商业模式
同样基于开源的Hadoop,但是三大公司所采用的商业模式却各有不同。
Cloudera采用发布Hadoop商业版和发布商用工具的模式。所谓的Hadoop发行商,有点类似于Linux世界里的RedHat。公司通过开源软件的包装,整合稳定的版本形成一个套餐。通过让企业用户购买套餐来实现盈利。所以,Cloudera给所有使用了其Hadoop的套餐的用户提供收费技术支持。
同时,Cloudera也提供免费的版,用户可以在网站上随便下载免费使用的。但是Cloudera同时又提供如Cloudera Manager的企业管理组件,在最初三个月试用之后就要收费的。
MapR走的和Cloudera类似的商业模式,但是它是以发布商业化工具产品为主,同时提供发行版。
Hortonworks提供的软件都是100%开源免费下载,将核心技术放在Hadoop开源社区中,每个人都可以看到并使用。对于企业客户来说有了源代码,如何与自己系统相结合、增强功能、调试故障、对接应用等都是问题。企业客户如果想用这项技术,自己开发难度较大的话,就会选择合作。这就是Hortonworks的盈利模式,通过提供支持服务和后期维护,向企业级客户收费。
支持服务主要是通过订阅的方式,客户需要就某些功能预定一年或者几年的服务,提前付费。支持服务覆盖整个周期,从最初的开发和POC阶段,到中间的质量测试,直至产品交付。维护服务主要是对企业级客户的培训和一些咨询业务。
敢兴趣了解下 :Cloudera和Hortonworks的开源(撒逼)之战
Cloudera与Hortonworks谁能一骑绝尘?
大数据
2018-08-13 16:50:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
前阶段用了差不多两周的时间把DKhadoop的运行环境搭建以及安装的各个操作都介绍了一遍。关于DKhadoop安装包下载也只是顺带说了一下,但好像大快搜索的服务器在更新,新的下载页面还不好用!有好些朋友留言说了大快搜索网站上无法下载。我已经将之前下载的这个版本上传到了网盘了,需要的DKhadoop安装包的朋友可以直接通过网盘下载! DKHadoop安装包下载: 关于DKhadoop版本在写Hadoop环境搭建部署的时候有提到过,大版本主要有DKHadoop标准版本、DKH-分布式SQL版本、DKHadoop商业发行版。我们自己可以去下载到的包括我之前下载的安装包版本都是三节点的学习版本。DKhadoop标准版本有测试用的单机版,支持3节点的学习版本,以及支持个人研发用的5节点标准服务器版本。3节点此前是提供免费下载,5节点可能需要提交申请,但还好同样也是免费的! DKHadoop安装包下载地址: https://pan.baidu.com/s/1-427Sh6lTLrLAPh6KMOYVg 密码: vg2w DKM平台监控参数说明: 平台监控参数的内容主要就是针对下载安装了DKHadoop的朋友了,下面简单的各大家介绍几个监控参数。 1、首页监控界面 (1) 集群平均负载 监控集群CUP负载 纵轴表示 任务数量,单位个 横轴表示时间,单位分钟 表示集群内等待的任务数量, 比如1分钟的红线代表在1分钟之内需要等待执行的任务数量, 5分钟的线代表5分钟之内需要等待执行的任务数量。 (2)集群磁盘IO 监控集群磁盘IO 纵轴表示读写速度,单位KB/S 横轴表示时间,单位分钟 磁盘字节写入速度表示写磁盘的速度。 磁盘字节数量读取表示读磁盘的速度。单位是KB/S (3)集群磁盘使用情况 监控集群磁盘使用的情况 纵轴表示磁盘空间 ,单位GB 横轴表示时间,单位分钟 Total:表示集群磁盘的总体空间 Free:表示空余空间 Used:表示已经使用的空间 2、HDFS监控界面 (1) HDFS 容量监控 监控集群中HDFS的容量 纵轴表示HDFS的容量,单位GB 横轴表示时间,单位分钟 (2) DataNode 读取字节数 监控集群中DataNode 读取量 纵轴表示DataNode字节数,单位B 横轴表示时间,单位分钟 (3) DataNode 写入字节数 监控集群中DataNode 写入量 纵轴表示DataNode字节数,单位B 横轴表示时间,单位分钟 3、Hbase监控界面 (1) RegionServer 的总数 监控RegionServer 的总数 纵轴表示数量,单位个 横轴表示时间,单位分钟 (2)RegionServer中memstoresize的数量
监控RegionServer中memstoresize的数量 纵轴表示数量,单位个 横轴表示时间,单位分钟 (3) RegionServer 读写请求次数 监控 RegionServer 读写请求次数 纵轴表示次/每秒,单位秒 横轴表示时间,单位分钟 (4) RegionServer 中总store个数
监控 RegionServer 中总store个数 纵轴表示store数量,单位个 横轴表示时间,单位分钟 (5) RegionServer 中总storFile个数
监控 RegionServer 中总storeFile个数 纵轴表示storeFile数量,单位个 横轴表示时间,单位分钟 DKH平台监控参数太多,本篇就简单介绍这几个吧,不然码的篇幅太长,看着也累!下次将会接着就监控平台的参数进行说明。我尽量把我知道的写完吧!本文的重点还是最上部分的安装包下载,提取码上面也给了。下载玩一下吧!
大数据
2018-08-13 15:03:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
主程序 package com.streaming.flink; import java.util.Properties; import org.apache.flink.api.common.functions.FlatMapFunction; import org.apache.flink.api.common.functions.MapFunction; import org.apache.flink.api.common.functions.ReduceFunction; import org.apache.flink.api.common.serialization.SimpleStringSchema; import org.apache.flink.api.java.DataSet; import org.apache.flink.api.java.ExecutionEnvironment; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer08; import org.apache.flink.util.Collector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSONObject; public class WordCount { private static final Logger logger = LoggerFactory .getLogger(WordCount.class); public static void main(String[] args) throws Exception { final ExecutionEnvironment env = ExecutionEnvironment .getExecutionEnvironment(); StreamExecutionEnvironment tenv = StreamExecutionEnvironment .getExecutionEnvironment(); // 2.从自定义source中读取数据 // DataStream dataStream = tenv.addSource(new JdbcRead()); // tenv.execute(); // get input data DataSet text = env.fromElements( "To be, or not to be,--that is the question:--", "Whether 'tis nobler in the mind to suffer", "The slings and arrows of outrageous fortune", "Or to take arms against a sea of troubles,"); DataSet> counts = text.flatMap(new LineSplitter()).groupBy(0).sum(1); text.flatMap(new LineSplitter()).groupBy(0); DataSet> sum = text.flatMap(new LineSplitter()) // group by the tuple field "0" and sum up tuple field "1" .reduce(new ReduceFunction>() { @Override public Tuple2 reduce( Tuple2 a, Tuple2 b) { return new Tuple2(a.f0, a.f1 + b.f1); } }); FlinkKafkaConsumer08 kafkaSource = createKafka(tenv); String hbase_zk="namenode1.xxx.com"; String hbase_port="2015"; String hbase_table="ns:table1"; tenv.addSource(kafkaSource).map(new MapFunction() { public String map(String line) { logger.error("收到消息:{}", line); return line; } }).process(new HbaseSink(hbase_zk,hbase_port,hbase_table)); tenv.execute(); // execute and print result // counts.print(); } /** * Implements the string tokenizer that splits sentences into words as a * user-defined FlatMapFunction. The function takes a line (String) and * splits it into multiple pairs in the form of "(word,1)" * (Tuple2<String, Integer>). */ public static final class LineSplitter implements FlatMapFunction> { @Override public void flatMap(String value, Collector> out) { String[] tokens = value.toLowerCase().split("\\W+"); for (String token : tokens) { if (token.length() > 0) { out.collect(new Tuple2(token, 1)); } } } } public static FlinkKafkaConsumer08 createKafka( StreamExecutionEnvironment tenv) { String zkConnc = "kafkazk01.xxx.com:2181"; String kafkaServer = "kafkabroker01.xxx.com:9092"; Properties kafkaProps = new Properties(); kafkaProps.setProperty("zookeeper.connect", zkConnc); kafkaProps.setProperty("bootstrap.servers", kafkaServer); kafkaProps.setProperty("group.id", "groupId_1"); kafkaProps.setProperty("auto.offset.reset", "smallest"); kafkaProps.setProperty("auto.commit.interval.ms", "30000"); kafkaProps.setProperty("enable.auto.commit", "true"); FlinkKafkaConsumer08 appSource = new FlinkKafkaConsumer08( "topicName", new SimpleStringSchema(), kafkaProps); return appSource; } }
写hbase: package com.streaming.flink; import org.apache.flink.streaming.api.functions.ProcessFunction; import org.apache.flink.util.Collector; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.Durability; import org.apache.hadoop.hbase.client.HConnection; import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.security.UserGroupInformation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HbaseSink extends ProcessFunction { private static final long serialVersionUID = 1L; private static final Logger LOGGER = LoggerFactory.getLogger(HbaseSink.class); private String _zookeeper; private String _port; private String _tableName; private HTableInterface _table; public HbaseSink(String zookeeper, String port, String tableName) { _zookeeper = zookeeper; _port = port; _tableName = tableName; } @Override public void open(org.apache.flink.configuration.Configuration parameters) throws Exception { try { Configuration conf = HBaseConfiguration.create(); conf.set(HConstants.ZOOKEEPER_QUORUM, _zookeeper); conf.set(HConstants.ZOOKEEPER_CLIENT_PORT, _port); conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/hbase"); User user = User.create(UserGroupInformation.createRemoteUser("bmps")); HConnection connection = HConnectionManager.createConnection(conf,user); _table = connection.getTable(_tableName); LOGGER.error("[HbaseSink] : open HbaseSink finished"); } catch (Exception e) { LOGGER.error("[HbaseSink] : open HbaseSink faild {}", e); } } @Override public void close() throws Exception { _table.close(); } @Override public void processElement(String value, Context ctx, Collector out) throws Exception { LOGGER.error("process String {}",value); String rowKey = new StringBuffer().append("1").toString(); Put put = new Put(Bytes.toBytes(rowKey)); put.setDurability(Durability.ASYNC_WAL); put.add(Bytes.toBytes("info"), Bytes.toBytes("flink"), Bytes.toBytes(value)); _table.put(put); LOGGER.error("[HbaseSink] : put rowKey:{}, value:{} to hbase", rowKey, value); } }
读mysql: package com.streaming.flink; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import org.apache.flink.configuration.Configuration; import org.apache.flink.streaming.api.functions.source.RichSourceFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JdbcRead extends RichSourceFunction { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory.getLogger(JdbcRead.class); private Connection connection = null; private PreparedStatement ps = null; /** * 一、open()方法中建立连接,这样不用每次invoke的时候都要建立连接和释放连接。 */ @Override public void open(Configuration parameters) throws Exception { super.open(parameters); String driver = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://127.0.0.1:3309/zkMonitor?characterEncoding=utf8&useSSL=true"; String username = "root"; String password = "123456"; // 1.加载驱动 Class.forName(driver); // 2.创建连接 connection = DriverManager.getConnection(url, username, password); // 3.获得执行语句 String sql = "select name from t_stock_pin;"; ps = connection.prepareStatement(sql); } /** * 二、DataStream调用一次run()方法用来获取数据 */ @Override public void run(SourceContext sourceContext) { try { // 4.执行查询,封装数据 ResultSet resultSet = ps.executeQuery(); while (resultSet.next()) { String name = resultSet.getString("name"); logger.error("readJDBC name:{}", name); sourceContext.collect(name); } } catch (Exception e) { logger.error("runException:{}", e); } } @Override public void cancel() { } /** * 三、 程序执行完毕就可以进行,关闭连接和释放资源的动作了 */ @Override public void close() throws Exception { // 5.关闭连接和释放资源 super.close(); if (connection != null) { connection.close(); } if (ps != null) { ps.close(); } } }
最后是pom配置: 4.0.0 com.streaming.flink flink-training 1.0-SNAPSHOT jar Flink Quickstart Job http://www.myorganization.org UTF-8 1.4.1 1.7.7 1.2.17 2.11 apache.snapshots Apache Development Snapshot Repository https://repository.apache.org/content/repositories/snapshots/ false true mysql mysql-connector-java 5.1.6 org.apache.flink flink-core ${flink.version} org.apache.flink flink-java ${flink.version} org.apache.flink flink-clients_${scala.binary.version} ${flink.version} org.apache.flink flink-streaming-java_${scala.binary.version} ${flink.version} org.apache.flink flink-connector-kafka-0.8_2.11 ${flink.version} org.apache.hbase hbase-client 0.98.8-hadoop2 jdk.tools jdk.tools org.slf4j slf4j-log4j12 ${slf4j.version} log4j log4j ${log4j.version} build-jar false org.apache.flink flink-core ${flink.version} provided org.apache.flink flink-java ${flink.version} provided org.apache.flink flink-clients_${scala.binary.version} ${flink.version} provided org.apache.flink flink-streaming-java_${scala.binary.version} ${flink.version} provided org.slf4j slf4j-log4j12 ${slf4j.version} provided log4j log4j ${log4j.version} provided org.apache.maven.plugins maven-shade-plugin 2.4.1 package shade org.apache.flink:force-shading com.google.code.findbugs:jsr305 org.slf4j:* *:* META-INF/*.SF META-INF/*.DSA META-INF/*.RSA org.apache.maven.plugins maven-compiler-plugin 3.1 1.8 1.8
大数据
2018-08-19 16:39:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、概述
1.1 简介
1、Hive提供了一个被称为Hive查询语言(简称HiveQL或HQL)的SQL语言,来查询存储在HDFS中的结构化数据文件,它把HQL语句的查询转换为MapReduce任务。
2、Hive应用场景:
(1)数据仓库:数据抽取、数据加载、数据转换
(2)数据汇总:每天/每周用户点击数、流量统计
(3)非实时分析:日志分析、文本分析
(4)数据挖掘:用户行为分析、兴趣分区、区域展示
1.2 架构

hive是典型C/S模式,Client端有JDBC/ODBC Client和Thrift Client两类。Server端则分为如下几个部分: CLI: CLI是和Hive交互的最简单/最常用方式,你只需要在一个具备完整Hive环境下的Shell终端中键入 hive 即可启动服务。 Thrift Server: Hive Thrift Server是基于Thrift 软件框架开发的,它提供Hive的RPC通信接口。目前的HiveServer2(HS2)较之前一版HiveServer,增加了多客户端并发支持和认证功能,极大地提升了Hive的工作效率和安全系数。 Metastore: Metastore是Hive元数据的存储地。在功能上Metastore分为两个部分:服务和存储,也就是架构图中提到的Metastore及其Database。通常使用MySQL来存储元数据。 WUI: WUI并不属于Apache Hive,它是Hive生态圈的一项服务,目前熟知的有Karmasphere、Hue、Qubole等项目。WUI是B/S模式的服务进程,Server一端与Hive Thrfit Server交互,Brower一端供用户进行Web访问。 Driver: 每一个Hive服务都需要调用Driver来完成HQL语句的翻译和执行。通俗地说,Driver就是HQL编译器,它解析和优化HQL语句,将其转换成一个Hive Job(可以是MapReduce,也可以是Spark等其他任务)并提交给Hadoop集群。

1.3 特性
1.3.1 优点
(1)高可靠、高容错:HiveServer采用主备模式、双MetaStore、超时重试
(2)类SQL:类似sql语句、内置大量函数
(3)可扩展:自定义存储格式、自定义函数
1.3.2 缺点
(1)延迟较高:默认M/R为执行引擎、M/R启动有延迟
(2)不支持物化视图:虽然提供了视图的概念,但还不支持物化视图;不能再视图上更新、插入、删除数据
(3)不适用OLTP:暂不支持行级别的数据添加、更新、删除操作
(4)暂无支持存储过程

2、数据类型

Hive表字段所支持的数据类型分为两类:基本数据类型和集合数据类型
2.1 基本数据类型
tinyint、smallint、int、bigint、boolean、float、double、string、timestamp、binary
2.2 集合数据类型
struct(结构体或者对象)、map(键-值对)、array(数组)

举个例子,创建一张员工表。
CREATE TABLE employees (
name STRING,
salary FLOAT,
subordinates ARRAY,
deductions MAP,
address STRUCT);
name表示员工姓名,salary是薪水,subordinates是下属员工的姓名集合数组,deductions是一个由键-值对构成的map,记录了每一次的扣除额,address是家庭住址,使用struct数据类型存储,其中的每个域都被作了命名,并且具有一个特定的类型。

3、读时模式 VS 写时模式
传统型数据库采用写时模式,即在数据写入数据库时对模式进行检查。Hive不会在数据加载时进行验证,而是在查询时进行,也就是读时模式。如果模式和文件内容并不匹配,hive会极力读取这些数据。比如每行记录中的字段个数少于对应的模式中定义的字段个数的话,那么用户将会看到查询结果中多出来的字段值为null。

4、HiveQL:数据定义
4.1 新增数据库
create database [数据库名];
如果没有显示指定数据库,那么将会使用默认的数据库default;
数据库所在的目录位于属性 hive.metastore.warehouse.dir 所指定的顶层目录之后,假设使用的是默认的配置,也就是/user/hive/warehouse,那么当我们创建数据库financials时,Hive将会对应地创建一个目录/user/hive/warehouse/financials.db,financials.db是一个文件夹,在financials数据库下建的表对应的文件都放这个目录下面。
4.2 建表
4.2.1 管理表(内部表)
默认创建的表即为管理表(内部表),区别于外部表,管理表(内部表)的数据文件是加载到内部,由hive来管理。
create table 表名(列名 列类型,列名 列类型......) location '路径';
location指定表对应的目录,默认为对应数据库目录下面,如在financials数据库下面新建的records表对应的目录为/user/hive/warehouse/financials.db/records,后面该表对应的数据文件会存储到该目录下。
4.2.2 外部表
create external table if not exists [表名] (列名 列类型,列名 列类型.....)
row format delimited fields terminated by ','
location '路径';
关键字external 来表名创建的是外部表,location声明该表对应的数据文件的位置,该位置处于外部系统,hive不会把该数据文件加载到系统内。在删除表时,hive不会同时此数据文件。
外部表适用于hive和其他的工具共用一份数据,可以进行一些查询的操作,但hive并不拥有此数据的所有权。
4.2.3 分区表
创建一张表partition_log,以dt和country这两个字段进行分区。
create table partition_log(ts bigint, line string) partitioned by (dt string, country string);
从本地文件给表partition_log加载数据,在加载时要为加载的数据指定分区,这里指定的值dt为2001-01-01,2001-01-01为GB。
load data local inpath '/root/hive/partitions/file1' into table partition_log partition (dt='2001-01-01', country='GB');
hive此时会在partition_log表对应的路径下面创建 /dt=2001-01-01/country=GB/ 这两级目录。
分区表本质上就是将数据进行归类,同一类的数据放到一个文件夹下,提供查询的效率。
4.2.4 外部分区表
要使用外部分区表,首先要创建一张外部表。
create external table external_table (列名 列类型,列名 列类型....) partitioned by (year int, month int ,day int)
用alter table为表增加一个分区,并为该分区指定一个外部文件的路径。
alter table external_table add partition(year=2012,month=1,day=2) location 'hdfs://master_server/data/log_messages/2012/01/02'

5、HiveQL:数据操作
5.1 向管理表中装载数据
load data local inpath '${env.HOME}/california-employees' overwrite into table employees partition (country='US', state='CA');
inpath指定数据文件的路径,此路径可以是一个目录,hive会把该目录下所有的文件都加载进来。partition指定分区,如果不是分区可以省略。overwrite关键字表示覆盖,hive会把原先表目录下的数据文件删除再加载新的数据文件。

5.2 通过查询语句向表中插入数据
insert overwrite table employees partition (country='US',state='OR')
select * from staged_employees se where se.cntry='US' and se.st='OR';
如果向多个分区插入数据,可以采用如下方式:
from staged_employees se
insert overwrite table employees
partition(country='US' , state='OR')
select * where se.cnty='US' and se.st='OR'
insert overwrite table employees
partition(country='US',state='CA')
select * where se.cnty='US' and se.st='CA';

动态分区插入
基于查询参数推断出需要创建的分区名称。
insert overwrite table employees
partition (country,state)
select ... ,se.cnty,se.st
from staged_employees se;
Hive根据select语句中最后2列来确定分区字段country和state的值。
也可以混合使用动态和静态分区,下面例子指定了country字段的值为静态的US,而分区字段state是动态值:
insert overwrite table employees partition (country='US',state)
select ...,se.cnty,se.st from staged_employees se where se.cnty='US';
静态分区键必须出现在动态分区键之前。

5.3 单个查询语句中创建表并加载数据
create table ca_employees
as select name,salary,address
from employees where se.state='CA';

6、HiveQL:查询
6.1 select ... from...语句
1、查询array数组中的元素,使用索引来查找,比如:
select name,subordinates[0] from employees;
2、查询map中的元素用 [键名]
select name,deductions["State Taxes"] from employees;
3、查询struct中的元素用“点”符号
select name,address.city from employees;
limit语句
限制返回的行数
select * from employees limit 2;
case...when...then 句式
case...when...then语句和if条件语句类似,用于处理单个列的查询结果。例如:
select name,salary,
case
when salary<5000.0 then 'low'
when salary>=5000.0 and salary<7000.0 then 'middle'
when salary>7000.0 then 'high'
end as bracket from employees;

6.2 where语句
1、like和rlike
like和rlike都可以进行模糊匹配,rlike是like的增强版,可以通过正则表达式来指定匹配条件,例如:
select name,address.street from employees where address.street rlike '.*(Chicago|Ontario).*';
6.3 group by 语句
having语句
having语句用来对group by产生的分组进行条件过滤,例如:
select avg(price_close) from stocks where exchange='NASDAQ' and symbol='AAPL' group by year
having avg(price_close)>50.0
6.4、join语句
1、 内连接 :只有进行连接的两个表中都存在与连接标准相匹配的数据才会被保留下来。Hive的join语句只支持等值连接,不支持“<” 和“>”。
select a.ymd, a.price_close, b.price_close from stocks a join stocks b on a.ymd=b.ymd where a.symbol='APPL' and b.symbol='IBM';
2、 join语句优化 :hive在执行join语句时,会把其他表都缓存起来,然后扫描最后那个表进行计算。所以在保证join语句中表从左至右要依次递增。比如:
select a.name, b.companyname from company a join employees b on a.companycode=b.companycode,要保证表大小company 3、 left outer join左外连接 :左边表符合where条件的全部保留,对应右边表选择的列如果没有符合连接条件的将会返回null值。
4、 right outer join右外连接 :返回右边表所有符合where语句的记录。左表中匹配不上的字段用null代替。

6.5 order by 、sort by、distribute by、cluster by
1、 order by: 进行全局排序,会有一个所有的数据都通过一个reducer进行处理的过程。
2、 sort by: 进行局部排序,只会在每个reducer中对数据进行排序。
distribute by: distribute by和sort by配合使用。distribute by可以让具有相同字段值的记录被分发到一个reducer,实现了对数据进行分组,并根据sort by指定的字段进行组内排序。例如:
select s.ymd, s.symbol, s.price_close from stocks s distribute by s.symbol sort by s.symbol ASC, s.ymd ASC;
3、 cluster by: 相当于distribute by...sort by...语句中distribute by 和sort by的是同一个字段,表示对数据进行分组显示。
select s.ymd, s.symbol, s.price_close from stocks s cluster by s.symbol;

7、HiveQL:视图
视图可以允许保存一个查询并像对待表一样对这个查询进行操作。这是一个逻辑结构,因为它不像一个表会存储数据。换句话说,Hive目前暂不支持物化视图。
使用视图的好处:
1、降低查询复杂度,例如下面以个嵌套子查询:
from (
select * from people join cart
on (cart.people_id=people.id) where firstname='john'
) a select a.lastname where a.id=3;
将嵌套子查询声明为一个视图:
create view shorter_join as
select * from people join cart on (cart.people_id=people.id) where firstname='john';
这样就可以用这个视图来简化第一个查询:
select lastname from shorter_join where id=3;
2、视图可以只展示一张表的部分内容,而不会让用户看到全部。

8、HiveQL:索引
Hive只有有限的索引功能,因为Hive没有主键和外键。建立索引可以加速查询速度。一张表的索引数据存储在另一张表中。
8.1 创建索引
例如对表employees的country字段建立索引:
create index employees_index on table employees(country)
as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
with deferred rebuild
idxproperties('creator'='me', 'created_at'='some_time') in table employees_index_table
partitioned by (country,name) comment 'Employees indexed by country and name.';
employees_index表示索引名称,as...语句指定了索引处理器,也就是一个实现了索引接口的类,也可以使用其他的类(Hive内置的其他实现类、第三方实现类或者是自定义实现类),with deferred rebuild表示重建索引,这样新建的索引将呈现空白状态。in table...指定了一张新表,用来存储该索引数据。

8.2 Bitmap索引
bitmap索引应用于排重后值较少的列,如性别、年级等。

9、模式设计
9.1 按天划分的表
每天一张表的方式在数据库领域用来应对数据集增长很快的情况,通常会在表名中加入一个时间戳,比如upply_2011_01_01、upply_2011_01_02等等。对于hive,这种情况应该使用分区表,为每一天创建一个对应的分区。
create table supply(id int, part string, quantity int) partitioned by (int day);
alter table supply add partition (day=20110102);
alter table supply add partition (day=20110103);
alter table supply add partition (day=20110104);
9.2 分区创建策略
一个理想的分区方案不应该导致产生太多的分区和文件夹目录,并且每个目录下的文件夹应该足够的大,应该是文件系统HDFS中块大小的若干倍。
9.3 同一份数据多种处理
hive提供了一个独特的语法,它可以从一个数据源产生多个数据聚合,而无需每次聚合都要重新扫描一次。例如,下面2个查询都会从源表history表读取数据,然后导入到2个不同的表中:
insert overwrite table sales
select * from history where action='purchased';
insert overwrite table credits
select * from history where action='returned';
上面的方式效率低下,下面这个查询可以达到同样的目的,却只需要扫描history表一次就可以:
from history
insert overwrite sales select * where action='purchased'
insert overwrite credits select * where action='returned';
9.4 分桶表存储数据
分桶是根据某一列的值把数据分成指定个数的文件进行存储,列值相同或者列值的hash值相同的记录会被存储到同一个文件。
分桶可以用于数据取样,同时当查询条件是分桶字段的话,也可以提高查询效率。
9.5 使用列存储表
hive通常使用行式存储,但是也提供了混合列式存储。下面两种表适合采用列式存储:
(1)某些列的值会有很多重复的值,比如包含性别、年龄、状态等属性的表。
(2)表含有非常多的字段。
9.6 使用压缩
压缩都可以使磁盘上存储的数据量变小,这样可以通过降低I/O来提高查询执行速度。压缩和解压缩会消耗CPU资源,但是MapReduce任务通常是I/O密集型,所以几乎在所有场景下都要使用压缩。除了CPU密集型的场景,例如一些机器学习算法等。

10、调优
10.1 explain [extended]
使用explain关键字可以显示sql的执行计划,explain extended可以显示出更多的信息。
10.2 limit限制调整
一般情况下,Limit语句还是需要执行整个查询语句,然后再返回部分结果。这种情况通常是浪费的,应该尽可能的避免出现这种情况。
有一个配置属性可以开启,避免这种情况---对数据源进行抽样
hive.limit.optimize.enable=true --- 开启对数据源进行采样的功能
hive.limit.row.max.size --- 设置最小的采样容量
hive.limit.optimize.limit.file --- 设置最大的采样样本数
缺点:有可能部分数据永远不会被处理到。
10.3 本地模式
有时hive的输入数据量是非常小的。在这种情况下,为触发其他机器执行任务的时间消耗可能会比实际job的执行时间要多的多。对于大多数这种情况,hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间会明显被缩短
set hive.exec.mode.local.auto=true;
当一个job满足如下条件才能真正使用本地模式:
   1.job的输入数据大小必须小于参数:hive.exec.mode.local.auto.inputbytes.max(默认128MB)
   2.job的map数必须小于参数:hive.exec.mode.local.auto.tasks.max(默认4)
   3.job的reduce数必须为0或者1
可用参数hive.mapred.local.mem(默认0)控制child jvm使用的最大内存数。
10.4 并行执行
hive会将一个查询转化为一个或多个阶段,包括:MapReduce阶段、抽样阶段、合并阶段、limit阶段等。默认情况下,一次只执行一个阶段。 不过,如果某些阶段不是互相依赖,是可以并行执行的。
set hive.exec.parallel=true,可以开启并发执行。
set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。
会比较耗系统资源。
10.5 严格模式
Hive提供了一个严格模式,可以防止用户执行那些可能产生意想不到的不好的影响的查询。
通过设置hive.mapred.mode为strict来开启。
使用严格模式可以禁止3种类型的查询:
(1)对于分区表,不加分区字段过滤条件,不能执行
(2)对于order by语句,必须使用limit语句。
(3)限制笛卡尔积的查询(join的时候不使用on,而使用where的)。
10.6 调整mapper和reducer数量
10.7 JVM重用
JVM启动过程比较慢,默认情况下,hadoop是通过为每一个map和reduce任务启动一个JVM实例来运行,当小文件比较多或者Task特别多的场景,任务的执行比较短,大量的时间消耗在JVM启动上。通过mapred.job.reuse.jvm.num.tasks配置,可以设置JVM实例在同一个job中重新使用的次数。这个功能的一个缺点是,开启JVM重用将会一直占用使用到的task插槽,直到整个任务执行结束。
10.8 索引
添加适当的索引来加快查询速度。
10.9 动态分区调整
(1)将动态分区模式设置为严格模式,必须保证至少有一个分区是静态的。通过设置hive.exec.dynamic.partition.mode为strict。
(2)限制单表可以创建的最大分区数。hive.exec.max.dynamic.partitions。
12、函数
12.1 内置函数
12.1.1 标准函数
以一行数据中的一列或多列数据作为参数然后返回结果是一个值的函数,大多数函数都是属于这类的,比如round()、floor()这些数学函数。
12.1.2 聚合函数
聚合函数接受从零行到多行的零个到多个列,然后返回单一值。例如sum()、avg()、min()、max()等。
12.1.3 表生成函数
表生成函数接受零个或多个输入,然后产生多列或多行输出,例如explode()函数以array类型数据作为输入,然后对数组中的数据进行迭代,返回多行结果,一行一个数组元素值。
12.1.4 自定义函数
分别提供了三种接口对应标准函数、聚合函数、表生成函数,需要实现对应接口,实现接口的方法。

13、Streaming
自定义函数需要开发人员编写java代码,对于不熟悉java的开发人员,hive提供了streaming的方式来完成同样的事情。streaming就是在hiveQL中允许使用系统的脚本来对数据进行处理。
例如,使用Linux系统中的命令cat来查询表:
select transform(e.name, e.salary) using '/bin/cat' as name, salary from employee e;
同时还允许运行用户自定义的脚本。

14、文件格式、记录格式和文件压缩
14.1 文件格式
Hive内置了三种文件格式:文本文件、SequenceFile、RCfile。当从表中读取数据时,Hive会使用到InputFormat,向表中写入数据时,会使用OutputFormat。在create table...建表时,通过stored as...来指定文件格式。
14.1.1 文本文件
文本文件格式是默认存储格式,等价于在创建表时通过 stored as textfile语句指定使用文本存储格式。对应的InputFormat是TextInputFormat,OutputFormat是HiveIgnoreKeyTextOutputFormat。
14.1.2 SequenceFile
SequenceFile是hadoop本身就支持的一种标准文件格式,在定义表结构时通过stored as sequencefile语句指定。对应的InputFormat是SequenceFileInputFormat,OutputFormat是HiveSequenceFileOutputFormat。
14.1.3 RCfile
采用列式存储。一张表有成百上千字段,而大多数的查询只需要使用到其中的一小部分字段,这时候该表就适合采用RCfile进行存储。对应的InputFormat是RCFileInputFormat,OutputFormat是RCFileOutputFormat。
14.1.4 自定义文件格式
可以通过实现InputFormat和OutFormat来自定义文件格式。在定义表结构时,可以指定InputFormat和OutFormat,例如:
create table colunmTable(key int, value int)
row format serde
'org.apache.hive.serde2.columnar.ColumnarSerde'
stored as
inputformat 'org.apache.hadoop.hive.ql.io.RCFileInputFormat'
outputformat 'org.apache.hadoop.hive.ql.io.RCFileOutputFormat'
14.2 记录格式
14.2.1 SerDe
SerDe是序列化/反序列化的接口,在内部,Hive引擎使用定义的InputFormat来读取一行数据记录,这行记录之后会被传递给SerDe.deserialize()方法来处理,SerDe决定了一行记录如何被解析。Hive内置了几个SerDe,比如处理正则表达式RegexSerDe,CSV文件CSVSerDe。
14.2.2 JSON SerDe
JsonSerde来自于第三方,可以用于查询json格式的记录。例如:
create external table messages (
msg_id bigint,
tstamp string,
text string,
user_id bigint,
user_name, string
)
row format serde "org.apache.hadoop.hive.contrib.serde2.JsonSerde"
with serdeproperties (
"msg_id"="$.id",
"tstamp"="$.created_at",
"text"="$.text",
"user_id"="$.user.id",
"user_name"="$.user.name"
)
location '/data/messages';
row format serde用于指定使用的SerDe,with serdeproperties用于给SerDe传递属性信息,上面的例子中用这些属性将json文档和表的字段对应起来。定义好之后,就可以像通常一样执行查询:select * from messages;
14.3 文件压缩
压缩可以节省磁盘存储空间,减小磁盘和网络I/O时间。Hive表的文件存储在hadoop上,可以使用hadoop提供的压缩对文件进行压缩。除此以外,hive也提供了两个跟压缩相关的特有设置:
(1)开启中间压缩 hive.exec.compress.intermediate
对中间数据进行压缩可以减少job中map和reduce task间的数据传输量
(2)最终输出结果压缩 hive.exec.compress.output和mapred.output.compression.codec

15、存储处理程序和NoSQL
存储处理程序可以将外部实体表作为标准的hive表进行处理,它包含了InputFormat、OutputFormat、SerDe和Hive需要使用的特定的代码。例如可以将Hbase、Cassandra、DynamoDB这样的NoSQL数据库中的表作为hive表来处理,下面是创建一个指向Hbase表的Hive表:
create table habase_stocks(key int, name string, price float)
stored by 'org.apache.hive.hbase.HBaseStorageHandler'
with serdeproperties("hbase.columns.mapping"=":key,stock:val")
tblproperties("hbase.table.name"="stocks");

16、权限
默认情况下,授权模块是不开启的,需要将属性hive.security.authorization.enabled设置为true。
16.1 用户、组和角色
hive中的用户和组是外部系统的用户和组,比如当使用HiveCLI方式来访问hive时,此时的用户和组就对应linux系统当前用户和组。角色是hive自己创建的,它的使用比较灵活。可以为一个角色赋予权限,然后给用户设置该角色,这样用户就拥有了该角色所拥有的权限。
16.2 权限种类
下面列举了可以配置的权限:

名称 描述 all 所有的权限
alter 修改表结构的权限
create 创建表的权限
drop 删除表或表中的分区的权限
index 创建表索引的权限
lock 开启并发后,锁定和解锁表的权限
select 查询表或者分区中数据的权限
show_database
update
查看所有数据库的权限
向表或者分区中插入或加载数据的权限
例如为用户edward赋予在数据库edsstuff中create权限:
grant create on database edsstuff to user edward;
16.3 分区级别的授权
默认情况下,是在表级别授予权限的,但是可以在分区级别进行授权,将表属性partition_level_privilege设置为true即可。如下面的例子:
create table autorized_part (key int, value string) partitioned by (ds string); //创建一张分区表autorized_part
alter table autorized_part set tblproperties("partition_level_privilege"="true");//为该表开启分区级别的授权
alter table autorized_part add partition (ds='3'); //为表新增一个分区,值为3
revoke select on table autorized_part partition(ds='3') from user edward; //给edward赋予分区ds='3'的select 权限

17、锁
hive不支持行级别的更新和删除,也不支持事务,因此细粒度锁对hive是没有必要的。hive提供了表级别和分区级别的锁,这需要配合zookeeper来使用。
在hive-site.xml配置文件中,增加hive.zookeeper.quorum属性来指定zookeeper集群的地址,同时设置hive.support.concurrency为true,开启支持并发。
show locks; //查询当前所有锁
show locks 表名; //查询某张表上的锁
show locks 表名 partition (...); //查询某个分区上的锁
17.1 锁的种类
hive中的锁分为两种:共享锁和独占锁。共享锁和共享锁之间不互斥,通常在读取的时候使用共享锁,独占锁通常在写入的时候使用,它会使其他用户无法访问锁定表或分区。
大数据
2018-08-19 09:16:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
准备工作已经完成,接下来我们就要正式的开始在我们服务器集群上搭建CDH
附上:
喵了个咪的博客: w-blog.cn
cloudera官网: https://www.cloudera.com/
官方文档地址: https://www.cloudera.com/documentation/enterprise/latest.html
一 , 安装MYSQL
无论是Hadoop相关组件还是cm本身都需要使用到数据库,cm默认会使用内嵌数据库,但是这种方式并不推荐在生产环节使用
(阿里云RDS是无法支持create table xxx select *from xxx的操作不能吧CM数据库放到) 在生产环境尽量使用外部数据库,不要使用CM自带数据库
这里使用oneinstack进行安装可以去官网选择你要的组件一条命令搞定 wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --db_option 2 --dbinstallmethod 1 --dbrootpwd Sunmi388
其他服务器上都可以跑一下空的安装指令进行软件更新和基础依赖的安装(全部N即可) wget http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh PS:如果大家没有使用oneinstack那么需要自主安装ntp来保证服务器直接的时间的一致性
二, JDK安装
卸载系统自带JDK rpm -qa |grep java #如果有就卸载。没有就不用执行下面 yum remove java* #删除自带的java
在CM上解压SDK配置环境变量 cd /app/install tar -zxvf jdk-8u101-linux-x64.tar.gz mv jdk1.8.0_101/ /usr/local/jdk1.8 # 拷贝到其他节点 scp -r /usr/local/jdk1.8 master-1:/usr/local/ scp -r /usr/local/jdk1.8 master-2:/usr/local/ scp -r /usr/local/jdk1.8 slave-1:/usr/local/ scp -r /usr/local/jdk1.8 slave-2:/usr/local/ scp -r /usr/local/jdk1.8 slave-3:/usr/local/
所有节点都进行环境变量配置 vim /etc/profile # java export JAVA_HOME=/usr/local/jdk1.8 export CLASSPATH=.:$CLASSPTAH:$JAVA_HOME/lib export PATH=$PATH:$JAVA_HOME/bin source /etc/profile
查看JAVA安装是否成功: [root@cm install]# java -version java version "1.8.0_101" Java(TM) SE Runtime Environment (build 1.8.0_101-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)
三, CM安装
安装基本包
每台服务器上安装CM所需要的第三方依赖包 yum -y install chkconfig python bind-utils psmisc libxslt zlib sqlite cyrus-sasl-plain cyrus-sasl-gssapi fuse portmap fuse-libs redhat-lsb
在cm服务器上解压CM mkdir -p /usr/local/cloudera-manager tar zxf /app/install/cloudera-manager-centos7-cm5.15.0_x86_64.tar.gz -C /usr/local/cloudera-manager/
修改CM的配置文件,agent从节点配置文件指定CM的主节点server的通讯地址 vim /usr/local/cloudera-manager/cm-5.15.0/etc/cloudera-scm-agent/config.ini [General] # Hostname of the CM server. server_host=cm
将CM的安装目录拷贝给集群的其他节点 scp -r /usr/local/cloudera-manager/ master-1:/usr/local/ scp -r /usr/local/cloudera-manager/ master-2:/usr/local/ scp -r /usr/local/cloudera-manager/ slave-1:/usr/local/ scp -r /usr/local/cloudera-manager/ slave-2:/usr/local/ scp -r /usr/local/cloudera-manager/ slave-3:/usr/local/
初始化数据库
配置CM访问mysql的权限并初始化在mysql中的状态 mysql -u root -p mysql> grant all privileges on *.* to 'root'@'%' identified by 'Sunmi388' with grant option; mysql> flush privileges;
CM要使用mysql作为数据源的话需要对应的驱动包(最易每个节点都需要增加这个JAR包) mkdir /usr/share/java/ cd /usr/share/java/ wget http://pic.w-blog.cn/mysql-connector-java.jar /usr/local/cloudera-manager/cm-5.15.0/share/cmf/schema/scm_prepare_database.sh mysql -h cm -uroot -pSunmi388 --scm-host % scm scm scm --force
配置CDH源parcel包
在cm上执行 mkdir -p /opt/cloudera/parcel-repo
在全部节点执行 mkdir -p /opt/cloudera/parcel
将parcel包文件移动到cm节点的parcel-repo目录下 cp /app/install/CDH-5.15.0-1.cdh5.15.0.p0.21-el7.parcel* /opt/cloudera/parcel-repo
修改校验码文件的后缀 mv /opt/cloudera/parcel-repo/CDH-5.15.0-1.cdh5.15.0.p0.21-el7.parcel.sha1 /opt/cloudera/parcel-repo/CDH-5.15.0-1.cdh5.15.0.p0.21-el7.parcel.sha
启动CM
cm执行: /usr/local/cloudera-manager/cm-5.15.0/etc/init.d/cloudera-scm-server start
查看cm是否启动
默认web页面会在cm服务器上开发7180端口 [root@cm init.d]# netstat -nltp|grep 7180 tcp 0 0 0.0.0.0:7180 0.0.0.0:* LISTEN 7333/java
等CM启动完成之后才在所有节点执行(不然agent会挂掉): /usr/local/cloudera-manager/cm-5.15.0/etc/init.d/cloudera-scm-agent start # 查看agent是否启动成功,如果未启动成功需要再次启动 ps -ef | grep agent
访问CM的web⻚⾯ http://xxxxxxxxx.com:7180(由于CM Server的启动需要花点时间,这⾥可能要等待⼀会才能访问),默认的⽤户名和密码均为admin
接受条约
选择版本
我们可以看到CDH中的软件列表
到这里cm-service的安装工作就已经算结束了
大数据
2018-08-18 23:55:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
生成日期维表和数据当然会想到要用存储过程procedure ,但hive还不支持,所以通用的方法就是在mysql或oracle里生成好在导入hive,或者需要手动集成HPL/SQL –Procedural SQL on hadoop,下为集成方法:
1. 什么是hpsql
目前版本的hive中没有提供类似存储过程的功能,使用Hive做数据开发时候,一般是将一段一段的HQL语句封装在Shell或者其他脚本中,然后以命令行
的方式调用,完成一个业务或者一张报表的统计分析。好消息是,现在已经有了Hive存储过程的解决方案(HPL/SQL –Procedural SQL on hadoop),并
且在未来的Hive的版本(2.0)中,会将该模块集成进来。该解决方案不仅支持Hive,还支持在SparkSQL,其他NoSQL,甚至是RDBMS中使用类似于
Oracle PL/SQL的功能,这将极大的方便数据开发者的工作,Hive中很多之前比较难实现的功能,现在可以很方便的实现,比如自定义变量、基于一个结果集的游标、循环等等。

2. 安装配置hpsql
2.1 下载软件
可以从官网 http://www.hplsql.org/download 下载最新版本安装包,并解压

也可以从我的云盘下载 链接是: https://pan.baidu.com/s/1i5mTBEH 密码是:xbf
2.2 安装配置hpsql
mkdir /opt/hpsql
tar -zxf hplsql-0.3.17.tar.gz -C /opt/hpsql
2.2.1 进入hplsql安装目录,配置 HADOOP_CLASSPATH
vi hplsql
2.2.2 进入hive安装目录,配置和启动Hive的thrift服务HiveServer2
启动HiveServer2:
nohup hive --service hiveserver2 > hiveserver2.log 2>&1 &

2.2.3 配置HPL/SQL与Hive的连接
vi hplsql-site.xml
2.3 使用hplsql执行HPL/SQL语句
2.3.1 使用-e 命令在命令行窗口直接运行

2.3.2 使用-f 命令运行脚本
创建测试表people
创建测试脚本
执行语句
2.3.3 存储过程调用
第一步,按如下格式创建存储过程
use database;
create procedure
begin
......
end;
第二步,按如下方式调用存储过程
include path/sp name
call sp name;

示例如下:

此处省略逻辑部分......
创建完成以后,调用运行,查看执行结果
在来看下通用的mysql生成法:
先创建表:
CREATE TABLE `dim_date` (
`date_id` bigint(8) DEFAULT NULL,
`date` date DEFAULT NULL,
`date_cn` varchar(20) DEFAULT NULL,
`WEEK_CN` varchar(20) DEFAULT NULL,
`WEEK_OF_YEAR_CN` varchar(20) DEFAULT NULL,
`MONTH` varchar(20) DEFAULT NULL,
`MONTH_CN` varchar(20) DEFAULT NULL,
`QUARTER` varchar(20) DEFAULT NULL,
`QUARTER_CN` varchar(20) DEFAULT NULL,
`YEAR_CN` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
二,创建存储过程并执行
create procedure p_dim_date(in start_date VARCHAR(20),in date_count int)
begin
declare i int;
set i=0;
DELETE from dim_date;
while i INSERT into dim_date
(date_id,date,date_cn,WEEK_CN,WEEK_OF_YEAR_CN,MONTH,MONTH_CN,QUARTER,QUARTER_CN,YEAR_CN)
SELECT
REPLACE(start_date,'-','') date_id,
DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y-%m-%d') date,
DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y年%m月%d日') date_cn,
case dayofweek(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s')) when 1 then '星期日' when 2 then '星期一' when 3 then '星期二' when 4 then '星期三' when 5 then '星期四' when 6 then '星期五' when 7 then '星期六' end WEEK_CN,
DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y年第%u周') WEEK_OF_YEAR_CN,
DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y-%m') MONTH,
DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y年第%m月') MONTH_CN,
CONCAT(DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y'),'Q',quarter(STR_TO_DATE( start_date,'%Y-%m-%d %H:%i:%s'))) QUARTER,
CONCAT(DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y'),'年第',quarter(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s')),'季度') QUARTER_CN,
DATE_FORMAT(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),'%Y年') YEAR_CN
from dual;
set i=i+1;
set start_date = DATE_FORMAT(date_add(STR_TO_DATE(start_date,'%Y-%m-%d %H:%i:%s'),interval 1 day),'%Y-%m-%d');
end while;
end;
call p_dim_date('2018-01-01',365)
效果图:
三,sqoop 导入数仓 import --connect jdbc:mysql://172.16.5.100:3306/dw_test --username testuser --password ******** --table dim_date -m 1 --hive-import --hive-database default --hive-table dim_date --fields-terminated-by "\t" --lines-terminated-by "\n" --optionally-enclosed-by '\"' --null-string '\\N' --null-non-string '\\N' --as-parquetfile --create-hive-table --hive-overwrite --target-dir /user/hive/warehouse/dim_date
大数据
2018-08-17 11:40:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
之前几周的时间一直是在围绕DKhadoop的运行环境搭建写分享,有一些朋友留言索要了dkhadoop安装包,不知道有没有去下载安装一探究竟。关于DKHadoop下载安装基本已经讲清楚了,这几天有点空闲把大快DKM大数据运维管理平台的内容整理了一些,作为DKHadoop相配套的管理平台,是有必要对DKM有所了解的。
DKM 是DKHadoop管理平台。作为大数据平台端到端Apache Hadoop 的管理应用,DKM 对 DKH 的每个部件都提供了细粒度的可视化和控制。通过DKM ,运维人员是可以提高集群的性能,提升服务质量,提高合规性并降低管理成本。
DKM 设计的目的是为了使得对于企业数据中心的管理变得简单和直观。通过DKM ,可以方便地部署,并且集中式的操作完整的大数据软件栈。该应用软件会自动化安装过程,从而减少了部署集群的时间。通过DKM 可以提供一个集群范围内的节点实时运行状态视图。同时,还提供了一个中央控制台,可以用于配置集群。总结DKM 能够提供的功能主要有以下几点:
1.自动化Hadoop 安装过程,大幅缩短部署时间;
2.提供实时的集群概况,例如节点,服务的运行状况;
3.提供了集中的中央控制台对集群的配置进行更改;
4.包含全面的报告和诊断工具,帮助优化性能和利用率;
基本功能:DKM的基本功能主要可以分为四大模块:管理功能,监控功能,诊断功能和集成功能。本篇我们就先来看以下管理功能:
1、批量部署
我们都知道Hadoop 本身是一个分布式的系统,因此在安装时,需要对每一个节点进行组件的安装,并且由于是开源软件,其安装过程相对比较复杂,Hadoop 每个组件都需要做很多的配置工作,这一点相信各位深有体会。DKH 提供了DKM 来自动化安装部署Hadoop 。 大大缩短了Hadoop 的安装时间,同时也简化了安装Hadoop 的过程。(DKHADOOP安装步骤请参考此前分享的文章)
自动化安装的过程如下:
1.安装环境准备,下载DKM 以及DKH 的安装文件,安装JDK,yum 等基本软件。
2.挑选一台节点,安装DKM ,用户只需要启动安装脚本即可,通常情况下几分钟就能够完成。
3.DKM 是一个web 应用,提供了基于浏览器的界面,用户可以通过浏览器可视化的进行DKH的安装部署。
4.通过DKM 界面,添加其他需要的安装的节点,选择要安装的Hadoop 组件,以及每个节点承担的角色,选择安装,DKM 会自动地将需要安装的软件分发到对应的节点,并完成安装。
5.当所有节点的软件都安装完成之后,DKM 会启动所有的服务。从上述的安装过程可以看出DKH 的安装主要体现两个特点,批量化以及自动化。只需要在其中一个节点完成,其他节点都可以进行批量化的自动安装。
2、集群配置
(1)可视化参数配置界面
Hadoop 包含许多的组件,不同的组件都包含各种各样的配置, 并且分布于不同的主机之上。 DKM 针对这种情况提供了界面化的参数配置功能,并且能够自动的部署到每个节点。
(2)高可靠配置
DKM 对关键的组件使用HA部署方案,避免单点失效的发生,同时DKH 对于组件的异常错误提供了自动恢复处理,最大限度的保证服务的可靠性。
(3)HDFS 高可靠
在标准配置中,NameNode 是HDFS群集中的单点故障(SPOF)。每个群集都具有一个NameNode ,如果机器或进程变为不可用,群集整体将变为不可用,直到NameNode 在新主机上重新启动或上线。Secondary NameNode 不提供故障转移功能。 为了让“备用” NameNode 的状态与“活动”NameNode 在此实施中保持同步,两个节点均与一组名为JournalNode 的独立后台程序进行通信。由“活动”NameNode 执行任何Namespace 修改时,它会持续记录其中大部分JournalNode 的修改记录。 “备用”NameNode 能够从JournalNode 读取编辑操作,并不断监视它们以了解编辑日志发生的更改。当备用节点发现编辑操作时,它会将这些编辑应用于自己的Namespace 。在发生故障转移时,备用节点将确保首先从JournalNode 读取所有的编辑操作,然后才会将自己升级为“活动状态”。这确保了再发生故障转移之前完全同步Namespace 状态。
为了提供快速故障转移,备用NameNode 还需要拥有有关群集中的块位置的最新信息。为实现这一目的,DataNode 配置了这两个NameNode的位置,它们会将这块位置信息和检测信号发送给这两个NameNode。
一次只能有其中一个NameNode 处于活动状态,这一点对于HA群集的正常运行来说至关重要。否则,Namespace 状态会在两者之间快速出现分歧,从而导致数据丢失风险或其他不正确的结果。为了确保此属性并防止所谓的“大脑分裂状况”,JournalNode 一次只允许一个NameNode 成为写入程序。在故障转移过程中,要进入“活动”状态的NameNode 将接管JournalNode的写入角色,这会有效地阻止其它NameNode继续保持“活动”状态,使得新的“活动”NameNode可以安全地继续执行故障转移。
DKH 默认开启了HA . 用户不用担心此问题。
(4)YARN 高可靠
YARN ResourceManager(RM) 负责跟踪群集中的资源并安排应用程序(例如,MapReduce作业)。RM 高可用性(HA)功能以活动/待机 RM 对形式添加冗余,以删除此单点故障。此外,在从待机RM 到活动RM 进行故障转移时,应用程序可以从其上次检查点状态恢复; 例如,在MapReduce 作业中完成的map 任务不在后续的尝试中重新运行。这样可以在不对运行中的应用程序产生任何重要性能影响的情况下,处理以下事件:
计划外事件,如计算机崩溃。
计划内维护事件,如在运行ResourceManager的计算机上进行的软件或硬件升级。
RM HA 要求Zookeeper 和HDFS 服务处于运行状态。RM HA 通过活动-待机RM 对的方式实施。启动时,每个RM 处于待机状态;启动过程,但未加载状态。转换到活动状态时,RM会从指定的状态存储加载内部状态,并启动所有内部服务。 管理员(通过CLI)或通过集成的故障转移控制器(启用自动故障转移时)可促进转换为活动状态。
DKH 默认开启了Resource Manager HA 。用户不需要担心。
3、权限管理
对系统管理员,数据库管理员及其他管理员必须授予不同级别的管理权限。
大数据
2018-08-17 11:14:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
这里探讨使用Let's Encrypt实现Kubernetes Ingress中自动创建、管理和部署证书,实现HTTPS支持。 编译来源, https://akomljen.com/get-automatic-https-with-lets-encrypt-and-kubernetes-ingress
HTTPS是什么? HTTPS是加密的http协议,提供数据通道加密和服务器验证功能。 使用支持https的浏览器上网,数据传输是加密的、而且可以防止中间被篡改; 对服务器需要进行验证,如果是假冒服务器浏览器会告警并拒绝与之连接,从而保护用户免于上当受骗。 不过,仅仅一个协议,也不是万能的。 比如浏览器如果就是被篡改的版本,完全可能将网站资源指向错误的路标; 证书依赖第三方机构认证,已经出现过假冒证书的情况,自签名证书也难以提供真正的安全; 部分浏览器或定制程序可以越过证书验证直接访问资源(不建议使用)。 需要指出的是,在隐私保护方面,https不支持IP地址隐藏、也不支持域名加密。
在Kubernetes中使用HTTPS
在Kubernetes集群中使用HTTPS协议发布服务,需要一个证书管理器、一个证书自动签发服务,主要通过Ingress来发布https服务,因此需要Ingress Controller并进行配置,启用https及其路由。
在Kubernetes中使用HTTPS的支持软件架构组成如下:
几天以前,读到 Troy Hunt写的关于HTTPS的文章,标题是 " HTTPS is easy "( https://my.oschina.net/u/2306127/blog/1929249 )。 HTTPS 并不难,尤其是在 Kubernetes 这样的平台上。不幸的是,不是所有的人都同意这一观点。我理解对于大型机构来说,把所有的流量都转化到HTTPS上是非常困难的事情。但你可以将HTTPS用于所有的外部流量,通过 Kubernetes ingress 和 Let's Encrypt 实现外部服务端点的自动化。意味着,只要你愿意,可以直接 "切换到 HTTPS"。所提供的插件可以处理需要做的一切。
预先要求
为了在Kubernetes中自动化HTTPS,需要先部署 ingress controller。 什么是 ingress呢? 通过ingress(中文译:入口)在 Kubernetes中的使用, 可以控制外部流量的路由。Ingress controller 与 Kubernetes API 实现了集成,但其服务需要安装相应的引擎(目前有Nginx和Traefic两种)。
要求的软件: Ingress controller,在 Kubernetes上部署。 自动化的 DNS(域名服务)。
我写过一些关于ingress controller的文章。如何满足这些需求,可以参考: AWS Cost Savings by Utilizing Kubernetes Ingress with Classic ELB 。
部署到一起
管理 SSL/TLS 证书的组件是 Cert manager 。它对于每一个ingress endpoint将会自动创建一个新的证书。当 certificates 过期时还能自动更新。Cert manager 也可以和其它的providers一起工作,例如 HashiCorp Vault 。在我的与Kubernetes相关的文章中,我使用 Helm来部署,主要是为了方便,但在生产环境下,我并不建议如此。参见 read my blog post about Helm 。
你需要配置一个缺缺省的 cluster issuer ,当部署Cert manager的时候,用于支持 kubernetes.io/tls-acme: "true" annotation来自动化TLS: ingressShim.defaultIssuerName=letsencrypt-prod ingressShim.defaultIssuerKind=ClusterIssuer
部署证书管理器
你将在后面定义 letsencrypt-prod cluster issuer。先来部署 Cert manager: ⚡ helm install --name cert-manager \ --namespace ingress \ --set ingressShim.defaultIssuerName=letsencrypt-prod \ --set ingressShim.defaultIssuerKind=ClusterIssuer \ stable/cert-manager ⚡ kubectl get pod -n ingress --selector=app=cert-manager NAME READY STATUS RESTARTS AGE cert-manager-cert-manager-7797579f9-m4dbc 1/1 Running 0 1m
当安装 Cert manager 提供的 Kubernetes custom resources : ⚡ kubectl get crd NAME AGE certificates.certmanager.k8s.io 1m clusterissuers.certmanager.k8s.io 1m issuers.certmanager.k8s.io 1m
创建证书签发服务
最后一步,定义集群范围内的 issuer letsencrypt-prod ,在上面的步骤中我们已经设置了。使用自定义资源来定义cluster issuer clusterissuers.certmanager.k8s.io : ⚡ cat << EOF| kubectl create -n ingress -f - apiVersion: certmanager.k8s.io/v1alpha1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: me@example.com privateKeySecretRef: name: letsencrypt-prod http01: {} EOF
注意: 使用有效的 email 地址!
创建一个服务进行测试
现在测试一下。部署一个新的 Ghost blog 到集群上,将通过 ghost.test.akomljen.com 域名访问,缺省使用了 HTTPS 。使用Helm来安装: ⚡ cat > values.yaml <注意: 这里有一个 a Helm issue , boolean 值无法作为 string 被正确滴解析。这就是为什么我要使用文件而不是 --set 和 --set-string 参数来更新缺省值的原因。
几分钟后,你可以使用定义的endpoint打开网页,HTTPS缺省支持!
总结
很容易,对吧?我们很幸运有像 Troy Hunt 这样的专家来促进安全的网络机制,使大家能够更容易地实施。同时,云原生的技术帮助我们自动这些事情。
大数据
2018-08-16 22:17:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
HTTPS is easy https://www.troyhunt.com/https-is-easy/
HTTPS is easy! In fact, it's so easy I decided to create 4 short videos around 5 minutes each to show people how to enable HTTPS on their site and get all traffic redirecting securely, optimise their HTTPS configuration to get it rating higher than most banks, fix any insecure references in a few clicks and finally, secure all the traffic all the way back to their website. I built a little demo site and embedded all the videos in it over at HTTPSIsEasy.com .
Let me begin by being clear about the demographic this is pitched at: I wanted to create a resource that had the broadest possible appeal regardless of technical competency. If someone has entry-level web dev skills and knows enough to get a site up and running but isn't a tech pro, I want this to be usable by them. I want to help take a big chunk out of the massive list of smaller sites that are still served over non-secure connections because the owners simply don't know where to start. I also wanted to keep each video to about 5 minutes so you'll see that there's plenty of stuff I don't embellish on, I just focus on making things work as expeditiously as possible. Having said that, everything in this video series is equally applicable to sites like this very blog and indeed that's pretty much how I have things configured today. If you are a tech pro and you want to go deeper on HTTPS, have a browse back through the dozens of posts on the SSL tag or go and watch 3 and a half hours of Pluralsight training on the subject .
Next, you'll see that this is all very Cloudflare-centric and you may be wondering "why not use Let's Encrypt instead?" I love Let's Encrypt and I love what they've done for the industry in terms of making certs free and automated. But that's only part of the journey to HTTPS and Let's Encrypt doesn't help people redirect to HTTPS, add HSTS, configure the versions of TLS they support or fix HTTP references in otherwise secure pages. All of this is really important for a robust HTTPS implementation and all of it's possible in Cloudflare with mere button clicks. To be honest, the significance of this really only became clear to me when recording these videos just yesterday; Cloudflare makes it so easy not just to get the site served over HTTPS, but to do all the other things you need to do for HTTPS to work properly .
In the final video, I secure the network segment between Cloudflare and the web server by loading one of their origin certificates into Azure. Because I know people will ask, go get yourself OpenSSL then the command I ran is as follows: openssl pkcs12 -export -inkey httpsiseasy.key -in httpsiseasy.pem -name httpsiseasy -out httpsiseasy.pfx
Frankly, I can't see the demographic I've targeted this series at going down this path that often, in part because of the technical complexity (and yes, grabbing OpenSSL and running commands will be a bar too high for many) and also in part because many hosting providers still don't provide the ability to upload your own cert (such as Ghost Pro that this blog runs on). And before anyone loses their minds over the entire network not being encrypted or Cloudflare being able to MitM the traffic, have a read of CloudFlare, SSL and unhealthy security absolutism .
Finally, because some people will inevitably wonder, this isn't a commercial activity on my behalf; Cloudflare didn't engage me to create this and it'll come as a surprise to them the first time they see it. I created this on a whim after some Twitter discussions earlier this week and I simply wanted to create the most easily accessible resource possible for helping people get their websites served over HTTPS. So share this generously, point people who don't know where to start at HTTPSIsEasy.com and help drive a more "secure by default" web.
大数据
2018-08-16 22:13:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
配置Impala以使用ODBC
可以将第三方产品设计为使用ODBC与Impala集成。为获得最佳体验,请确保支持您打算使用的任何第三方产品。验证支持包括检查Impala,ODBC,操作系统和第三方产品的版本是否已获批准同时使用。在配置系统以使用ODBC之前,请下载连接器。在访问下载ODBC连接器所需的页面之前,您可能需要登录并接受许可协议。
继续阅读: 下载ODBC驱动程序 配置ODBC端口 为Impala设置ODBC应用程序的示例 有关JDBC和ODBC与Impala SQL功能交互的说明

下载ODBC驱动程序
重要提示: 截至2015年底,大多数商业智能应用程序都使用2.x ODBC驱动程序进行了认证。虽然此页面上的说明涵盖了2.x和1.x驱动程序,但是对于连接到Impala的大多数ODBC应用程序,只能使用2.x驱动程序。
有关安装说明,请参阅 连接器文档页面 。
下载:https://www.cloudera.com/downloads/connectors/impala/odbc/2-5-43.html
文档:http://www.cloudera.com/documentation/other/connectors/impala-odbc/

一、检查unixODBC是否安装:
rpm -qa|grep unixODBC
假设没有安装。使用以下的命令安装:

yum install unixODBC

yum install unixODBC-devel
使用odbcinst命令查看unixODBC配置文件路径,不同版本号的unixODBC配置文件路径是不同的,假设是源码方式安装unixODBC,也能够通过编译參数--sysconfdir指定。

[root@h1 ~]# odbcinst -j unixODBC 2.2.14 DRIVERS............: /etc/odbcinst.ini SYSTEM DATA SOURCES: /etc/odbc.ini FILE DATA SOURCES..: /etc/ODBCDataSources USER DATA SOURCES..: /root/.odbc.ini SQLULEN Size.......: 8 SQLLEN Size........: 8 SQLSETPOSIROW Size.: 8
二、安装Impala ODBC驱动
yum --nogpgcheck localinstall /opt/src/ClouderaImpalaODBC-2.5.43.1032-1.el7.x86_64.rpm
Marking /opt/src/ClouderaImpalaODBC-2.5.43.1032-1.el7.x86_64.rpm to be installed
Resolving Dependencies
--> Running transaction check
---> Package ClouderaImpalaODBC.x86_64 0:2.5.43.1032-1 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
=====================================================================================
Package Arch Version Repository Size
=====================================================================================
Installing:
ClouderaImpalaODBC
x86_64 2.5.43.1032-1 /ClouderaImpalaODBC-2.5.43.1032-1.el7.x86_64 49 M
Transaction Summary
=====================================================================================
Install 1 Package
Total size: 49 M
Installed size: 49 M
Is this ok [y/d/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : ClouderaImpalaODBC-2.5.43.1032-1.x86_64 1/1
Verifying : ClouderaImpalaODBC-2.5.43.1032-1.x86_64 1/1
Installed:
ClouderaImpalaODBC.x86_64 0:2.5.43.1032-1
Complete!
安装完毕后的文件在:/opt/cloudera/impalaodbc 文件夹,这个文件夹包括了安装文档、lib包、配置文件演示样例。
ll /opt/cloudera/impalaodbc/
total 644
-rwxr-xr-x 1 root root 528661 Apr 25 03:19 Cloudera-ODBC-Driver-for-Impala-Install-Guide.pdf
drwxr-xr-x 3 root root 4096 Aug 16 16:27 ErrorMessages
-rwxr-xr-x 1 root root 12003 Apr 25 03:19 EULA.txt
drwxr-xr-x 3 root root 4096 Aug 16 16:27 lib
-rwxr-xr-x 1 root root 15623 Apr 25 03:19 Release-Notes-Impala-ODBC.txt
drwxr-xr-x 2 root root 4096 Aug 16 16:27 Setup
-rwxr-xr-x 1 root root 83667 Apr 25 03:19 third-party-licenses.txt
问题:cdh5.15 impala2.12 下装impalaODBC-2.5.39报如下错误,提示冲突,换2.5.43即可
rpm -ivh /opt/src/ClouderaImpalaODBC-2.5.39.1020-1.el7.x86_64.rpm
Preparing... ################################# [100%]
file /opt/cloudera from install of ClouderaImpalaODBC-2.5.39.1020-1.x86_64 conflicts(冲突) with file from package cloudera-manager-daemons-5.15.0-1.cm5150.p0.62.el7.x86_64
配置ODBC端口
Cloudera ODBC Connector的2.5和2.0版本(目前已针对某些但不是所有BI应用程序进行了认证)使用HiveServer2协议,对应于Impala端口21050.Impala支持使用所有受支持的驱动程序版本进行Kerberos身份验证,并且需要ODBC 2.05.13用于LDAP用户名/密码身份验证的Impala或更高版本。
Cloudera ODBC Connector的1.x版使用原始的HiveServer1协议,对应于Impala端口21000。
设置驱动的环境变量:
在 /etc/profile 最后加入:
export ODBCINI=/etc/odbc.ini
export ODBCSYSINI=/etc
export CLOUDERAIMPALAODBCINI=/etc/cloudera.impalaodbc.ini
然后运行:source /etc/profile
使改动的脚本马上生效。
拷贝:cloudera.impalaodbc.ini 到 /etc/文件夹:
[root@h1 Setup]#cp /opt/cloudera/impalaodbc/lib/64/cloudera.impalaodbc.ini /etc/ [root@h1 Setup]#
改动:/etc/cloudera.impalaodbc.ini 中的例如以下条目:

# Generic ODBCInstLib # iODBC #ODBCInstLib=libiodbcinst.so # SimbaDM / unixODBC ODBCInstLib=libodbcinst.so
也就是说不使用iODBC , 使用 unixODBC

三、改动/etc/odbc.ini 文件
參照 /opt/cloudera/impalaodbc/Setup/odbc.ini , 在/etc/odbc.ini 加入例如以下的内容:
[impalaodbc] # Description: DSN Description. # This key is not necessary and is only to give a description of the data source. Description=Cloudera ODBC Driver for Impala (64-bit) DSN # Driver: The location where the ODBC driver is installed to. Driver=/opt/cloudera/impalaodbc/lib/64/libclouderaimpalaodbc64.so # The DriverUnicodeEncoding setting is only used for SimbaDM # When set to 1, SimbaDM runs in UTF-16 mode. # When set to 2, SimbaDM runs in UTF-8 mode. #DriverUnicodeEncoding=2 # Values for HOST, PORT, KrbFQDN, and KrbServiceName should be set here. # They can also be specified on the connection string. HOST=172.16.230.152 PORT=21050 Database=default # The authentication mechanism. # 0 - no authentication. # 1 - Kerberos authentication # 2 - Username authentication. # 3 - Username/password authentication. # 4 - Username/password authentication with SSL. AuthMech=0 # Kerberos related settings. KrbFQDN= KrbRealm= KrbServiceName= # Username/password authentication with SSL settings. UID= PWD= CAIssuedCertNamesMismatch=1 TrustedCerts=/opt/cloudera/impalaodbc/lib/64/cacerts.pem # Specify the proxy user ID to use. #DelegationUID= # General settings TSaslTransportBufSize=1000 RowsFetchedPerBlock=1000 SocketTimeout=0 StringColumnLength=32767 UseNativeQuery=0
四、验证安装是否成功
运行 isql -v impalaodbc
[root@h1 ~]# isql -v impalaodbc +---------------------------------------+ | Connected! | | | | sql-statement | | help [tablename] | | quit | | | +---------------------------------------+


大数据
2018-08-16 19:42:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
CDH5.15安装指南
1.集群规划
CDH (Cloudera's Distribution, including Apache Hadoop),是Hadoop众多分支中的一种,由Cloudera维护,基于稳定版本的Apache Hadoop构建,并集成了很多补丁,可直接用于生产环境。
Cloudera Manager则是为了便于在集群中进行Hadoop等大数据处理相关的服务安装和监控管理的组件,对集群中主机、Hadoop、Hive、Spark等服务的安装配置管理做了极大简化。
本文安装选择全离线安装方式,主机6台,系统版本CentOS6.7。具体配置如图所示:



2.环境准备
2.1 配置hosts
(1)在每台机器上修改hostname # 查看当前 host hostname # 临时修改 hostname ,重启后无效 hostname uat2 # 在此处永久修改 vim /etc/sysconfig/network NETWORKING=yes # 修改主机名 HOSTNAME=uat2.hadoop.feidai.com

(2)修改每台机器的hosts文件 vim /etc/hosts # 添加以下主机列表 172.16.100.217 uat1.hadoop.feidai.com uat1 172.16.100.218 uat2.hadoop.feidai.com uat2 172.16.100.219 uat3.hadoop.feidai.com uat3 172.16.100.220 uat4.hadoop.feidai.com uat4 172.16.100.221 uat5.hadoop.feidai.com uat5 172.16.100.222 uat6.hadoop.feidai.com uat6


2.2 关闭防火墙和selinux
在 每台机器 上进行关闭防火墙和禁用SELINUX服务操作 service iptables start # 启动防火墙 service iptables status # 查看防火墙的状态 service iptables stop # 关闭防火墙 chkconfig iptables off # 防止服务器重启开启防火墙 sestatus – v # 查看 selinux 的状态 ## 关闭 selinux vim /etc/selinux/config SELINUX=disabled # SELINUXTYPE= can take one of these two values: # targeted - Targeted processes are protected, # mls - Multi Level Security protection. SELINUXTYPE=targeted


2.3 免密登录配置
在 主节点 上,设置SHH无密码登录。此处选择uat6作为主节点。 # 在主节点上执行 ssh-keygen -t rsa # 一路回车,生成无密码的密钥对。 # 将公钥添加到认证文件中 cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # 并设置 authorized_keys 的访问权限: chmod 600 ~/.ssh/authorized_keys 。 #scp 文件到所有从节点: scp ~/.ssh/authorized_keys root@uat2:~/.ssh/
之后在主节点上用ssh 主机名的方式就能免密登录主机了。


2.4 挂载系统镜像
在 每台机器 上挂载系统镜像并配置在yum源中 # 创建系统镜像的挂载目录 mkdir -pv /mnt/cdrom # 挂载系统镜像 mount -o loop /home/CentOS-6.7-x86_64-bin-DVD1.iso /mnt/cdrom ## 新建系统镜像的 yum 源 vim /etc/yum.repos.d/os.repo # 添加本地 os yum 源 [os.repo] name=os.repo baseurl=file:///mnt/cdrom enabled=1 gpgcheck=0 yum repolist # 配置完后通过 yum 命令检查是否配置成功

yum源列表截图


2.5 安装HTTPD服务
在集群中 选择一台主机 安装HTTPD服务(此处选择UAT2主机),用于之后的Yum源配置以及CM包配置,将下载好的包放在暴露的HTTP资源目录下,通过http请求能下载到包文件。 yum clean all # 清理 yum 的缓存 yum repolist all # 查看已有的 yum 源 yum info httpd # 查看 http 的 yum 源的详细信息 yum install -y httpd #yum 安装 httpd 服务 service httpd start # 启动 httpd 服务 chkconfig --level 2345 httpd on # 添加开机启动服务

*linux apache 默认目录在: /var/www/html
通过访问安装了服务的主机80端口,可以看到下面的内容,表示安装成功


2.6 开启ntpd授时服务
在 每台机器 上安装ntpd服务,保证时间的同步 #yum 源安装 ntp yum install -y ntp # 修改配置文件 vim /etc/ntp.conf server uat2 iburst # 目标服务器网络位置 uat2 #server 1.centos.pool.ntp.org iburst # 注释掉 #server 2.centos.pool.ntp.org iburst # 注释掉 #server 3.centos.pool.ntp.org iburst # 注释掉 systemctl start ntpd.service    # 启动服务 systemctl enable ntpd.service   # 设置为开机启动 systemctl status ntpd.service # 查看运行状态

配置完成后,在每台机器上执行date命令,查看时间是否同步成功。



2.7 配置远程yum 源
在2.5小节安装httpd服务的时候,把httpd服务安装到了uat2上,一方面是为了配置本节中的远程yum源。将下载好的包放到http默认访问目录中,通过yum配置文件指定URL,便达到了远程yum源的功能。
下面将下载好的包放到uat2的相应的目录中去(mysql、cm、cdh)。 /var/www/html/mariadb10.0.14 /var/www/html/cm5150 /var/www/html/cdh5150

然后在 每台机器 上配置好远程yum源的地址,注意httpd服务是安装在uat2中的。Uat2的IP为172.16.100.218 # 配置 mariadb 的 yum 源 vim /etc/yum.repos.d/mariadb.repo # 添加以下内容 [mariadb]" name = http://172.16.100.218/mariadb10.0.14 baseurl = h enabled=1 gpgcheck=0 # 配置 cm 的 yum 源 vim /etc/yum.repos.d/cm.repo # 添加以下内容 [cm] name = Cloudera Manager baseurl = http://172.16.100.218/cm5150 enabled=1 gpgcheck=0 # 配置 cdh 的 yum 源 vim /etc/yum.repos.d/cdh.repo # 添加以下内容 [cdh] name = CDH baseurl = http://172.16.100.218/cdh5150 enabled=1 gpgcheck=0

配置好远程yum源后,在每台机器输入命令yum repolist 查看是否配置成功,在下图中红框的列表上出现了对应的yum源,说明配置成功。
此处yum源的配置主要作用是为了接下来Mysql的安装、cloudera-manager组件的安装,所以必须确保yum源中有相应的安装包。 # 检查是否有相应的包文件 yum info MariaDB-server yum info cloudera-manager-server yum info cloudera-manager-agent yum info cloudera-manager-daemons



2.8 安装mysql并创建相关的库
在上一小节中,配置好了mysql的远程yum源,那么通过yum install命令即可安装mysql服务。
选择 一台机器 作为mysql的服务端,进行服务端的安装,这里选择Uat2作为server # 安装服务端 仅需要在 uat2 上安装 yum install -y MariaDB-server # 其它服务器安装客户端 yum install -y MariaDB-client # 修改服务端配置文件:不区分大小写 以及 utf8 字符集 vim /etc/my.cnf.d/server.cnf [mysqld] lower_case_table_names=1 character_set_server = utf8 # 启动 mysql 服务 service mysql start
启动mysql服务成功后,要设置root账户的密码。 # 第一次可无密登录 mysql -uroot # 执行以下 sql 语句进行初始密码的设置 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'IDENTIFIED BY '123456' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost'IDENTIFIED BY '123456' WITH GRANT OPTION; flush privileges;
创建cdh相关的库 create database hive DEFAULT CHARSET utf8; create database amon DEFAULT CHARSET utf8; create database hue DEFAULT CHARSET utf8; create database oozie default charset utf8; create database activity_monitor default charset utf8; create database reports_manager default charset utf8;


创建相关的用户并赋予库操作权限和外网访问权限 # 创建相关用户 use mysql; insert into user(Host,User,Password) values("%","hive",password("hive")); insert into user(Host,User,Password) values("%","amon",password("amon")); insert into user(Host,User,Password) values("%","hue",password("hue")); insert into user(Host,User,Password) values("%","oozie",password("oozie")); insert into user(Host,User,Password) values("%","activity_monitor",password("activity_monitor")); insert into user(Host,User,Password) values("%","reports_manager",password("reports_manager")); # 赋予权限 GRANT ALL PRIVILEGES ON *.* TO 'cmf'@'%'IDENTIFIED BY '123456' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'cmf'@'localhost'IDENTIFIED BY '123456' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'hive'@'%'IDENTIFIED BY 'hive' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'hive'@'localhost'IDENTIFIED BY 'hive' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'hue'@'%'IDENTIFIED BY 'hue' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'hue'@'localhost'IDENTIFIED BY 'hue' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'amon'@'%'IDENTIFIED BY 'amon' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'amon'@'localhost'IDENTIFIED BY 'amon' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'oozie'@'%'IDENTIFIED BY 'oozie' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'oozie'@'localhost'IDENTIFIED BY 'oozie' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'activity_monitor'@'%'IDENTIFIED BY 'activity_monitor' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'activity_monitor'@'localhost'IDENTIFIED BY 'activity_monitor' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'reports_manager'@'%'IDENTIFIED BY 'reports_manager' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'reports_manager'@'localhost'IDENTIFIED BY 'reports_manager' WITH GRANT OPTION; # 刷新 flush privileges; # 查看用户权限 show grants for hue;



2.10 安装JDK
此处安装jdk1.7版本,先查看本机是否有安装其它版本的jdk,若有,则先卸载。
在每台机器上安装jdk # 查看是否安装有 jdk rpm -qa|grep jdk # 卸载相关 jdk rpm -e --nodeps 上步骤搜索出的包全名 # 安装 jdk1.7 yum install -y oracle-j2sdk1.7


2.11 安装cloudera-manager组件
选择 一台主机 安装server端,此处选择Uat6作为server端
在 全部主机 中安装agent和daemons # 在 uat6 上安装 server 端 yum install -y cloudera-manager-server # 所有主机上安装 agent 和 daemons yum install -y cloudera-manager-agent cloudera-manager-daemons
在安装了server端的机器上(此处是uat6),修改数据库配置文件 # 在安装了 server 的机器上 vim /etc/cloudera-scm-server/db.properties com.cloudera.cmf.db.type=mysql com.cloudera.cmf.db.host=172.16.100.218 com.cloudera.cmf.db.name=cmf com.cloudera.cmf.db.user=cmf com.cloudera.cmf.db.setupType=EXTERNAL com.cloudera.cmf.db.password=123456 # 设置开机自启 chkconfig --level 2345 cloudera-scm-server on
在安装了agent的机器上(每台机器),修改指向的server端host和ip vim /etc/cloudera-scm-agent/config.ini [General] # Hostname of the CM server. server_host=uat6 # Port that the CM server is listening on. server_port=7182 # 设置开机自启 chkconfig --level 2345 cloudera-scm-agent on



在cm server端配置好mysql的连接驱动,并初始化cmf数据库 ln –s /usr/java/mysql-connector-java-5.1.42-bin.jar /usr/share/java/mysql-connector-java.jar # 初始化 CMF 数据库 /usr/share/cmf/schema/scm_prepare_database.sh mysql -h 172.16.100.218 -uroot -p123456 --scm-host 172.16.100.218 cmf cmf 123456 # 启动服务 service cloudera-scm-server start # 在 server 端执行 service cloudera-scm-agent start # 在每台机器上执行 # 查看日志 less /var/log/cloudera-scm-server/cloudera-scm-server.log

启动server和agent成功后,访问 http://uat6:7180 ,进行下一步的CDH配置。


3.CDH安装配置
3.1 集群配置及初始化服务安装
在上一章中,安装好了CM server和CM agent后,即可访问 http://uat6:7180 进入到CM的web管理页面,初始化账户是admin,密码admin。
第一次登陆后,会提示部署哪一个版本,此处选择数据集线器试用版。
勾选安装条款,然后继续
指定主机操作中,在输入框内输入所有主机的host列表,点击搜索。
搜索后会出现所有主机的列表,全选后点击继续
离线安装是使用parcel方式,在第二章的2.5小节中,安装httpd的目的之一在于将parcel包以url的形式暴露出来,在此页面上填写URL后,会自动列出检测出的最新版本的CDH安装包。
填写本地parcel目录和存储库路径,以及远程parcel存储库
选择识别出的版本以及agent暴露的URL地址
此处在第二章环境准备中已经安装好了JDK,所以不勾选。
不勾选单用户模式
输入集群主机的登录密码
等待拷贝与安装


在集群设置中,按需选择安装服务组合,此处勾选自定义服务,自由勾选初始化安装的服务,没有勾选的服务在 cm 安装完成后还可以已添加服务的方式添加进来。
按集群规划分配相应的组件角色



此处的数据库设置中,因为在第二章的2.8小节已经配置好初始化的一些数据库和用户密码,此处仅需填入之前创建的库名,用户名和密码,点击测试连接即可。


集群参数配置,按照规划配置




配置完成后,cm会启动全部配置的组件





3.2 CDH集成Kafka
3.2.1 安装包下载
在CDH官网中关于Kafka的安装和升级中已经说到,在CDH中,Kafka作为一个分布式的parcel,单独出来作为parcel分发安装包。只要我们把分离开的kafka的服务描述jar包和服务parcel包下载了,就可以实现完美集成了。
注意集成之前请阅读官方文档,特别是版本支持方面。
查看kafka与CDH版本对应:
https://www.cloudera.com/documentation/enterprise/release-notes/topics/rn_consolidated_pcm.html#pcm_kafka
我们的CDH是5.15的所以选择3.1的版本。



3.2.1.1 下载Parcel
下载网址: http://archive.cloudera.com/kafka/parcels/latest/
到这个网址下载你需要的 kafka 的 parcel 版本(下载图示红框中的三个文件,并将 .sha1 后缀的文件名改成 .sha )。我们的虚拟机是 Centos6 的,下载对应的版本,其版本对应如下



打开刚刚下载好的 manifest.json 文件, 找到这个版本对应的hash值,将其复制到.sha 文件中去,替换掉原来的hash值。
然后将这三个文件,拷贝到服务器cdh的/opt/cloudera/parcel-repo目录下。如果有相同的文件,即manifest.json,只需将之前的重命名即可。

3.2.1.2 下载CSD
网址: http://archive.cloudera.com/csds/kafka/
上传下载好的CSD包KAFKA-1.2.0.jar,到服务器CDH目录下,路径为/opt/cloudera/csd。



3.2.2 激活并添加服务
选择CM主页 -> Hosts -> parcel -> 检查新parcel -> 配置 -> 激活

激活完安装包后,在添加服务页面进行Kafka服务的添加即可。



在CM的集群监控界面,点击操作中的添加服务操作

选择安装Broker的主机和KM的主机




3.2.3 安装常见问题
3.2.3.1 填写Destination Brokers List
若添加了 Kafka MirrorMaker , 则可填写其所在节点构成的列表 , 若未添加 Kafka MirrorMaker ,可填写任意服务器即可,如下: master:9092;salve1:9092;salve2:9092
3.2.3.2 填写Source Brokers List
填写 Kafka Broker 所在节点构成的列表(用逗号分隔),如下 master:9092;salve1:9092;salve2:9092
3.2.3.3 启动时出现内存溢出错误(java.lang.OutOfMemoryError:Javaheapspace)
解决方法:
主页服务列表 -> kafka -> 配置 -> Kafka-Broker -> Java Heap Size of Broker 修改参数到256以上即可。
3.2.3.4启动 kafka mirrormaker 的时候报错: whitelist must be specified when using new consumer in mirror maker
解决方法:
点击 cm 集群管理页面 --kafka--instances--kafka mirrormaker-- 然后搜索 Whitelist ,然后提示 mirrormaker default group, 把刚才分配的时候设置的添加进去。在分配 kafka 生产环境是怎么分配的,这里就怎么填。
3.3 CDH-HDFS高可用配置
点击CM主页的HDFS服务进入服务监控主页,点击操作按钮,选择下拉列表的启用HA按钮开始配置HA HDFS。
填写nameservice




等待运行完成后。在原HDFS界面的实例列表就可以看到新加的HA组件

3.4 常见问题
3.4.1 cloudemanager 安装时出现 ProtocolError: 问题解决方法
CLOUDEMANAGER安装时出现:
PROTOCOLERROR:
解决办法: # 杀死 supervisord 进程 ps -ef | grep supervisord kill -9 sudo service cloudera-scm-agent restart

大数据
2018-08-16 15:49:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
CDH5.15卸载指南
在删除CDH前,注意要备份好数据。先备份或转移集群中的重要数据,在进行集群的卸载。像一些重要的用户数据,默认的存储路径是在/var/lib/下面,一些组件如HDFS/Impala/Kudu的数据根据安装时的目录来查看。
下面开始卸载CDH。


1. 停止所有的服务
1.1 停止组件服务
打开 Cloudera Manager 控制台
关闭集群:选择集群后点击操作按钮,点击后在弹出的下拉菜单中点击停止,之后静待所有服务都停止完成。(如果有多个集群,每个集群依次操作)操作如下图:

静待服务停止完毕



1.2 停止Cloudera Management Service
点击导航栏的集群按钮,找到 Cloudera Management Service
找到其下的 CM 服务名称右边的倒三角,在弹出的下拉菜单中点击 Stop ,操作如下图:

之后静待服务停止完成。
1.3 关闭并移除 Parcels
集群是通过parcels安装的,通过CM的操作面板将parcels卸载并移除。点击导航栏中的parcel按钮。
选中集群后, 并在右侧面板中找到对应的所有 parcels ,点击停用按钮,在弹出的对话框中选择仅限停用状态。


对所有 parcels 完成了上述操作后,点击按钮右边的倒三角,再点击从主机删除。从主机删除完成后,再次点击倒三角按钮,选择删除操作。




1.4 删除集群
点击到CM的首页,选中集群后,点击操作按钮,选择删除操作。

并删除Cloudera Management Service




2. 卸载 Cloudera Manager 服务
2.1 关闭cm的server和agent服务
在所有Agent节点停止agent服务:service cloudera-scm-agent stop
[root@uat1 ~]# service cloudera-scm-agent stop Stopping cloudera-scm-agent: [ OK ] 在当初安装时的 server 节点停止 server 服务 service cloudera-scm-server stop [root@uat4 nameservice1]# service cloudera-scm-server stop Stopping cloudera-scm-server: [ OK ]


查看相关进程,如果在CM界面中未完成服务的关闭,可以用以下命令来强行关闭相关进程
# 关闭相关进程 ps -ef |grep cloudera #ps -ef |grep cloudera |grep -v grep |awk '{print $2}' |xargs kill for i in hdfs mapred cloudera-scm hbase hue zookeeper oozie hive impala flume; do ps -ef |grep ${i} |grep -v grep |awk '{print $2}'; done ps -ef |grep cmf # 查看相关进程 for u in hdfs mapred cloudera-scm hbase hue zookeeper oozie hive impala flume; do echo $(ps -u $u -o pid=); done #kill 掉相关进程 for u in hdfs mapred cloudera-scm hbase hue zookeeper oozie hive impala flume; do sudo kill $(ps -u $u -o pid=); done


2.2 删除cm相关的软件 # 卸载 cloudera-manager-server yum remove cloudera-manager-daemons cloudera-manager-server -y # 卸载 cloudera-manager-agent yum remove cloudera-manager-agent cloudera-manager-daemons -y # 用匹配方式删除 yum remove 'cloudera-manager-*' # 清除缓存 yum clean all


2.3 删除用户数据
建议在卸载 CDH 前,先备份或转移集群上的用户数据。以下命令应在集群中所有 Agent 主机执行;以下路径是集群的默认安装配置,如果有所修改,请按修改后的路径操作。 # 清理组件相关文件 rm -Rf /var/lib/flume-ng /var/lib/hadoop* /var/lib/hue /var/lib/navigator /var/lib/oozie /var/lib/solr /var/lib/sqoop* /var/lib/zookeeper /var/lib/kudu /var/lib/kafka/ /var/lib/impala/ /var/lib/cloudera-scm-* # 删除数据库配置文件 rm -rf /etc/cloudera* # 卸载掉相关的进程 umount /var/run/cloudera-scm-agent/process # 删除 cloudera 的安装目录 rm -rf /usr/share/cmf /var/lib/cloudera* /var/cache/yum/x86_64/6/cloudera* /var/cache/yum/x86_64/6/cm /var/log/cloudera* /var/run/cloudera* # 删除数据目录 ( 根据安装时的实际目录删除 ) for data in data data1 data2 data3 data4 data5 data6 data7 data8 data9 data10 data11 data12 data13; do rm -rf /${data}/dfs /${data}/impala /${data}/yarn /${data}/kudu; done rm -rf /var/run/hdfs-sockets rm -rf /usr/lib/hue rm -rf /usr/bin/hadoop* /usr/bin/zookeeper* /usr/bin/hbase* /usr/bin/hive* /usr/bin/hdfs /usr/bin/mapred /usr/bin/yarn /usr/bin/sqoop* /usr/bin/oozie /usr/bin/impala /usr/bin/spark* rm -rf /etc/alternatives/hadoop* /etc/alternatives/flume-ng* /etc/alternatives/hbase* /etc/alternatives/hdfs /etc/alternatives/hive* /etc/alternatives/hue* /etc/alternatives/impala* /etc/alternatives/mahout* /etc/alternatives/mapred /etc/alternatives/oozie /etc/alternatives/pig* /etc/alternatives/solr* /etc/alternatives/spark* /etc/alternatives/sqoop* /etc/alternatives/yarn /etc/alternatives/zookeeper* rm -rf /etc/hadoop* /etc/zookeeper* /etc/hive* /etc/hue /etc/impala /etc/sqoop* /etc/oozie /etc/hbase* /etc/hcatalog /etc/spark /etc/solr # 删除 Cloudera Manager 的 lock file rm -f /tmp/.scm_prepare_node.lock


3. Mysql 卸载 # 查看当前安装 mysql 情况 rpm -qa|grep -i mysql # 查看 mysql 服务状态 service mysql status # 关闭 mysql 服务 service mysql stop # 查看 mysql 相关进程 ps -ef |grep mysql # 关闭相关进程 kill pid # 删除包命令: yum remove -y mysql # 或者 rpm -e – nodeps 包名 # 查找 mysql 的相关目录 find / -name mysql # 删除对应的 mysql 目录 rm -rf 目录 # 手工删除 /etc/my.cnf rm -rf /etc/my.cnf # 检查机器是否安装 mysql rpm -qa|grep -i mysql


到此CDH已经卸载完成。
大数据
2018-08-16 15:46:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Hive应用:设置字段自增
介绍
语法: ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)
简单的说row_number()从1开始,为每一条分组记录返回一个数字,这里的ROW_NUMBER() OVER (ORDER BY xlh DESC) 是先把xlh列降序,再为降序以后的每条xlh记录返回一个序号。
以上是row_number() over()的基本用法,下面本人就给他赋予一个新的用法。
字段自增
当你要往一个表中导入数据时,需要一个自增的id字段,那么就需要使用以下两个函数搭配产生:row_number() over()
如果什么参数都不加,直接使用这两个字段,那么直接产生的是从1开始增加的数字。
例如: insert into table User_Attribute select row_number() over() as id,customid from tbl_custom;
如果单独使用函数row_number(),则会报错,错误内容如下: FAILED: SemanticException org.apache.hadoop.hive.ql.metadata.HiveException: Only COMPLETE mode supported for row_number function
指定自增基数
那么上面的自增完成了,肯定会有指定一个基数进行自增的需求,这个时候怎么办呢?
本人曾经试着在两个方法的括号里填写参数,实在是做不到,那么本人就从另一个角度进行思考,想出了如下格式的方式: (row_number() over())+number
number即为你指定的基数,上面的语句就可以写成如下: insert into table User_Attribute select (row_number() over())+1000 as id,customid from tbl_custom;
那么此时插入Hive表中的数据就是从1000开始增加的ID。插入的下一条的id就为1001,依次递增。
上一篇: Hive应用:数据外置内部表
下一篇: Hive应用:设置字段默认值
大数据
2018-08-11 10:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
背景
注: ElasticSearch 版本为 5.4 。
在我们的日志系统里需要一些系统索引,这些系统索引在应用初始化的时候就会被添加到 ElasticSearch 中去,这些在 ElasticSearch 中的系统索引在没有索引数据的时候,只有索引名和一些配置信息,没有 mapping 信息。当用户去根据时间区间排序搜索日志信息的时候, ElasticSearch 就会产生 all shards failed 异常。具体异常信息如下: Caused by: [.alert/NXa3zq5WSb-wGBKgyZibzw] QueryShardException[No mapping found for [timestamp] in order to sort on] at org.ElasticSearch.search.sort.FieldSortBuilder.build(FieldSortBuilder.java:262) at org.ElasticSearch.search.sort.SortBuilder.buildSort(SortBuilder.java:156) at org.ElasticSearch.search.SearchService.parseSource(SearchService.java:617) at org.ElasticSearch.search.SearchService.createContext(SearchService.java:468) at org.ElasticSearch.search.SearchService.createAndPutContext(SearchService.java:444) at org.ElasticSearch.search.SearchService.executeQueryPhase(SearchService.java:252) at org.ElasticSearch.action.search.SearchTransportService$6.messageReceived(SearchTransportService.java:331) at org.ElasticSearch.action.search.SearchTransportService$6.messageReceived(SearchTransportService.java:328) at org.ElasticSearch.transport.RequestHandlerRegistry.processMessageReceived(RequestHandlerRegistry.java:69) at org.ElasticSearch.transport.TransportService$7.doRun(TransportService.java:627) at org.ElasticSearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:638) at org.ElasticSearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37) ... 3 more
查看了 .alert 的索引数据再结合 ElasticSearch 的异常信息判断,我怀疑是由于 .alert 系统索引没有 timestamp mapping 信息引起的, .alert 索引初始化没有任何数据时, ElasticSearch 中的信息如下: http://dev:9200/.alert { ".alert": { "aliases": { "alert": {} }, "mappings": { "alert": {} }, "settings": { "index": { "refresh_interval": "-1", "number_of_shards": "5", "provided_name": ".alert", "creation_date": "1533613744728", "store": { "type": "fs" }, "number_of_replicas": "1", "uuid": "YuPjsObOTMO6u3fEdG6hVw", "version": { "created": "5040099" } } } } }
看到这些信息之后,我开始了用以下方法尝试解决。
解决方法
以下方法1和方法2都以失败而告终,只有方法3可以成功解决该问题。但在解决问题中我查找了很多资料,让我对 ElasticSearch 的 mapping 有了更深地理解,因此我将解决该问题的过程记录了下来。
方法1:添加索引模板
首先,由于是没有 timestamp 这个 mapping 信息,因此我想到创建索引模板,将 .alert 这个索引的 mappings 信息用模板来设置,以便在索引创建的时候就有相应的 mapping 信息。模板信息如下: { "alert": { "order": 0, "template": "alert", "settings": { "index": { "number_of_shards": "5", "number_of_replicas": "1", "refresh_interval": "2s" } }, "mappings": { "alert": { "properties": { "timestamp": { "type": "date" } } } }, "aliases": {} } }
但是,经过测试后发现, all shards failed 的问题还是会产生。究其原因是由于: 索引模板只会在插入新索引数据的时候生效,如果没有索引数据,索引模板定义的 mappings 信息不会生效,而且对模板的改变不会影响到已存在的索引。
此时, .alert 这个索引为空,还没有新数据插入,因此,模板不会生效,也就致使该方法不会解决 all shards failed 的问题。
方法2:创建索引时添加mapping
由于 ElasticSearch 允许在创建索引时就创建 mapping 信息,于是我想到了这个方法,经过测试后,可以解决 all shards failed 的问题。但是,产生了一个严重的后果,我们用 .alert 索引来记录服务器报警信息,当我往 .alert 这个索引里添加数据时,只有 timestamp 这个字段的数据添加进去了,其他数据像产生报警的主机、报警内容等信息添加失败。
查询官方文档发现: mapping 信息一旦被创建,就不允许被修改。改变已有的 mapping 就意味着使已经存在的索引数据无效,解决的办法就是使用正确的 mappings 信息来创建新的索引,然后重新把数据添加到新索引中。虽然官方提供了 reindex 方法来解决这个问题,但是,在大数据量的情况下, reindex 代价比较高,因此,创建索引时添加 mapping 这个方法也行不通。
方法3:给排序条件加unmapped_type
ElasticSearch 的 search api 可以设置排序时忽略字段的哪些映射。默认情况下,如果没有与排序字段关联的映射,则搜索请求将失败。 unmapped_type 选项允许设置忽略没有映射的字段,从而不对该字段排序。由于 timestamp 的 mapping 为 date 类型,因此,在搜索排序条件中增加 {"timestamp":{"unmapped_type":"date"}} 成功解决由于排序字段没有 date 映射引起的 all shards failed 问题。
参考资料
索引模板官方文档: Index Templates
索引排序官方文档: Sort
更新已存在的 mapping 信息官方文档: updating_existing_mappings
stackoverflow 问题链接: No mapping found for field in order to sort on in ElasticSearch
大数据
2018-08-10 23:29:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
概述
本文档介绍Hadoop hdfs系统的一些常用命令。
操作hdfs系统可以使用hadoop fs 也可以使用 hdfs dfs ,两者效果一样。(hadoop dfs命令已不再建议使用)

参考: http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_shell.html

常用命令
一、 hadoop fs (hdfs dfs) 文件操作
1) ls 显示目录下的所有文件或者文件夹
使用方法: hadoop fs -ls [uri形式目录]
示例: hadoop fs –ls / 显示根目录下的所有文件和目录

显示目录下的所有文件可以加 -R 选项
示例: hadoop fs -ls -R /

2) cat 查看文件内容
使用方法:hadoop fs -cat URI [URI …]
示例: hadoop fs -cat /in/test2.txt

3) mkdir 创建目录
使用方法:hadoop fs -mkdir [uri形式目录]
示例: hadoop fs –mkdir /test

创建多级目录 加上 –p
示例: hadoop fs –mkdir -p /a/b/c

4) rm 删除目录或者文件
使用方法:hadoop fs -rm [文件路径] 删除文件夹加上 -r
示例: hadoop fs -rm /test1.txt


删除文件夹加上 -r,
示例:hadoop fs -rm -r /test



5) put 复制文件
将文件复制到hdfs系统中,也可以是从标准输入中读取文件,此时的dst是一个文件
使用方法: hadoop fs -put ...
示例:
Hadoop fs -put /usr/wisedu/temp/test1.txt /
从标准输入中读取文件:hadoop fs -put -/in/myword

6) cp 复制系统内文件
使用方法:hadoopfs -cp URI [URI …]
将文件从源路径复制到目标路径。这个命令允许有多个源路径,此时目标路径必须是一个目录。
示例:
hadoop fs -cp /in/myword/word


7) copyFromLocal 复制本地文件到hdfs
使用方法:hadoop fs-copyFromLocal URI
除了限定源路径是一个本地文件外,和 put 命令相似
8) get 复制文件到本地系统
使用方法:hadoop fs -get[-ignorecrc] [-crc]
复制文件到本地文件系统。可用-ignorecrc选项复制CRC校验失败的文件。使用-crc选项复制文件以及CRC信息。
示例:hadoop fs -get/word /usr/wisedu/temp/word.txt

9) copyToLocal 复制 文件到本地系统
使用方法:hadoop fs-copyToLocal [-ignorecrc] [-crc] URI
除了限定目标路径是一个本地文件外,和 get 命令类似。
示例:hadoop fs - copyToLocal/word /usr/wisedu/temp/word.txt
10) mv
将文件从源路径移动到目标路径。这个命令允许有多个源路径,此时目标路径必须是一个目录。不允许在不同的文件系统间移动文件。
使用方法:hadoop fs -mv URI [URI …]
示例:hadoop fs -mv /in/test2.txt /test2.txt


11) du 显示文件大小
显示目录中所有文件的大小。
使用方法:hadoop fs -du URI [URI …]
示例: hadoop fs -du /

显示当前目录或者文件夹的大小可加选项 -s
示例: hadoop fs -du -s /


12) touchz 创建空文件
使用方法:hadoop fs -touchz URI [URI …]
创建一个0字节的空文件
示例:hadoop fs -touchz /empty.txt

13) chmod 改变文件权限
使用方法:hadoop fs -chmod[-R] URI [URI …]
与Linux平台下chmod命令相似,改变文件的权限。使用-R将使改变在目录结构下递归进行。命令的使用者必须是文件的所有者或者超级用户。
示例:先创建一个普通用户test:sudo useradd -m test
再用wisedu用户在hdfs系统目录/a下创建hello.txt文件,此时test具有读取/a/hello.txt文件的权限,如下图:

在切换回wisedu用户修改文件的权限,让/a目录下的文件对于其他用户都不可读,命令: hadoop fs -chmod -R o-r /a 如下图所示,再切换回test用户查看/a/hello.txt文件时提示没有权限:


14) chown 改变文件所有者
使用方法:hadoop fs -chown [-R] [OWNER][:[GROUP]] URI [URI]
改变文件的拥有者。使用-R将使改变在目录结构下递归进行。命令的使用者必须是超级用户。
示例:hadoop fs -chown -R test /a 如下图:


15) chgrp 改变文件所在组
使用方法:hadoop fs -chgrp [-R] GROUP URI [URI …]
改变文件所属的组。使用-R将使改变在目录结构下递归进行。命令的使用者必须是文件的所有者或者超级用户。
示例:hadoop fs -chgrp -R test /a 如下图:

二、 hdfs dfsadmin 管理命令
1) -report
查看文件系统的基本信息和统计信息。
示例:hdfs dfsadmin -report

2) -safemode
enter | leave | get | wait:安全模式命令。安全模式是NameNode的一种状态,在这种状态下,NameNode不接受对名字空间的更改(只读);不复制或删除块。NameNode在启动时自动进入安全模式,当配置块的最小百分数满足最小副本数的条件时,会自动离开安全模式。enter是进入,leave是离开。
示例:hdfs dfsadmin -safemode get
hdfsdfsadmin -safemode enter

3) -refreshNodes
重新读取hosts和exclude文件,使新的节点或需要退出集群的节点能够被NameNode重新识别。这个命令在新增节点或注销节点时用到。
示例:hdfs dfsadmin -refreshNodes

4) -finalizeUpgrade
终结HDFS的升级操作。DataNode删除前一个版本的工作目录,之后NameNode也这样做。
5) -upgradeProgress
status| details | force:请求当前系统的升级状态 | 升级状态的细节| 强制升级操作
6) -metasave filename
保存NameNode的主要数据结构到hadoop.log.dir属性指定的目录下的文件中。
7) -setQuota……
为每个目录设定配额。目录配额是一个长整形整数,强制设定目录树下的名字个数。
8) -clrQuota……
为每个目录清除配额设定。
9) -help
显示帮助信息
大数据
2018-08-10 16:47:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
重磅|大快搜索上榜2018中国大数据企业50强
——斩获“2018中国大数据产业生态大会”多项大奖,成年度最大黑马
近日,由工信部中国电子信息产业发展研究院主办,中国大数据产业生态联盟承办的2018(第三届)中国大数据产业生态大会在北京盛大召开,工信部党组成员、总工程师张锋、工信部原副部长、北京大学教授杨学山等中央及地方主管领导、行业专家、企业领袖、知名投资人近千人汇聚一堂,深入探讨深挖数据智能、助推数字经济发展的有效路径。青岛大数据企业大快搜索受邀出席,并斩获多项大奖。
入选“2018中国大数据企业50强”
2018中国大数据企业50强”从企业规模(15%)、研发投入(15%)、创新能力(20%)、应用案例(20%)、产品及方案成熟度(15%)、投资及发展潜力(15%)等不同维度设置评价指标体系。同时,结合《2018中国大数据产业生态地图暨中国大数据产业发展白皮书》的调研工作,经过由政府主管部门的相关领导、大数据产业资深专家、行业知名用户CIO、行业媒体总编以及第三方测评机构专家组成的专家评审组的严格评审,由最初的初步筛选,到近1000家企业成功入围,到200家优秀企业进入专家评审,最终评审出“2018中国大数据企业50强”。大快搜索凭借在大数据、人工智能、自然语言处理等领域的卓越能力和发展潜力入选“2018中国大数据企业50强”。 
大快搜索跻身“2018中国大数据50强”
获评“中国最具投资价值大数据企业排行榜·TOP100” 会上,主办方重磅发布的《2018中国大数据产业发展白皮书》重点呈现:2018中国大数据产业生态地图、中国最具投资价值大数据企业排行榜·TOP100及中国大数据产业应用十大爆发领域等。 其中,在2018中国大数据产业生态地图中,大快搜索全面覆盖基础支撑、数据服务及融合应用三大生态环节,涉及大数据基础平台、数据采集及预处理及政府大数据解决方案等;同时,经过企业估值/市值、营收状况、创新投入、专利数量、产品竞争力、企业发展潜力、领导层能力等多维度的定量与定性评比及专家打分,大快搜索获“中国最具投资价值大数据企业排行榜·TOP100”。
大快搜索获“中国最具投资价值大数据企业排行榜·TOP100”
总工程师汤连杰荣获“2018中国数据大工匠 2016年3月,政府工作报告中提出要“培育精益求精的工匠精神”,工匠精神列入政府工作报告。工匠精神是指精雕细琢,精益求精的精神理念。对于大数据企业的产品、解决方案以及服务进行精雕细琢,坚持精耕细作,精益求精,就是大数据领域的工匠精神。本次评选推选出兼具技术特长、影响力、领导力、贡献力、实践力等综合能力的中国数据大工匠,为培育国际领先的大数据核心龙头企业储备能量。大快搜索总工程师汤连杰凭借多年在Hadoop国产化、易用性的卓越贡献,荣获“2018中国数据大工匠”。
获奖人:汤连杰——青岛大快搜索计算技术股份有限公司总工程师 颁奖词:由汤连杰主持开发的DKHadoop解决了Hadoop技术不透明、数据安全存在隐患的痛点,并已得到了市场的广泛认可。在汤连杰的带领下,大快搜索为我国大数据软件市场提供了安全、可控的国产化大数据基础软件。
大数据公共资源管理(管控)平台、石化预警预判系统项目入选《2018中国大数据应用典型案例集》
《2018中国大数据应用典型案例集》重点展示充分体现技术先进性/实用性、探索大数据新型商业服务模式、引领行业转型升级、促进大数据新技术/新业态/新模式产业化、优化大数据产业发展环境、带动产业蓬勃发展等的优秀产品、服务平台及应用解决方案。由大快搜索研发的大数据公共资源管理(管控)平台、石化预警预判系统项目凭借技术领先性和引领行业转型升级,成功入选《2018中国大数据应用典型案例集》 HanLP获评“2018中国数据星技术” HanLP是大快搜索高级研究员何晗(Hankcs)主持开发的面向象形文字的自然语言处理技术。具备功能完善、性能高效、架构清晰、语料时新、可自定义的特点。目前HanLP在GitHub上的star数已达到8000,高于老牌的NLTK(6.4k)和斯坦福大学开源的CoreNLP(4.3k)以及哈尔滨工业大学开源的LTP(1.4k),是目前全球开发者用户最多、最受欢迎、活跃度最高的开源自然语言处理项目。凭借技术领先性和用户活跃度,HanLP获评《2018中国数据星技术》

HanLP获评“2018中国数据星技术”
获评:“2018中国大数据基础软件领域创新企业&最佳产品” 大快搜索自成立以来,始终致力于大数据与人工智能核心技术自主研发,在大数据和人工智能基础软件、自然语言处理技术、大数据标准开发库等领域均取得了傲人的成绩。目前大快的合作客户已超过200余家,其中:上市企业 43 家,中国软件百强 23 家。大快的核心技术,帮助众多大数据与人工智能项目,实现更高的计算性能提升。大快深度研发、整合的DK.ES、DK.Sqoop Pro等产品也应用在了大量的项目中,并取得了良好的市场反馈。本次大会,获评“2018中国大数据基础软件领域创新企业&最佳产品”
大快搜索获评“2018中国大数据基础软件领域创新企业&最佳产品”
此次大会获得的荣誉既是对以往工作的肯定,也是对大快未来成绩的一种期冀。大快将继续以核心技术自主可控为发展方向,为更多合作伙伴提供更高性能、更具可用性、更安全的国产化大数据与人工智能核心技术,助推中国大数据生态构建、为政府、社会提供自主可控、高效易用的大数据底层技术。
大数据
2018-08-10 15:36:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
简介
如果是新手,请严格按照步骤来做。当然还有其他安装方式,这里讲的方式比较适合测试使用。
内容 版本 CentOS 7 64位
JDK Cloudera Manager
1.7 5.14.1
本次安装一共使用3台服务器,主要用户测试。
服务名 内网IP 用途 master 192.168.254.130 主,按照CM
slave01 slave02
192.168.254.210 192.168.254.211
从 从
可以搭建三台虚拟机,其中master内存在8G以上,slave内存在4G以上,每个虚机的硬盘空间100G+
下载软件包和数据包
我这里提供两种下载方式: 在下载的时候可以先把服务器基础环境准备好
百度云盘下载
推荐百度云超级VIP账号的用户,里面包含所有的安装包和数据包 链接: https://pan.baidu.com/s/1JC-vpYH7SWBwju9C8DkVPw 密码: 26v8
官方下载
这是一个漫长的过程,试过才知道爽。
下载CM和jdk软件包
访问: http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/
把上面的所有rpm包都下载回来本地,下载速度慢可以使用 axel 多线程下载,如果没有装 axel ,也可以使用 wget -b 后台下载
我的相关下载都放在 /data/soft 下,我的Cloudera Manager 5.14.1的下载放在 /data/soft/cm5.14.1 ,所以新建目录并进入目录: mkdir -p /data/soft/cm5.14.1/cm-and-jdk cd /data/soft/cm5.14.1/cm-and-jdk wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/cloudera-manager-agent-5.14.1-1.cm5141.p0.1.el7.x86_64.rpm wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/cloudera-manager-daemons-5.14.1-1.cm5141.p0.1.el7.x86_64.rpm wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/cloudera-manager-server-5.14.1-1.cm5141.p0.1.el7.x86_64.rpm wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/cloudera-manager-server-db-2-5.14.1-1.cm5141.p0.1.el7.x86_64.rpm wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/enterprise-debuginfo-5.14.1-1.cm5141.p0.1.el7.x86_64.rpm wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/jdk-6u31-linux-amd64.rpm wget -b http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/RPMS/x86_64/oracle-j2sdk1.7-1.7.0+update67-1.x86_64.rpm
下载cloudera-manager安装文件
访问: http://archive.cloudera.com/cm5/installer/5.14.1/
下载cloudera-manager-installer.bin cd /data/soft/cm5.14.1/ wget http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/cloudera-manager.repo
下载rpm仓库文件 wget http://archive.cloudera.com/cm5/redhat/7/x86_64/cm/cloudera-manager.repo
下载parcel
这个比较大,放下服务器慢慢下吧 mkdir -p /data/soft/cm5.14.1/parcel cd /data/soft/cm5.14.1/parcel wget -b http://archive.cloudera.com/cdh5/parcels/5.14.0.24/CDH-5.14.0-1.cdh5.14.0.p0.24-el7.parcel wget -b http://archive.cloudera.com/cdh5/parcels/5.14.0.24/CDH-5.14.0-1.cdh5.14.0.p0.24-el7.parcel.sha1
服务器环境准备
修改hostname及hosts 针对所有节点操作
为了便于安装过程中对各个服务器的访问更易区分、更便捷,我们需要分别对各个服务器修改hostname及hosts hostnamectl --static set-hostname master hostnamectl --static set-hostname slave01 hostnamectl --static set-hostname slave02
修改hosts: vim /etc/hosts
根据自己的3台服务器IP地址,在最后面增加: 192.168.254.130 master 192.168.254.210 slave01 192.168.254.211 slave02
重启机器 reboot
关闭防火墙和selinux 针对所有节点操作
关闭防火墙 systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止firewall开机启动 firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)
关闭selinux: vim /etc/selinux/config
找到SELINUX改为: SELINUX=disabled
ssh无密码登录 针对所有节点操作
先在master上执行: ssh-keygen -t rsa #一路回车到完成 ssh-copy-id -i ~/.ssh/id_rsa.pub root@master #将公钥拷贝到本机的authorized_keys上
再在其他节点分别执行以下命令: ssh-keygen -t rsa #一路回车到完成 ssh-copy-id -i ~/.ssh/id_rsa.pub root@master #注意此处不变,将公钥拷贝到master的authorized_keys上
在master上,将authorized_keys分发到其他节点服务器: scp ~/.ssh/authorized_keys root@slave01:~/.ssh/ scp ~/.ssh/authorized_keys root@slave02:~/.ssh/
安装ntp时间同步软件
所有节点时间一致非常重要,要不然启动Cloudera Manager服务后,后台会报错。
所有节点执行: yum install ntp -y
安装完成后,阿里云的服务器会自动使用阿里云的ntp服务器进行同步,故可不再进行下面的配置,直接进入2.6节,若其他没有统一ntp服务器进行同步的,则还需要以下设置:
将master设置为主服务器(在master节点操作): vim /etc/ntp.conf
内容如下: driftfile /var/lib/ntp/ntp.drift #草稿文件 # 允许内网其他机器同步时间 restrict 192.168.137.0 mask 255.255.255.0 nomodify notrap # Use public servers from the pool.ntp.org project. # 中国这边最活跃的时间服务器 : [http://www.pool.ntp.org/zone/cn](http://www.pool.ntp.org/zone/cn) server 210.72.145.44 perfer # 中国国家受时中心 server 202.112.10.36 # 1.cn.pool.ntp.org server 59.124.196.83 # 0.asia.pool.ntp.org # allow update time by the upper server # 允许上层时间服务器主动修改本机时间 restrict 210.72.145.44 nomodify notrap noquery restrict 202.112.10.36 nomodify notrap noquery restrict 59.124.196.83 nomodify notrap noquery # 外部时间服务器不可用时,以本地时间作为时间服务 server 127.127.1.0 # local clock fudge 127.127.1.0 stratum 10
重启ntpd服务: systemctl ntpd restart
查看同步状态: netstat -tlunp | grep ntp
所有子节点ntp加入开机启动: systemctl enable ntpd
设置slave到master 的同步(在slave节点操作): vim /etc/ntp.conf
内容如下: driftfile /var/lib/ntp/ntp.drift # 草稿文件 statsdir /var/log/ntpstats/ statistics loopstats peerstats clockstats filegen loopstats file loopstats type day enable filegen peerstats file peerstats type day enable filegen clockstats file clockstats type day enable # 让NTP Server为内网的ntp服务器 server 192.168.137.110 fudge 192.168.137.110 stratum 5 # 不允许来自公网上ipv4和ipv6客户端的访问 restrict -4 default kod notrap nomodify nopeer noquery restrict -6 default kod notrap nomodify nopeer noquery # Local users may interrogate the ntp server more closely. restrict 127.0.0.1 restrict ::1
重启ntpd服务: systemctl ntpd restart
手动同步: ntpdate -u master
所有节点重启服务器: reboot
分配安装文件
主节点和子节点分别需要的文件整理如下:
主节点master,所需文件: cloudera-manager-agent-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm cloudera-manager-daemons-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm cloudera-manager-server-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm cloudera-manager-server-db-2-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm enterprise-debuginfo-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm cloudera-manager-installer.bin cloudera-manager.repo CDH-5.14.1-1.cdh5.14.1.p0.2-el7.parcel CDH-5.14.1-1.cdh5.14.1.p0.2-el7.parcel.sha1
从节点slave01、slave02,所需文件: cloudera-manager-agent-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm cloudera-manager-daemons-5.14.1-1.cm5141.p0.2.el7.x86_64.rpm cloudera-manager.repo
使用 scp 命令分配所需要的安装文件
安装Cloudera Manager
至此,所有设置完成。开始Cloudera Manager安装吧!
安装 cm-and-jdk 针对所有节点操作
修改仓库文件cloudera-manager.repo,把版本号加上 [cloudera-manager] name = Cloudera Manager baseurl = https://archive.cloudera.com/cm5/redhat/7/x86_64/cm/5.14.1/ #主要改这里的版本号 gpgkey = https://archive.cloudera.com/redhat/cdh/RPM-GPG-KEY-cloudera gpgcheck = 1
验证repo文件是否起效
yum list | grep cloudera #如果列出的不是待安装的版本,执行下面命令重试 yum clean allyum list | grep cloudera
切换到cm-and-jdk目录下,执行 yum localinstall --nogpgcheck *.rpm
设置java路径: vi /etc/profile
在该文件末尾添加以下行 JAVA_HOME=/usr/java/jdk1.7.0_67-cloudera PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME PATH
检查安装: java -version 下面针对master节点操作
进入cloudera-manager-installer.bin文件目录,给bin文件赋予可执行权限: chmod +x ./cloudera-manager-installer.bin
运行: ./cloudera-manager-installer.bin --skip_repo_package=1
如果提示需要删除配置文件,则删除该文件 rm -rf /etc/cloudera-scm-server/db.properties
相同配置下顺利安装时间在1分钟内即可完成。 然后我们在web浏览器访问 http://192.168.254.130:7180/,看是否能打开页面即可,先不要进行登录操作。
注意:chd server服务器启动需要一些时间,等1分钟左右。
如果能访问,那证明 cloudera manager安装正常。
安装CDH
制作本地parcel
前面完成cloudera manager安装之后master会在/opt目录下生成cloudera文件夹,将之前下载好的CDH-*文件移动到parcel-repo文件夹中 cp CDH-5.14.0-1.cdh5.14.0.p0.24-el7.parcel /opt/cloudera/parcel-repo/ cp CDH-5.14.0-1.cdh5.14.0.p0.24-el7.parcel.sha1 /opt/cloudera/parcel-repo/CDH-5.14.0-1.cdh5.14.0.p0.24-el7.parcel.sha #注意这里有重命名
将cloudera manager的用户授权给/opt和日志目录: chown -R cloudera-scm.cloudera-scm /var/lib/cloudera-scm-server chown cloudera-scm.cloudera-scm /opt -R chown cloudera-scm.cloudera-scm /var/log/cloudera-scm-agent -R
重启cloudera-scm-server(重要) /etc/init.d/cloudera-scm-server restart
重启速度较慢,约1分钟后访问 http://192.168.254.130:7180/ 登陆,账号密码 admin 选择免费版本,一路next开始安装。
基本默认就行
在为CDH集群安装指定主机的时候写 master slave01 slave02
这里需要填写我们集群定义的ip或者服务器名称(包括安装CM的主机本身),点击搜索,即可加载出所有主机。全选所有主机,并继续。
这里会出现我们之前cp过去的CDH版本,选择并继续。

如果之前的操作没有问题,这里将会很快完成
在选择安装的服务组合的时候,选择自己需要的,如果不知道,全部安装就行
这里是最激动人心的时候
随便找台机器测试一下spark: spark-shell
激动的敲了一个:
CDH启动与关闭
CM Portal 地址:
http://master:7180/cmf/home
关闭步骤:
在CM portal上关闭 cluster
在所有节点关闭CM agent: service cloudera-scm-agent stop
在master节点关闭CM server: service cloudera-scm-server stop
启动步骤:
在所有节点启动CM agent: service cloudera-scm-agent start
在master节点启动CM server: service cloudera-scm-server start
在CM portal上启动 cluster
查看启动日志: /var/log/cloudera-scm-server/cloudera-scm-server.log
如果是3台机器一般会出现错误:
在CM console中将副本设为2: dfs.replication=2
在所有的节点命令行执行: hadoop fs -setrep 2 /
安装要点: 仔细,认真,严格按照步骤 常见问题:网络,防火墙等主机设置 碰到问题:查看日志&官网&百度 cloudera JDBC Driver com.mysql.jdbc.Driver not found.
将oracle的mysql的jar包放置到/usr/share/java/mysql-connector-java.jar路径下即可,注意修改jar包名称;
切记除了要下载parcel文件之外,还有manifest.json文件,否则在选择安装版本界面,cloudera无法识别parcel的版本。
还有需要对于sha1文件进行改名:*.parcel.sha1 -> *.parcel.sha
为什么CDH的安装页面显示无法发现CDH ?
之前一直怀疑是流程步骤有问题,其实流程本身没有问题,问题发生在流程的实施节点上:cdh文件损坏了;本来1.5G的大小,当时只有50M,我不记得原因了,但是太坑了。
我想到了权限问题;但是忽略了文件损坏问题:sha就是干这个用的,当时应该考虑到使用sha来校验一下文件。
如果cloudera发现能够正常发现parcel,在server启动后将会打出一条日志: SearchRepositoryManager-0:com.cloudera.server.web.cmf.search.components.SearchRepositoryManager: Finished constructing repo:2017-09-27T16:19:00.763Z
安装CDH在拷贝parcel的时候发生异常: Exhausted available authentication methods ;
后来发现原来是因为ssh的root用户被我设置为禁止远程登录;而CDH页面向导中我还配置的用root用户登录
之后发现拷贝异常,总是联网去下载agent包,但是agent都已经在各个节点了;后来发现agent的启动是失败的(在开始的步骤中能够被自动发现的都不需要装agent,需要通过手动输入IP来进行发现的需要装agent,怎么装?联网),报错显示: ProtocolError: ;在网上搜索了一下,如下处理: sudo ps -ef | grep supervisord kill -9 PID sudo ./cloudera-scm-agent restart
未完,重启后发现: Error, CM server guid updated, expected d6c22714-0175-4a40-ace6-db92b7417a40, received 613b2c09-88f6-41fe-9424-41601be40310
原来还需要将 cm/lib/cloudera-scm-agent/ 下面的 cm_guid 进行清除;这一点让我想到了cloudera数据迁移的时候需要做的事情,需要将同目录下的uuid进行删除;
在安装的过程中还有一个问题一直困扰我,就是僵尸agent,在agent经历如上的问题后,在自动发现的列表中有一些僵尸agent,会看到同hostname的多台机器,有一个是正常通信,有的则是Unkonwn,无法删掉,因为不勾选,那么正常通信的也不会勾选上。反正后来我改了一下hosts文件,莫名其妙的在勾选列表中消失了,但是遗憾的是正常通信的也没了。安装成功后,在Hosts页面才看到这些僵尸agent,此时再delete可以正常删除。 Skipping start command because all roles are started or decommissioned or on decommissioned host.
cloudera的server停止后要稍等一会在启动,因为释放内存需要一段时间;如果停止后立即就启动将会发生一种情况,内存没有释放完,JVM的内存大量释放和JVM的大量使用将会导致JVM频繁的进行回收和释放,导致JVM Pause以及World Stop JAVA_HOME is not set and Java could not be found
具体原因不太清楚,最小化安装了一个centos7,发现没有jdk,不解。
在clouderea中添加了一个host,然后添加了一个spark nodemanager的角色,然后就悲剧了,总是抱JAVA_HOME is not set and Java could not be found的异常;即使手动拷贝了一个jdk1.8到上面,profile也配置了,仍然不好用。不解。
再看日志的时候,发现安装程序(cloudera的安装程序)将会到几个固定的地方查找,选一个,然后将jdk拷贝到该目录下,问题解决
欢迎关注公众号《全栈架构》
全栈有风险,菜鸟需谨慎
参考: https://www.linuxidc.com/Linux/2018-03/151491.htm https://blog.csdn.net/czk740960212/article/details/80484671 https://blog.csdn.net/chenhai201/article/details/78856007 https://www.cnblogs.com/xiashiwendao/p/7260302.html
大数据
2018-08-10 10:50:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1.文件准备(elasticsearch的jdk需要1.8以上)
去官网下载最新的elasticsearch-6.3.2和kibana-6.3.2
https://www.elastic.co/downloads
2.下载完成后,上传至linux,解压到指定目录。 tar -zxvf /opt/elasticserach-6.3.2 -C /var/opt/
3.修改elasticsearch的配置文件 cd elasticsearch-6.3.2/config vim elasticsearh.yml cluster.name: elasticsearch-6 node.name: node-1 network.host: 0.0.0.0 http.port: 9200
4.直接root用户启动会报错,6.0后直接修改配置文件,用root用户启动已经不行了,所以需要创建一个其他用户来启动elasticsearch。 #创建elasticsearch用户组 groupadd elasticsearch useradd es -g elasticsearch-p /var/opt/elasticsearch-6.3.2 #更改elasticsearch文件夹及内部文件的所属用户及组为es:elasticsearch cd /var/opt chown -R es:elasticsearch elasticsearch-6.3.2 #切换到elsearch用户再启动 su es cd elasticsearch-6.3.2/bin ./elasticsearh
5.启动发现报错:
1 . max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
2.max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
修改配置文件: #修改第一个错误 vim /etc/security/limits.conf # 在最后面追加下面内容 es hard nofile 65536 es soft nofile 65536 #es即为启动用户的名称 ---修改第二个错误 #切换到root用户修改配置sysctl.conf vi /etc/sysctl.conf #添加下面配置: vm.max_map_count=655360 #并执行命令: sysctl -p
参考文档:
https://blog.csdn.net/jiankunking/article/details/65448030
https://www.cnblogs.com/yidiandhappy/p/7714481.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/zip-targz.html

kibana-6.3.2安装 #解压至指定目录 tar -zxvf kibana-6.3.2-linux-x86_64.tar.gz -C /var/opt/ #修改配置config/kibana.yml cd /var/opt/kibana-6.3.2-linux-x86_64/config vim kibana.yml #端口 server.port: 5601 #主机 server.host: "172.16.20.11" #es的地址 elasticsearch.url: "http://172.16.20.11:9200" #kibana在es中的索引 kibana.index: ".kibana" #启动kibana #前台启动 ./kibana #后台启动 nohup ./kibana &
参考文档:
https://my.oschina.net/shea1992/blog/1925414

安装ik分词器 elasticsearch-analysis-ik -6.3.2
下载地址: https://github.com/medcl/elasticsearch-analysis-ik/releases
需要下载对应的的elasticseach的版本的分词器,然后直接解压zip到es的plugins目录中 #创建ik分词器的目录 cd /var/opt/elaticsearch-6.3.2/plugins/ mkdir ik #解压至指定目录 unzip /var/opt/elasticsearch-analysis-ik-6.3.2.zip -d /var/opt/elaticsearch-6.3.2/plugins/ik #重启es #在kibana中测试分词器是否加载成功 #点击Dev_Tools GET _analyze?pretty { "analyzer":"ik_smart", "text":"我爱北京天安门" } #显示如下 { "tokens": [ { "token": "我", "start_offset": 0, "end_offset": 1, "type": "CN_CHAR", "position": 0 }, { "token": "爱", "start_offset": 1, "end_offset": 2, "type": "CN_CHAR", "position": 1 }, { "token": "北京", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 2 }, { "token": "天安门", "start_offset": 4, "end_offset": 7, "type": "CN_WORD", "position": 3 } ] }
logstash-6.3.2安装
下载logstash-6.3.2
https://www.elastic.co/downloads/logstash #解压loastash至指定文件 tar -zxvf logstash-6.3.2.tar.gz -C /var/opt/ #进入到bin目录下安装jdbc插件:用于将mysql数据同步到elasticsearch ./logstash-plugin install logstash-input-jdbc
再下载mysql的链接工具:
https://dev.mysql.com/downloads/connector/j/
然后放入到指定目录--/var/opt/
从mysql导入数据到elasticsearch通过logstash
1.首先创建索引---通过kibana的Div_Tools PUT hisms_ns { "mappings": { "t_kc21k1": { "properties": { "id": { "type": "text", "index": "false" }, "aac003": { "type": "text", "index": "false" }, "yka002": { "type": "text", "index": "false" }, "yka003": { "type": "text", "index": "false" }, "ykd018": { "type": "text", "index": "false" }, "ykd018_name": { "type": "text", "index": "false" }, "akc190": { "type": "text", "index": "false" }, "aac001": { "type": "text", "index": "false" }, "akc194": { "type": "text", "format": "dateOptionalTime" }, "yka055": { "type": "double" }, "money_sum": { "type": "double" }, "id_drg": { "type": "text", "index": "false" }, "name_drg": { "type": "text", "index": "false" }, "id_mdc": { "type": "text", "index": "false" }, "name_mdc": { "type": "text", "index": "false" }, "if_ss": { "type": "short" }, "if_death": { "type": "short" }, "zysc": { "type": "short" }, "sq_zysc": { "type": "short" }, "if_ry_cy_fh": { "type": "short" }, "if_zdfx_death": { "type": "short" }, "if_zyhz": { "type": "short" }, "if_yngr": { "type": "short" }, "if_sscf": { "type": "short" }, "yp_fee": { "type": "double" }, "if_tskss": { "type": "short" }, "if_3tskss": { "type": "short" }, "ghc_fee": { "type": "double" }, "jc_fee": { "type": "double" }, "oneself_fee": { "type": "double" }, "if_34_ss": { "type": "short" }, "id_depa": { "type": "text", "index": "false" }, "id_doctor_org": { "type": "text", "index": "false" }, "zyys_org": { "type": "text", "index": "false" }, "if_zzy": { "type": "short" }, "if_tzzy": { "type": "short" }, "if_op10_death": { "type": "short" }, "if_bl_lc_fh": { "type": "short" }, "if_yx_bl_fh": { "type": "short" }, "yjqk_yh_sum": { "type": "short" }, "yjqk_sum": { "type": "short" }, "bazl": { "type": "short" }, "rescue_true": { "type": "short" }, "rescue": { "type": "short" }, "zhylfwf": { "type": "double" }, "syszdf": { "type": "double" }, "yxxzdf": { "type": "double" }, "sszlf": { "type": "double" }, "fsszlf": { "type": "double" }, "xyf": { "type": "double" }, "kjywf": { "type": "double" }, "zcyjzyf": { "type": "double" }, "hcf": { "type": "double" }, "qtf": { "type": "double" }, "zdbm": { "type": "text", "index": "false" }, "zdmc": { "type": "text", "index": "false" }, "ssbm": { "type": "text", "index": "false" }, "ssmc": { "type": "text", "index": "false" }, "group_status": { "type": "text", "index": "false" }, "drg_error_msg": { "type": "text", "index": "false" }, "bz_name": { "type": "text", "index": "false" }, "bz_id": { "type": "text", "index": "false" }, "belong_ks": { "type": "text", "index": "false" }, "id_doctor_add": { "type": "text", "index": "false" }, "zyys_add": { "type": "text", "index": "false" }, "id_doctor": { "type": "text", "index": "false" }, "zyys": { "type": "text", "index": "false" } } } } }' #安装完后,然后在进入到config的目录下, #创建配置文件jdbc.conf(自己取名即可 vim jdbc.conf #输入以下内容: input { jdbc { jdbc_driver_library => "/var/opt/mysql-connector-java-8.0.11.jar" jdbc_driver_class => "com.mysql.cj.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://10.111.121.236:3306/hisms_ns?serverTimezone=GMT%2B8" jdbc_user => "root" jdbc_password => "root" schedule => "* * * * *" statement => "SELECT * from t_kc21k1" } } output { elasticsearch { hosts => [ "172.16.20.11:9200" ] index => "hisms_ns" document_type => "t_kc21k1" document_id => "%{id}" } stdout { codec => json_lines } } ##参数解析 index => "hisms_ns"#指定导入的索引 document_type => "t_kc21k1"#指定导入的该索引下的type ##如果要将不同数据导入不同索引,可以参考如下: input { jdbc { jdbc_driver_library => "/var/opt/mysql-connector-java-8.0.11.jar" jdbc_driver_class => "com.mysql.cj.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://10.111.121.236:3306/hisms_ns?serverTimezone=GMT%2B8" jdbc_user => "root" jdbc_password => "root" schedule => "* * * * *" statement => "SELECT * from t_kc21k1" type => "01" } jdbc { jdbc_driver_library => "/var/opt/mysql-connector-java-8.0.11.jar" jdbc_driver_class => "com.mysql.cj.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://10.111.121.236:3306/hisms_ns?serverTimezone=GMT%2B8" jdbc_user => "root" jdbc_password => "root" schedule => "* * * * *" statement => "SELECT * from t_kc21k1" type => "02" } } output { if [type] == "01" { elasticsearch { hosts => [ "172.16.20.11:9200" ] index => "hisms_ns" document_type => "t_kc21k1" document_id => "%{id}" } stdout { codec => line { format => "Crawl: %{id} %{title}" } } } else { elasticsearch { hosts => [ "172.16.20.11:9200" ] index => "hisms_ns" document_type => "t_kc21k1_2" document_id => "%{id}" } stdout { codec => line { format => "VMS: %{id} %{title}" } } } }
最后执行导入命令即可:
./bin/logstash -f ./config/jdbc.conf --config.reload.automatic
或者
./bin/logstash -f ./config/jdbc.conf

参考文档:
https://blog.csdn.net/chenjianhuideyueding/article/details/80864345
https://blog.csdn.net/lilongsy/article/details/78283122
https://elasticsearch.cn/question/3753

补充:kibana中的索引问题 1.通过logstash导入数据后kibana不能显示出字段问题 解决方法: logstash导入数据后可以在kibana看见数据,此时点击management,再点击index patterns,最后点击右上角的刷新按钮,刷新所有字段即可显示。 2.针对string字段不能使用Aggregatabel问题。 case1:不手动创建索引映射的情况 直接通过logstash自动导入,此时string字段是可以被聚合的,默认自带keyword标签。 case2:需要手动创建索引映射的情况 在创建索引的时候,添加字段描述,方式如下: "yka003": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } },
大数据
2018-08-10 09:46:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Hive应用:数据外置内部表
介绍
个人认为这种表就体现了Hive的无节操无底线。会颠覆你对外部表和内部表的传统认知。
当你在创建内部表的时候,加上了location和目录,那么你的数据就存放在你指定的目录中,这个目录可以是在HDFS的任意目录,所以如果你的Hive库中存在这样的表,那么你就不能随意地删除你Hive中的任何表,因为使用show tables;命令查看Hive中的表的列表时,没有明确标识哪个表是外部表,哪个表是内部表,不小心删除之后,数据就彻底没了。
示例
先创建HDFS目录/data/person,将数据文件上传到此目录之下。数据内容如下: 1.0|张三|20.0|男|未知|0 2.0|李四|25.0|男|河北|0 3.0|张飞|30.0|男|河北|0 4.0|关羽|35.0|男|山东|0 5.0|小乔|38.0|女|浙江|0 6.0|刘备|40.0|男|成都|0 7.0|小李|29.0|男|江南|0
创建Hive内部表: hive> create table person(id string,name string,age string,gender string,address string,test int) row format delimited fields terminated by '|' location 'hdfs://192.168.75.150:9000/data/person'; OK Time taken: 0.148 seconds hive> select * from person; OK 1.0 张三 20.0 男 未知 0 2.0 李四 25.0 男 河北 0 3.0 张飞 30.0 男 河北 0 4.0 关羽 35.0 男 山东 0 5.0 小乔 38.0 女 浙江 0 6.0 刘备 40.0 男 成都 0 7.0 小李 29.0 男 江南 0 Time taken: 0.141 seconds, Fetched: 7 row(s) hive>
此时就创建了一个数据外置的内部表,这个表也允许先有数据,上面展示的数据,就是证明了这一点,完美展示了数据外置的内部表。
然而如果删除Hive中的这个表的话,数据也会跟着被删除。
下图是数据存放的目录:
在看一下test数据库目录:
没有person表的目录。
接下来将删除person表看看目录的变化: hive> drop table preson; OK Time taken: 0.184 seconds hive> show tables; OK person promo tab Time taken: 0.222 seconds, Fetched: 3 row(s) hive> drop table person; OK Time taken: 0.189 seconds hive> show tables; OK promo tab Time taken: 0.076 seconds, Fetched: 2 row(s) hive>
第一遍删除竟然没有成功,不知道闹哪样,第二次删除成功,下面是目录结构:
data目录空了,person文件夹也不存在了。
总结
所以综上所述,这种内部表有普通外部表的先有数据的特性,还具有普通内部表删除表数据也同时删除的特性。那么如果这个表也是内部表的话,那么内部表和外部表的区别在哪里?只剩下一个external关键字了,其他的没有区别了,而且Hive中表的列表中没有明确标识表的种类,稀里糊涂一顿删除,有可能删除的就是这种表!
这种表出现有两种可能:一种是创建外部表的时候手误忘记写external关键字,另外一种就是真的需要这样一种表,但是好像在我的职业生涯中,还暂时没有遇到这种需求,而本人只是手误忘记写external关键字,才产生的这种表,然后删除,重新创建,发现存放数据的目录以及数据都没有了,才进一步做了以上的实验来证明这个事情。
上一篇: Hive应用:外部分区表
下一篇: Hive应用:设置字段自增
大数据
2018-08-09 21:15:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1.产品介绍
Ignite
Ignite内存计算平台是一个高性能、集成化、混合式的企业级分布式架构解决方案,功能强大,有先进的集群管理功能,对于分布式内存数据库、流处理技术、分布式计算、分布式服务、分布式数据结构、持久化、Hadoop和Spark加速等功能,提供了广泛的支持,用于大规模的数据处理,比传统的基于磁盘或闪存的技术在性能上有指数级的提升。最新的版本在基于ZooKeeper的发现机制基础上,支持扩展至上千个节点。该软件由美国GridGain公司开发,于2014年将绝大部分功能捐赠给Apache基金会,命名为Ignite,目前为Apache基金会的顶级项目,GridGain公司还提供Ignite的企业版,具体可以根据需要进行选择。
Oracle TimesTen Scaleout
TimesTen Scaleout是Oracle TimesTen 18.1版本的一个新的产品分支,是Oracle第一个商用关系型内存分布式数据库,支持分布式,横向扩展。这种新的体系结构使TimesTen内存数据库能够扩展至几十台主机,达到数百TB的容量,并且每秒支持数百万次事务,而无需手动数据库分片或应用程序分区,特别适合有着高并发、高吞吐量事务处理需求的业务场景。
2.产品对比
基本属性
序号 对比项目 Ignite TimesTen Scaleout 1 是否支持开源 Ignite本身为Apache2.0协议开源,还有企业版GridGain 商业软件
2 技术支持 有开源社区技术支持,也有商业技术支持 商业技术支持
3 线性扩展 支持,使用ZooKeeper的发现机制,支持扩展至上千个节点。 支持,最多扩展至64个节点
4 内存分布式数据库 内存分布式数据库是Ignite的主打功能之一。 是Oracle第一个商用的内存分布式数据库。之前的TimesTen为非分布式架构
5 扩展功能 Ignite基于自己特有的分布式架构,开发了完整的企业级分布式架构解决方案,包括分布式内存数据库、流处理技术、分布式计算、分布式服务、分布式数据结构、NoSQL数据库集成、Hadoop和Spark加速等 作为Oracle的商用内存分布式数据库产品,定位明确,功能专注
6 部署模式 支持多种部署模式,支持独立部署,嵌入式部署,也可以部署在云环境中,对Kubernetes等新技术也有广泛的支持 支持嵌入式和独立部署,可以脱离Oracle独立部署为内存分布式数据库。安装配置较为复杂,对于新的技术,云环境等支持较差。
7 客户端协议 支持SQL、ODBC/JDBC、除了Java还支持.NET平台,也支持Python、Ruby、PHP或者NodeJS,也可以考虑使用Ignite的二进制客户端协议 支持SQL和PL/SQL、支持ODBC/JDBC、OCI、ODP .NET,另外许多开源数据库API和适配器也可以与TimesTen一起使用,包括 PHP、node.js、Ruby、Python、Go、R和REST等
8 监控等企业级功能 企业版有完善的监控管理工具、安全、滚动更新、数据中心复制等功能,有完善的图形界面。Ignite本身提供命令行以及部分API,可以进行简单的监控方便运维。 提供命令行界面、图形界面、存储过程、API调用等多种形式的相关支持。
9 开发支持 提供了各种可能的方式方便开发,具体代码改动工作量,取决于架构设计模式以及软件使用方式。已有的代码可能改动较多,也可能改动很少。 对应用开发透明,可以轻易地将TimesTen部署进已有的系统中,代码改动较少。
10
11 12
多平台支持
综合成本 成熟度
支持常见操作系统平台和CPU架构
综合成本较低,技术支持有开源社区技术支持,也可以购买商业技术支持。 目前以每季度发布一个版本的速度快速迭代。
支持常见操作系统平台和CPU架构
Oracle的综合成本高昂,包括软件授权费、技术支持费、培训费用等 TimesTen有近20年的历史,但是TimesTen Scaleout为Oracle的第一款商用内存分布式数据库产品。
内存分布式数据库
序号 对比项目 Ignite TimesTen Scaleout 1 SQL支持 支持兼容ANSI-99的SQL标准,支持DDL、DML语句。 支持兼容ANSI-99的SQL标准,支持DDL、DML语句,透明支持Oracle的相关技术
2 事务 不完整,在键值API层次支持ACID事务,基于经过一阶段提交优化后的二阶段提交机制。SQL层,仅支持原子性。 支持完整的ACID事务、多语句事务、约束和全局二级索引。
3 数据库支持 支持提供JDBC/ODBC协议的传统关系型数据库,包括Oracle,也包括MySQL等其他数据库。 只支持Oracle。
4 数据同步 支持数据库的通读和通写,支持多种数据同步方式,提供开发人员接口,自定义能力强。 有非常完善的数据同步方式。
5 故障恢复 基于WAL和检查点等相关技术,有完善的故障恢复机制。同时也支持通过复制、备份等机制提高可用性。 TimesTen有事务日志和检查点文件存放在磁盘上。当系统重启或者意外宕机,内存数据库可以从检查点文件和事务日志中得到恢复。另外,还可以通过复制技术来提高可用性。
6 数据库模型 键值存储,通过H2引擎提供关系型功能。 关系型数据库
7 并置处理 通过将计算带到数据实际驻留的服务端节点,会在数据实际存储的地方执行高级的业务逻辑或者分布式SQL,甚至关联,避免了昂贵的序列化和网络开销 不支持
8 索引 支持 支持
9 缓存维护操作 使用标准DDL语法,添加了部分专有属性。 专有的CREATE CACHE等语法,需要一段时间的学习。
10
11 12
开发工具
开发便利性 数据预热
支持JDBC协议的工具,都可以接入Ignite。
Ignite为常见的、主流开发框架提供了集成的支持,包括Spring、Hibernate、MyBatis、Spring Data JPA等等。 如果开启了原生持久化,系统重启无需预热数据。
Oracle SQL Developer对TimesTen有更好的支持
仅提供JDBC/ODBC等标准协议的支持。 不支持
扩展特性
在内存分布式SQL数据库功能之外,Ignite相比TimesTen,还提供了大量的扩展特性,比如: 分布式服务 :分布式服务可以在集群中任意部署自定义的服务,可以实现和部署任意服务,比如自定义计数器,ID生成器,分级映射等; 数据注入和流计算 :Ignite流式计算可以以可扩展和容错的方式处理连续不中断的数据流。可以与主要的流处理技术和框架进行集成,比如Kafka、Camel、Storm或者JMS等,它们为基于Ignite的架构带来非常强大的功能; 分布式计算 :分布式计算是通过并行处理的方式来获得更高的性能,更低的延迟以及线性可扩展性,Ignite提供了一组简单的API,在集群内的多台计算机中执行分布式计算和数据处理,该功能针对传统的数据库存储过程,形成了完整的替代方案; 分布式数据结构 :Ignite以分布式的形式支持基于 java.util.concurrent 框架的大部分数据结构。比如,可以在一个节点上使用 java.util.concurrent.BlockingQeque 加入一些东西,然后在另一个节点上获取它。或者有一个分布式的ID生成器,它可以保证所有节点上的ID唯一性; 消息和事件 :Ignite提供了集群范围的高性能的消息功能,支持基于发布-订阅以及直接点对点通信模型的数据交换。当在分布式网格环境中发生各种事件时,Ignite的分布式事件功能可以使应用收到通知。可以自动地收到集群内的本地和远程节点上发生的任务执行、读写和查询操作的通知; 机器学习 :Ignite的机器学习是一套简单、可扩展以及高效的工具,可以构建可预测的机器学习模型,而不需要昂贵的ETL; 大数据组件支持 :Ignite为Apache体系的很多技术提供了广泛的支持,包括与Apache旗下的NoSQL数据库集成,比如Cassandra等,为Hadoop和Spark进行加速等。
3.总结
如果将Ignite作为一个内存分布式数据库,那么从功能性来说,与Oracle的TimesTen Scaleout产品基本对等,TimesTen具有的功能,Ignite大体都有,但是TimesTen Scaleout作为一个专业的内存分布式数据库,在部分功能的细节设计上,在与Oracle产品的功能整合上,做的更好。但就Ignite来说,它不仅仅是一个内存分布式数据库,在已有的系统中,如果引入了Ignite,相当于引入了一个多功能的数据处理平台,为已有系统的未来发展和演进,提供了更多的可能,会极大地增强已有系统的扩展性,保护用户原有的投资。
而如果引入了Oracle的TimesTen软件,会进一步增强与Oracle的绑定,不管是从行业发展的趋势来说,还是从降低大型企业的IT支出成本来说,TimesTen都未必是最佳的选择。
大数据
2018-08-09 20:33:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
线程池详解


线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配、调优和监控,有以下好处:
1、降低资源消耗;
2、提高响应速度;
3、提高线程的可管理性。
Java1.5中引入的Executor框架把任务的提交和执行进行解耦,只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行、被哪个线程执行,以及什么时候执行。
demo

1、 Executors.newFixedThreadPool(10) 初始化一个包含10个线程的线程池executor;
2、通过 executor.execute 方法提交20个任务,每个任务打印当前的线程名;
3、负责执行任务的线程的生命周期都由Executor框架进行管理;
ThreadPoolExecutor
Executors是java线程池的工厂类,通过它可以快速初始化一个符合业务需求的线程池,如 Executors.newFixedThreadPool 方法可以生成一个拥有固定线程数的线程池。

其本质是通过不同的参数初始化一个ThreadPoolExecutor对象,具体参数描述如下:
corePoolSize
线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。
maximumPoolSize
线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;
keepAliveTime
线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间;默认情况下,该参数只在线程数大于corePoolSize时才有用;
unit
keepAliveTime的单位;
workQueue
用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供了如下阻塞队列:
1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
4、priorityBlockingQuene:具有优先级的无界阻塞队列;
threadFactory
创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。

handler
线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:
1、AbortPolicy:直接抛出异常,默认策略;
2、CallerRunsPolicy:用调用者所在的线程来执行任务;
3、DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
4、DiscardPolicy:直接丢弃任务;
当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
Exectors
Exectors工厂类提供了线程池的初始化接口,主要有如下几种:
newFixedThreadPool

初始化一个指定线程数的线程池,其中corePoolSize == maximumPoolSize,使用LinkedBlockingQuene作为阻塞队列,不过当线程池没有可执行任务时,也不会释放线程。
newCachedThreadPool

1、初始化一个可以缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
2、和newFixedThreadPool创建的线程池不同,newCachedThreadPool在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源,当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;
所以,使用该线程池时,一定要注意控制并发的任务数,否则创建大量的线程可能导致严重的性能问题。
newSingleThreadExecutor

初始化的线程池中只有一个线程,如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行,内部使用LinkedBlockingQueue作为阻塞队列。
newScheduledThreadPool

初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使用该线程池定期的同步数据。
实现原理
除了newScheduledThreadPool的内部实现特殊一点之外,其它几个线程池都是基于ThreadPoolExecutor类实现的。
线程池内部状态

其中AtomicInteger变量ctl的功能非常强大:利用低29位表示线程池中线程数,通过高3位表示线程池的运行状态:
1、RUNNING: -1 << COUNT_BITS ,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
2、SHUTDOWN: 0 << COUNT_BITS ,即高3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
3、STOP : 1 << COUNT_BITS ,即高3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;
4、TIDYING : 2 << COUNT_BITS ,即高3位为010;
5、TERMINATED: 3 << COUNT_BITS ,即高3位为011;
任务提交
线程池框架提供了两种方式提交任务,根据不同的业务需求选择不同的方式。
Executor.execute()

通过Executor.execute()方法提交的任务,必须实现Runnable接口,该方式提交的任务不能获取返回值,因此无法判断任务是否执行成功。
ExecutorService.submit()

通过ExecutorService.submit()方法提交的任务,可以获取任务执行完的返回值。
任务执行
当向线程池中提交一个任务,线程池会如何处理该任务?
execute实现

具体的执行流程如下:
1、workerCountOf方法根据ctl的低29位,得到线程池的当前线程数,如果线程数小于corePoolSize,则执行addWorker方法创建新的线程执行任务;否则执行步骤(2);
2、如果线程池处于RUNNING状态,且把提交的任务成功放入阻塞队列中,则执行步骤(3),否则执行步骤(4);
3、再次检查线程池的状态,如果线程池没有RUNNING,且成功从阻塞队列中删除任务,则执行reject方法处理任务;
4、执行addWorker方法创建新的线程执行任务,如果addWoker执行失败,则执行reject方法处理任务;

addWorker实现
从方法execute的实现可以看出:addWorker主要负责创建新的线程并执行任务,代码实现如下:

这只是addWoker方法实现的前半部分:
1、判断线程池的状态,如果线程池的状态值大于或等SHUTDOWN,则不处理提交的任务,直接返回;
2、通过参数core判断当前需要创建的线程是否为核心线程,如果core为true,且当前线程数小于corePoolSize,则跳出循环,开始创建新的线程,具体实现如下:

线程池的工作线程通过Woker类实现,在ReentrantLock锁的保证下,把Woker实例插入到HashSet后,并启动Woker中的线程,其中Worker类设计如下:
1、继承了AQS类,可以方便的实现工作线程的中止操作;
2、实现了Runnable接口,可以将自身作为一个任务在工作线程中执行;
3、当前提交的任务firstTask作为参数传入Worker的构造方法;

从Woker类的构造方法实现可以发现:线程工厂在创建线程thread时,将Woker实例本身this作为参数传入,当执行start方法启动线程thread时,本质是执行了Worker的runWorker方法。
runWorker实现

runWorker方法是线程池的核心:
1、线程启动之后,通过unlock方法释放锁,设置AQS的state为0,表示运行中断;
2、获取第一个任务firstTask,执行任务的run方法,不过在执行任务之前,会进行加锁操作,任务执行完会释放锁;
3、在执行任务的前后,可以根据业务场景自定义beforeExecute和afterExecute方法;
4、firstTask执行完成之后,通过getTask方法从阻塞队列中获取等待的任务,如果队列中没有任务,getTask方法会被阻塞并挂起,不会占用cpu资源;
getTask实现

整个getTask操作在自旋下完成:
1、workQueue.take:如果阻塞队列为空,当前线程会被挂起等待;当队列中有任务加入时,线程被唤醒,take方法返回任务,并执行;
2、workQueue.poll:如果在keepAliveTime时间内,阻塞队列还是没有任务,则返回null;
所以,线程池中实现的线程可以一直执行由用户提交的任务。
Future和Callable实现
通过ExecutorService.submit()方法提交的任务,可以获取任务执行完的返回值。

在实际业务场景中,Future和Callable基本是成对出现的,Callable负责产生结果,Future负责获取结果。
1、Callable接口类似于Runnable,只是Runnable没有返回值。
2、Callable任务除了返回正常结果之外,如果发生异常,该异常也会被返回,即Future可以拿到异步执行任务各种结果;
3、Future.get方法会导致主线程阻塞,直到Callable任务执行完成;
submit实现

通过submit方法提交的Callable任务会被封装成了一个FutureTask对象。
FutureTask

1、FutureTask在不同阶段拥有不同的状态state,初始化为NEW;
2、FutureTask类实现了Runnable接口,这样就可以通过Executor.execute方法提交FutureTask到线程池中等待被执行,最终执行的是FutureTask的run方法;
FutureTask.get实现

内部通过awaitDone方法对主线程进行阻塞,具体实现如下:

1、如果主线程被中断,则抛出中断异常;
2、判断FutureTask当前的state,如果大于COMPLETING,说明任务已经执行完成,则直接返回;
3、如果当前state等于COMPLETING,说明任务已经执行完,这时主线程只需通过yield方法让出cpu资源,等待state变成NORMAL;
4、通过WaitNode类封装当前线程,并通过UNSAFE添加到waiters链表;
5、最终通过LockSupport的park或parkNanos挂起线程;
FutureTask.run实现

FutureTask.run方法是在线程池中被执行的,而非主线程
1、通过执行Callable任务的call方法;
2、如果call执行成功,则通过set方法保存结果;
3、如果call执行有异常,则通过setException保存异常;
set

setException

set和setException方法中,都会通过UnSAFE修改FutureTask的状态,并执行finishCompletion方法通知主线程任务已经执行完成;
finishCompletion

1、执行FutureTask类的get方法时,会把主线程封装成WaitNode节点并保存在waiters链表中;
2、FutureTask任务执行完成后,通过UNSAFE设置waiters的值,并通过LockSupport类unpark方法唤醒主线程;
大数据
2018-08-09 07:12:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
一、先从redis-trib.rb的help信息,看下redis-trib.rb提供了哪些功能。
$ruby redis-trib.rb help Usage: redis-trib 1.create:创建集群 create host1:port1 ... hostN:portN --replicas 2.check:检查集群 check host:port 3.info:查看集群信息 info host:port 4.fix:修复集群 fix host:port --timeout 5.reshard:在线迁移slot reshard host:port --from --to --slots --yes --timeout --pipeline 6.rebalance:平衡集群节点slot数量 rebalance host:port --weight --auto-weights --threshold --use-empty-masters --timeout --simulate --pipeline 7.add-node:将新节点加入集群 add-node new_host:new_port existing_host:existing_port --slave --master-id 8.del-node:从集群中删除节点 del-node host:port node_id 9.set-timeout:设置集群节点间心跳连接的超时时间 set-timeout host:port milliseconds 10.call:在集群全部节点上执行命令 call host:port command arg arg .. arg 11.import:将外部redis数据导入集群 import host:port --from --copy --replace help (show this help) For check, fix, reshard, del -node, set-timeout you can specify the host and port of any working node in the cluster.

二、下面从redis-trib.rb使用和源码的角度详细介绍redis-trib.rb的每个功能。
redis-trib.rb主要有两个类:ClusterNode和RedisTrib。ClusterNode保存了每个节点的信息,RedisTrib则是redis-trib.rb各个功能的实现。 ClusterNode对象 先分析ClusterNode源码。ClusterNode有下面几个成员变量(ruby的类成员变量是以@开头的): @r:执行redis命令的客户端对象。 @info:保存了该节点的详细信息,包括cluster nodes命令中自己这行的信息和cluster info的信息。 @dirty:节点信息是否需要更新,如果为true,我们需要把内存的节点更新信息到节点上。 @friends:保存了集群其他节点的info信息。其信息为通过cluster nodes命令获得的其他节点信息。 ClusterNode有下面一些成员方法: initialize:ClusterNode的构造方法,需要传入节点的地址信息。 friends:返回@friends对象。 slots:返回该节点负责的slots信息。 has_flag?:判断节点info信息的的flags中是否有给定的flag。 to_s:类似java的toString方法,返回节点的地址信息。 connect:连接redis节点。 assert_cluster:判断节点开启了集群配置。 assert_empty:确定节点目前没有跟任何其他节点握手,同时自己的db数据为空。 load_info:通过cluster info和cluster nodes导入节点信息。 add_slots:给节点增加slot,该操作只是在内存中修改,并把dirty设置成true,等待flush_node_config将内存中的数据同步在节点执行。 set_as_replica:slave设置复制的master地址。dirty设置成true。 flush_node_config:将内存的数据修改同步在集群节点中执行。 info_string:简单的info信息。 get_config_signature:用来验证集群节点见的cluster nodes信息是否一致。该方法返回节点的签名信息。 info:返回@info对象,包含详细的info信息。 is_dirty?:判断@dirty。 r:返回执行redis命令的客户端对象。 有了ClusterNode对象,在处理集群操作的时候,就获得了集群的信息,可以进行集群相关操作。在此先简单介绍下redis-trib.rb脚本的使用,以create为例: create host1:port1 ... hostN:portN --replicas host1:port1 ... hostN:portN表示子参数,这个必须在可选参数之后,--replicas 是可选参数,带的表示后面必须填写一个参数,像--slave这样,后面就不带参数,掌握了这个基本规则,就能从help命令中获得redis-trib.rb的使用方法。 其他命令大都需要传递host:port,这是redis-trib.rb为了连接集群,需要选择集群中的一个节点,然后通过该节点获得整个集群的信息。

三、详细介绍redis-trib.rb的每个功能。
3.1 create创建集群
Usage: redis-trib create host1:port1 ... hostN:portN --replicas create命令可选replicas参数,replicas表示需要有几个slave。 最简单命令使用如下: $ruby redis-trib.rb create 10.180.157.199:6379 10.180.157.200:6379 10.180.157.201:6379 有一个slave的创建命令如下: $ruby redis-trib.rb create --replicas 1 10.180.157.199:6379 10.180.157.200:6379 10.180.157.201:6379 10.180.157.202:6379 10.180.157.205:6379 10.180.157.208:6379 创建流程如下: 1、首先为每个节点创建ClusterNode对象,包括连接每个节点。检查每个节点是否为独立且db为空的节点。执行load_info方法导入节点信息。 2、检查传入的master节点数量是否大于等于3个。 只有大于3个节点才能组成集群 。 3、计算每个master需要分配的slot数量,以及给master分配slave。分配的算法大致如下: 先把节点按照host分类,这样保证master节点能分配到更多的主机中。 不停遍历遍历host列表,从每个host列表中弹出一个节点,放入interleaved数组。直到所有的节点都弹出为止。 master节点列表就是interleaved前面的master数量的节点列表。保存在masters数组。 计算每个master节点负责的slot数量,保存在slots_per_node对象,用slot总数除以master数量取整即可。 遍历masters数组,每个master分配slots_per_node个slot,最后一个master,分配到16384个slot为止。 接下来为master分配slave,分配算法会尽量保证master和slave节点不在同一台主机上。对于分配完指定slave数量的节点,还有多余的节点,也会为这些节点寻找master。分配算法会遍历两次masters数组。 第一次遍历masters数组,在余下的节点列表找到replicas数量个slave。每个slave为第一个和master节点host不一样的节点,如果没有不一样的节点,则直接取出余下列表的第一个节点。 第二次遍历是在对于节点数除以replicas不为整数,则会多余一部分节点。遍历的方式跟第一次一样,只是第一次会一次性给master分配replicas数量个slave,而第二次遍历只分配一个,直到余下的节点被全部分配出去。 4、打印出分配信息,并提示用户输入“yes”确认是否按照打印出来的分配方式创建集群。 5、输入“yes”后,会执行flush_nodes_config操作,该操作执行前面的分配结果,给master分配slot,让slave复制master,对于还没有握手(cluster meet)的节点,slave复制操作无法完成,不过没关系,flush_nodes_config操作出现异常会很快返回,后续握手后会再次执行flush_nodes_config。 6、给每个节点分配epoch,遍历节点,每个节点分配的epoch比之前节点大1。 7、节点间开始相互握手,握手的方式为节点列表的其他节点跟第一个节点握手。 8、然后每隔1秒检查一次各个节点是否已经消息同步完成,使用ClusterNode的get_config_signature方法,检查的算法为获取每个节点cluster nodes信息,排序每个节点,组装成node_id1:slots|node_id2:slot2|...的字符串。如果每个节点获得字符串都相同,即认为握手成功。 9、此后会再执行一次flush_nodes_config,这次主要是为了完成slave复制操作。 10、最后再执行check_cluster,全面检查一次集群状态。包括和前面握手时检查一样的方式再检查一遍。确认没有迁移的节点。确认所有的slot都被分配出去了。 11、至此完成了整个创建流程,返回[OK] All 16384 slots covered.。

3.2 check检查集群
Usage: redis-trib check host:port 检查集群状态的命令,没有其他参数,只需要选择一个集群中的一个节点即可。 执行命令以及结果如下: $ruby redis-trib.rb check 10.180.157.199:6379 >>> Performing Cluster Check (using node 10.180.157.199:6379) M: b2506515b38e6bbd3034d540599f4cd2a5279ad1 10.180.157.199:6379 slots:0-5460 (5461 slots) master 1 additional replica(s) S: d376aaf80de0e01dde1f8cd4647d5ac3317a8641 10.180.157.205:6379 slots: (0 slots) slave replicates e36c46dbe90960f30861af00786d4c2064e63df2 M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: 59fa6ee455f58a5076f6d6f83ddd74161fd7fb55 10.180.157.208:6379 slots: (0 slots) slave replicates 15126fb33796c2c26ea89e553418946f7443d5a5 S: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379 slots: (0 slots) slave replicates b2506515b38e6bbd3034d540599f4cd2a5279ad1 M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379 slots:5461-10922 (5462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. 检查前会先执行load_cluster_info_from_node方法,把所有节点数据load进来。load的方式为通过自己的cluster nodes发现其他节点,然后连接每个节点,并加入nodes数组。接着生成节点间的复制关系。 load完数据后,开始检查数据,检查的方式也是调用创建时候使用的check_cluster。

3.3 info查看集群信息
Usage: redis-trib info host:port info命令用来查看集群的信息。info命令也是先执行load_cluster_info_from_node获取完整的集群信息。然后显示ClusterNode的info_string结果 ,示例如下: $ruby redis-trib.rb info 10.180.157.199:6379 10.180.157.199:6379 (b2506515...) -> 0 keys | 5461 slots | 1 slaves. 10.180.157.201:6379 (15126fb3...) -> 0 keys | 5461 slots | 1 slaves. 10.180.157.200:6379 (e36c46db...) -> 0 keys | 5462 slots | 1 slaves. [OK] 0 keys in 3 masters. 0.00 keys per slot on average.

3.4 fix修复集群
Usage: redis-trib fix host:port --timeout fix命令的流程跟check的流程很像,显示加载集群信息,然后在check_cluster方法内传入fix为true的变量,会在集群检查出现异常的时候执行修复流程。 目前fix命令能修复两种异常,一种是集群有处于迁移中的slot的节点,一种是slot未完全分配的异常。 fix_open_slot方法是修复集群有 处于迁移中的slot的节点异常 。 1、先检查该slot是谁负责的,迁移的源节点如果没完成迁移,owner还是该节点。没有owner的slot无法完成修复功能。 2、遍历每个节点,获取哪些节点标记该slot为migrating状态,哪些节点标记该slot为importing状态。对于owner不是该节点,但是通过cluster countkeysinslot获取到该节点有数据的情况,也认为该节点为importing状态。 3、如果migrating和importing状态的节点均只有1个,这可能是迁移过程中redis-trib.rb被中断所致,直接执行move_slot继续完成迁移任务即可。传递dots和fix为true。 4、如果migrating为空,importing状态的节点大于0,那么这种情况执行回滚流程,将importing状态的节点数据通过move_slot方法导给slot的owner节点,传递dots、fix和cold为true。接着对importing的节点执行cluster stable命令恢复稳定。 5、如果importing状态的节点为空,有一个migrating状态的节点,而且该节点在当前slot没有数据,那么可以直接把这个slot设为stable。 6、如果migrating和importing状态不是上述情况,目前redis-trib.rb工具无法修复,上述的三种情况也已经覆盖了通过redis-trib.rb工具迁移出现异常的各个方面,人为的异常情形太多,很难考虑完全。 fix_slots_coverage方法能 修复slot未完全分配的异常 。未分配的slot有三种状态。 1、所有节点的该slot都没有数据。该状态redis-trib.rb工具直接采用随机分配的方式,并没有考虑节点的均衡。本人尝试对没有分配slot的集群通过fix修复集群,结果slot还是能比较平均的分配,但是没有了连续性,打印的slot信息非常离散。 2、有一个节点的该slot有数据。该状态下,直接把slot分配给该slot有数据的节点。 3、有多个节点的该slot有数据。此种情况目前还处于TODO状态,不过redis作者列出了修复的步骤,对这些节点,除第一个节点,执行cluster migrating命令,然后把这些节点的数据迁移到第一个节点上。清除migrating状态,然后把slot分配给第一个节点。

3.5 reshard在线迁移slot
Usage: redis-trib reshard host:port --from --to --slots --yes --timeout --pipeline reshard命令可以在线把集群的一些slot从集群原来slot负责节点迁移到新的节点,利用reshard可以完成集群的在线横向扩容和缩容。 reshard的参数很多,下面来一一解释一番: host:port:这个是必传参数,用来从一个节点获取整个集群信息,相当于获取集群信息的入口。 --from :需要从哪些源节点上迁移slot,可从多个源节点完成迁移,以逗号隔开,传递的是节点的node id,还可以直接传递--from all,这样源节点就是集群的所有节点,不传递该参数的话,则会在迁移过程中提示用户输入。 --to :slot需要迁移的目的节点的node id,目的节点只能填写一个,不传递该参数的话,则会在迁移过程中提示用户输入。 --slots :需要迁移的slot数量,不传递该参数的话,则会在迁移过程中提示用户输入。 --yes:设置该参数,可以在打印执行reshard计划的时候,提示用户输入yes确认后再执行reshard。 --timeout :设置migrate命令的超时时间。 --pipeline :定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10。 迁移的流程如下: 1、通过load_cluster_info_from_node方法装载集群信息。 2、执行check_cluster方法检查集群是否健康。只有健康的集群才能进行迁移。 3、获取需要迁移的slot数量,用户没传递--slots参数,则提示用户手动输入。 4、获取迁移的目的节点,用户没传递--to参数,则提示用户手动输入。此处会检查目的节点必须为master节点。 5、获取迁移的源节点,用户没传递--from参数,则提示用户手动输入。此处会检查源节点必须为master节点。--from all的话,源节点就是除了目的节点外的全部master节点。这里为了保证集群slot分配的平均,建议传递--from all。 6、执行compute_reshard_table方法,计算需要迁移的slot数量如何分配到源节点列表,采用的算法是按照节点负责slot数量由多到少排序,计算每个节点需要迁移的slot的方法为:迁移slot数量 * (该源节点负责的slot数量 / 源节点列表负责的slot总数)。这样算出的数量可能不为整数,这里代码用了下面的方式处理: n = (numslots/source_tot_slots*s.slots.length) if i == 0 n = n.ceil else n = n.floor 这样的处理方式会带来最终分配的slot与请求迁移的slot数量不一致,这个BUG已经在github上提给作者,https://github.com/antirez/redis/issues/2990。 7、打印出reshard计划,如果用户没传--yes,就提示用户确认计划。 8、根据reshard计划,一个个slot的迁移到新节点上,迁移使用move_slot方法,该方法被很多命令使用,具体可以参见下面的迁移流程。move_slot方法传递dots为true和pipeline数量。 9、至此,就完成了全部的迁移任务。 下面看下一次reshard的执行结果: $ruby redis-trib.rb reshard --from all --to 80b661ecca260c89e3d8ea9b98f77edaeef43dcd --slots 11 10.180.157.199:6379 >>> Performing Cluster Check (using node 10.180.157.199:6379) S: b2506515b38e6bbd3034d540599f4cd2a5279ad1 10.180.157.199:6379 slots: (0 slots) slave replicates 460b3a11e296aafb2615043291b7dd98274bb351 S: d376aaf80de0e01dde1f8cd4647d5ac3317a8641 10.180.157.205:6379 slots: (0 slots) slave replicates e36c46dbe90960f30861af00786d4c2064e63df2 M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: 59fa6ee455f58a5076f6d6f83ddd74161fd7fb55 10.180.157.208:6379 slots: (0 slots) slave replicates 15126fb33796c2c26ea89e553418946f7443d5a5 M: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379 slots:0-5460 (5461 slots) master 1 additional replica(s) M: 80b661ecca260c89e3d8ea9b98f77edaeef43dcd 10.180.157.200:6380 slots: (0 slots) master 0 additional replica(s) M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379 slots:5461-10922 (5462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. Ready to move 11 slots. Source nodes: M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379 slots:10923-16383 (5461 slots) master 1 additional replica(s) M: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379 slots:0-5460 (5461 slots) master 1 additional replica(s) M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379 slots:5461-10922 (5462 slots) master 1 additional replica(s) Destination node: M: 80b661ecca260c89e3d8ea9b98f77edaeef43dcd 10.180.157.200:6380 slots: (0 slots) master 0 additional replica(s) Resharding plan: Moving slot 5461 from e36c46dbe90960f30861af00786d4c2064e63df2 Moving slot 5462 from e36c46dbe90960f30861af00786d4c2064e63df2 Moving slot 5463 from e36c46dbe90960f30861af00786d4c2064e63df2 Moving slot 5464 from e36c46dbe90960f30861af00786d4c2064e63df2 Moving slot 0 from 460b3a11e296aafb2615043291b7dd98274bb351 Moving slot 1 from 460b3a11e296aafb2615043291b7dd98274bb351 Moving slot 2 from 460b3a11e296aafb2615043291b7dd98274bb351 Moving slot 10923 from 15126fb33796c2c26ea89e553418946f7443d5a5 Moving slot 10924 from 15126fb33796c2c26ea89e553418946f7443d5a5 Moving slot 10925 from 15126fb33796c2c26ea89e553418946f7443d5a5 Do you want to proceed with the proposed reshard plan (yes/no)? yes Moving slot 5461 from 10.180.157.200:6379 to 10.180.157.200:6380: Moving slot 5462 from 10.180.157.200:6379 to 10.180.157.200:6380: Moving slot 5463 from 10.180.157.200:6379 to 10.180.157.200:6380: Moving slot 5464 from 10.180.157.200:6379 to 10.180.157.200:6380: Moving slot 0 from 10.180.157.202:6379 to 10.180.157.200:6380: Moving slot 1 from 10.180.157.202:6379 to 10.180.157.200:6380: Moving slot 2 from 10.180.157.202:6379 to 10.180.157.200:6380: Moving slot 10923 from 10.180.157.201:6379 to 10.180.157.200:6380: Moving slot 10924 from 10.180.157.201:6379 to 10.180.157.200:6380: Moving slot 10925 from 10.180.157.201:6379 to 10.180.157.200:6380: move_slot方法可以在线将一个slot的全部数据从源节点迁移到目的节点,fix、reshard、rebalance都需要调用该方法迁移slot。 move_slot接受下面几个参数, 1、pipeline:设置一次从slot上获取多少个key。 2、quiet:迁移会打印相关信息,设置quiet参数,可以不用打印这些信息。 3、cold:设置cold,会忽略执行importing和migrating。 4、dots:设置dots,则会在迁移过程打印迁移key数量的进度。 5、update:设置update,则会更新内存信息,方便以后的操作。 move_slot流程如下: 1、如果没有设置cold,则对源节点执行cluster importing命令,对目的节点执行migrating命令。fix的时候有可能importing和migrating已经执行过来,所以此种场景会设置cold。 2、通过cluster getkeysinslot命令,一次性获取远节点迁移slot的pipeline个key的数量. 3、对这些key执行migrate命令,将数据从源节点迁移到目的节点。 4、如果migrate出现异常,在fix模式下,BUSYKEY的异常,会使用migrate的replace模式再执行一次,BUSYKEY表示目的节点已经有该key了,replace模式可以强制替换目的节点的key。不是fix模式就直接返回错误了。 5、循环执行cluster getkeysinslot命令,直到返回的key数量为0,就退出循环。 6、如果没有设置cold,对每个节点执行cluster setslot命令,把slot赋给目的节点。 7、如果设置update,则修改源节点和目的节点的slot信息。 8、至此完成了迁移slot的流程。

3.6 rebalance平衡集群节点slot数量
Usage: redis-trib rebalance host:port --weight --auto-weights --threshold --use-empty-masters --timeout --simulate --pipeline
rebalance命令可以根据用户传入的参数平衡集群节点的slot数量 ,rebalance功能非常强大,可以传入的参数很多,以下是rebalance的参数列表和命令示例。 $ruby redis-trib.rb rebalance --threshold 1 --weight b31e3a2e=5 --weight 60b8e3a1=5 --use-empty-masters --simulate 10.180.157.199:6379 下面也先一一解释下每个参数的用法: host:port:这个是必传参数,用来从一个节点获取整个集群信息,相当于获取集群信息的入口。 --weight :节点的权重,格式为node_id=weight,如果需要为多个节点分配权重的话,需要添加多个--weight 参数,即--weight b31e3a2e=5 --weight 60b8e3a1=5,node_id可为节点名称的前缀,只要保证前缀位数能唯一区分该节点即可。 没有传递–weight的节点的权重默认为1 。 --auto-weights:这个参数在rebalance流程中并未用到。 --threshold :只有节点需要迁移的slot阈值超过threshold,才会执行rebalance操作。具体计算方法可以参考下面的rebalance命令流程的第四步。 --use-empty-masters:rebalance是否考虑没有节点的master,默认没有分配slot节点的master是不参与rebalance的,设置--use-empty-masters可以让没有分配slot的节点参与rebalance。 --timeout :设置migrate命令的超时时间。 --simulate:设置该参数,可以模拟rebalance操作,提示用户会迁移哪些slots,而不会真正执行迁移操作。 --pipeline :与reshar的pipeline参数一样,定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10。 rebalance命令流程如下: 1、load_cluster_info_from_node方法先加载集群信息。 2、计算每个master的权重,根据参数--weight ,为每个设置的节点分配权重,没有设置的节点,则权重默认为1。 3、根据每个master的权重,以及总的权重,计算自己期望被分配多少个slot。计算的方式为:总slot数量 * (自己的权重 / 总权重)。 4、计算每个master期望分配的slot是否超过设置的阈值,即--threshold 设置的阈值或者默认的阈值。计算的方式为:先计算期望移动节点的阈值,算法为:(100-(100.0*expected/n.slots.length)).abs,如果计算出的阈值没有超出设置阈值,则不需要为该节点移动slot。只要有一个master的移动节点超过阈值,就会触发rebalance操作。 5、如果触发了rebalance操作。那么就开始执行rebalance操作,先将每个节点当前分配的slots数量减去期望分配的slot数量获得balance值。将每个节点的balance从小到大进行排序获得sn数组。 6、用dst_idx和src_idx游标分别从sn数组的头部和尾部开始遍历。目的是为了把尾部节点的slot分配给头部节点。 sn数组保存的balance列表排序后,负数在前面,正数在后面。负数表示需要有slot迁入,所以使用dst_idx游标,正数表示需要有slot迁出,所以使用src_idx游标。 理论上sn数组各节点的balance值加起来应该为0,不过由于在计算期望分配的slot的时候只是使用直接取整的方式,所以可能出现balance值之和不为0的情况, balance值之和不为0即为节点不平衡的slot数量,由于slot总数有16384个,不平衡数量相对于总数,基数很小,所以对rebalance流程影响不大。 7、获取sn[dst_idx]和sn[src_idx]的balance值较小的那个值,该值即为需要从sn[src_idx]节点迁移到sn[dst_idx]节点的slot数量。 8、接着通过compute_reshard_table方法计算源节点的slot如何分配到源节点列表。这个方法在reshard流程中也有调用,具体步骤可以参考reshard流程的第六步。 9、如果是simulate模式,则只是打印出迁移列表。 10、如果没有设置simulate,则执行move_slot操作,迁移slot,传入的参数为:quiet=>true,:dots=>false,:update=>true。 11、迁移完成后更新sn[dst_idx]和sn[src_idx]的balance值。如果balance值为0后,游标向前进1。 12、直到dst_idx到达src_idx游标,完成整个rebalance操作。

3.7 add-node将新节点加入集群
Usage: redis-trib add-node new_host:new_port existing_host:existing_port --slave --master-id add-node命令可以将新节点加入集群,节点可以为master,也可以为某个master节点的slave。 add-node有两个可选参数: --slave:设置该参数,则新节点以slave的角色加入集群 --master-id:这个参数需要设置了--slave才能生效,--master-id用来指定新节点的master节点。如果不设置该参数,则会随机为节点选择master节点。 可以看下add-node命令的执行示例: $ruby redis-trib.rb add-node --slave --master-id dcb792b3e85726f012e83061bf237072dfc45f99 10.180.157.202:6379 10.180.157.199:6379 >>> Adding node 10.180.157.202:6379 to cluster 10.180.157.199:6379 >>> Performing Cluster Check (using node 10.180.157.199:6379) M: dcb792b3e85726f012e83061bf237072dfc45f99 10.180.157.199:6379 slots:0-5460 (5461 slots) master 0 additional replica(s) M: 464d740bf48953ebcf826f4113c86f9db3a9baf3 10.180.157.201:6379 slots:10923-16383 (5461 slots) master 0 additional replica(s) M: befa7e17b4e5f239e519bc74bfef3264a40f96ae 10.180.157.200:6379 slots:5461-10922 (5462 slots) master 0 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. >>> Send CLUSTER MEET to node 10.180.157.202:6379 to make it join the cluster. Waiting for the cluster to join. >>> Configure node as replica of 10.180.157.199:6379. [OK] New node added correctly. add-node流程如下: 1、通过load_cluster_info_from_node方法转载集群信息,check_cluster方法检查集群是否健康。 2、如果设置了--slave,则需要为该节点寻找master节点。设置了--master-id,则以该节点作为新节点的master,如果没有设置--master-id,则调用get_master_with_least_replicas方法,寻找slave数量最少的master节点。如果slave数量一致,则选取load_cluster_info_from_node顺序发现的第一个节点。load_cluster_info_from_node顺序的第一个节点是add-node设置的existing_host:existing_port节点,后面的顺序根据在该节点执行cluster nodes返回的结果返回的节点顺序。 3、连接新的节点并与集群第一个节点握手。 4、如果没设置–slave就直接返回ok,设置了–slave,则需要等待确认新节点加入集群,然后执行cluster replicate命令复制master节点。 5、至此,完成了全部的增加节点的流程。

3.8 del-node从集群中删除节点
Usage: redis-trib del-node host:port node_id del-node可以把某个节点从集群中删除。del-node只能删除没有分配slot的节点 。 del-node执行结果示例如下: $ruby redis-trib.rb del-node 10.180.157.199:6379 d5f6d1d17426bd564a6e309f32d0f5b96962fe53 >>> Removing node d5f6d1d17426bd564a6e309f32d0f5b96962fe53 from cluster 10.180.157.199:6379 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node. del-node流程如下: 1、通过load_cluster_info_from_node方法转载集群信息。 2、根据传入的node id获取节点,如果节点没找到,则直接提示错误并退出。 3、如果节点分配的slot不为空,则直接提示错误并退出。 4、遍历集群内的其他节点,执行cluster forget命令,从每个节点中去除该节点。如果删除的节点是master,而且它有slave的话,这些slave会去复制其他master,调用的方法是get_master_with_least_replicas,与add-node没设置--master-id寻找master的方法一样。
5、然后关闭该节点

3.9 set-timeout设置集群节点间心跳连接的超时时间
Usage: redis-trib set-timeout host:port milliseconds set-timeout用来设置集群节点间心跳连接的超时时间,单位是毫秒,不得小于100毫秒,因为100毫秒对于心跳时间来说太短了。 该命令修改是节点配置参数cluster-node-timeout,默认是15000毫秒。通过该命令,可以给每个节点设置超时时间,设置的方式使用config set命令动态设置,然后执行config rewrite命令将配置持久化保存到硬盘。 以下是示例: ruby redis-trib.rb set-timeout 10.180.157.199:6379 30000 >>> Reconfiguring node timeout in every cluster node... *** New timeout set for 10.180.157.199:6379 *** New timeout set for 10.180.157.205:6379 *** New timeout set for 10.180.157.201:6379 *** New timeout set for 10.180.157.200:6379 *** New timeout set for 10.180.157.208:6379 >>> New node timeout set. 5 OK, 0 ERR.

3.10 call在集群全部节点上执行命令
Usage: redis-trib call host:port command arg arg .. arg call命令可以用来在集群的全部节点执行相同的命令。call命令也是需要通过集群的一个节点地址,连上整个集群,然后在集群的每个节点执行该命令 。 $ruby redis-trib.rb call 10.180.157.199:6379 get key >>> Calling GET key 10.180.157.199:6379: MOVED 12539 10.180.157.201:6379 10.180.157.205:6379: MOVED 12539 10.180.157.201:6379 10.180.157.201:6379: 10.180.157.200:6379: MOVED 12539 10.180.157.201:6379 10.180.157.208:6379: MOVED 12539 10.180.157.201:6379

3.11 import将外部redis数据导入集群
Usage: redis-trib import host:port --from --copy --replace
import命令可以把外部的redis节点数据导入集群。 导入的流程如下:
1、通过load_cluster_info_from_node方法转载集群信息,check_cluster方法检查集群是否健康。
2、连接外部redis节点,如果外部节点开启了cluster_enabled,则提示错误。
3、通过scan命令遍历外部节点,一次获取1000条数据。
4、遍历这些key,计算出key对应的slot。
5、执行migrate命令,源节点是外部节点,目的节点是集群slot对应的节点,如果设置了--copy参数,则传递copy参数,如果设置了--replace,则传递replace参数。
6、不停执行scan命令,直到遍历完全部的key。
7、至此完成整个迁移流程
这中间如果出现异常,程序就会停止。没使用--copy模式,则可以重新执行import命令,使用--copy的话,最好清空新的集群再导入一次。

import命令更适合离线的把外部redis数据导入,在线导入的话最好使用更专业的导入工具,以slave的方式连接redis节点去同步节点数据应该是更好的方式。
下面是一个例子
./redis-trib.rb import --from 10.0.10.1:6379 10.10.10.1:7000
上面的命令是把 10.0.10.1:6379(redis 2.8)上的数据导入到 10.10.10.1:7000这个节点所在的集群
大数据
2018-08-08 18:00:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Hive on Mapreduce Hive的原理大家可以参考这篇 大数据时代的技术hive:hive介绍 ,实际的一些操作可以看这篇 笔记:新手的Hive指南 ,至于还有兴趣看Hive优化方法可以看看我总结的这篇 Hive性能优化上的一些总结
Hive on Mapreduce执行流程
执行流程详细解析 Step 1:UI(user interface) 调用 executeQuery 接口,发送 HQL 查询语句给 Driver Step 2:Driver 为查询语句创建会话句柄,并将查询语句发送给 Compiler, 等待其进行语句解析并生成执行计划 Step 3 and 4:Compiler 从 metastore 获取相关的元数据 Step 5:元数据用于对查询树中的表达式进行类型检查,以及基于查询谓词调整分区,生成计划 Step 6 (6.1,6.2,6.3):由 Compiler 生成的执行计划是阶段性的 DAG,每个阶段都可能会涉及到 Map/Reduce job、元数据的操作、HDFS 文件的操作,Execution Engine 将各个阶段的 DAG 提交给对应的组件执行。 Step 7, 8 and 9:在每个任务(mapper / reducer)中,查询结果会以临时文件的方式存储在 HDFS 中。保存查询结果的临时文件由 Execution Engine 直接从 HDFS 读取,作为从 Driver Fetch API 的返回内容。
Hive on Mapreduce特点 关系数据库里,表的加载模式是在数据加载时候强制确定的(表的加载模式是指数据库存储数据的文件格式),如果加载数据时候发现加载的数据不符合模式,关系数据库则会拒绝加载数据,这个就叫“写时模式”,写时模式会在数据加载时候对数据模式进行检查校验的操作。 Hive在加载数据时候和关系数据库不同,hive在加载数据时候不会对数据进行检查,也不会更改被加载的数据文件,而检查数据格式的操作是在查询操作时候执行,这种模式叫“读时模式”。 在实际应用中,写时模式在加载数据时候会对列进行索引,对数据进行压缩,因此加载数据的速度很慢,但是当数据加载好了,我们去查询数据的时候,速度很快。但是当我们的数据是非结构化,存储模式也是未知时候,关系数据操作这种场景就麻烦多了,这时候hive就会发挥它的优势。 关系数据库一个重要的特点是可以对某一行或某些行的数据进行更新、删除操作,hive**不支持 对某个具体行的操作,hive对数据的操作 只支持覆盖原数据和追加数据**。Hive也不支持事务和索引。更新、事务和索引都是关系数据库的特征,这些hive都不支持,也不打算支持,原因是hive的设计是海量数据进行处理,全数据的扫描时常态,针对某些具体数据进行操作的效率是很差的,对于更新操作,hive是通过查询将原表的数据进行转化最后存储在新表里,这和传统数据库的更新操作有很大不同。 Hive也可以在hadoop做实时查询上做一份自己的贡献,那就是和hbase集成,hbase可以进行快速查询,但是 hbase不支持类SQL 的语句,那么此时hive可以给hbase提供sql语法解析的外壳,可以用类sql语句操作hbase数据库。 Hive可以认为是MapReduce的一个封装、包装。Hive的意义就是在业务分析中将用户容易编写、会写的Sql语言转换为复杂难写的MapReduce程序,从而大大降低了Hadoop学习的门槛,让更多的用户可以利用Hadoop进行数据挖掘分析。 与传统数据库之间对比—From: Hive和传统数据库进行比较
比较项 SQL HiveQL ANSI SQL 支持 不完全支持
更新 UPDATE\INSERT\DELETE insert OVERWRITE\INTO TABLE
事务 支持 不支持
模式 写模式 读模式
数据保存 块设备、本地文件系统 HDFS
延时
多表插入 不支持 支持
子查询 完全支持 只能用在From子句中
视图 Updatable Read-only
可扩展性
数据规模
….
……
……
SparkSQL
SparkSQL简介 SparkSQL的前身是Shark,给熟悉RDBMS但又不理解MapReduce的技术人员提供快速上手的工具, hive 应运而生,它是当时唯一运行在 Hadoop 上的SQL-on- hadoop 工具。但是MapReduce计算过程中大量的中间磁盘落地过程消耗了大量的I/O,降低的运行效率,为了提高SQL-on-Hadoop的效率,Shark应运而生,但又因为Shark对于Hive的太多依赖(如采用Hive的语法解析器、查询优化器等等),2014年spark团队停止对Shark的开发,将所有资源放SparkSQL项目上
​ 其中SparkSQL作为Spark生态的一员继续发展, 而不再受限于Hive,只是兼容Hive;而Hive on Spark是一个Hive的发展计划,该计划将Spark作为Hive的底层引擎之一,也就是说,Hive将不再受限于一个引擎,可以采用Map-Reduce、Tez、Spark等引擎。 SparkSQL的两个组件 SQLContext:Spark SQL提供SQLContext封装Spark中的所有关系型功能。可以用之前的示例中的现有SparkContext创建SQLContext。 DataFrame:DataFrame是一个分布式的,按照命名列的形式组织的数据集合。DataFrame基于R语言中的data frame概念,与关系型数据库中的数据库表类似。通过调用将DataFrame的内容作为行RDD(RDD of Rows)返回的rdd方法,可以将DataFrame转换成RDD。可以通过如下数据源创建DataFrame:已有的RDD、结构化数据文件、JSON数据集、Hive表、外部数据库。
SparkSQL运行架构 类似于关系型数据库,SparkSQL也是语句也是由Projection(a1,a2,a3)、Data Source(tableA)、Filter(condition)组成,分别对应sql查询过程中的Result、Data Source、Operation,也就是说SQL语句按Operation–>Data Source–>Result的次序来描述的。
当执行SparkSQL语句的顺序 对读入的SQL语句进行解析(Parse),分辨出SQL语句中哪些词是关键词(如SELECT、FROM、WHERE),哪些是表达式、哪些是Projection、哪些是Data Source等,从而判断SQL语句是否规范; Projection:简单说就是select选择的列的集合,参考: SQL Projection 将SQL语句和数据库的数据字典(列、表、视图等等)进行绑定(Bind),如果相关的Projection、Data Source等都是存在的话,就表示这个SQL语句是可以执行的; 一般的数据库会提供几个执行计划,这些计划一般都有运行统计数据,数据库会在这些计划中选择一个最优计划(Optimize); 计划执行(Execute),按Operation–>Data Source–>Result的次序来进行的,在执行过程有时候甚至不需要读取物理表就可以返回结果,比如重新运行刚运行过的SQL语句,可能直接从数据库的缓冲池中获取返回结果。
Hive on Spark ​ hive on Spark是由Cloudera发起,由Intel、MapR等公司共同参与的开源项目, 其目的是把Spark作为Hive的一个计算引擎,将Hive的查询作为Spark的任务提交到Spark集群上进行计算。 通过该项目,可以提高Hive查询的性能,同时为已经部署了Hive或者Spark的用户提供了更加灵活的选择,从而进一步提高Hive和Spark的普及率。
Hive on Spark与SparkSql的区别
​ hive on spark大体与SparkSQL结构类似, 只是SQL引擎不同,但是计算引擎都是spark! 敲黑板!这才是重点! 我们来看下,在pyspark中使用Hive on Spark是中怎么样的体验 #初始化Spark SQL #导入Spark SQL from pyspark.sql import HiveContext,Row # 当不能引入Hive依赖时 # from pyspark.sql import SQLContext,Row # 注意,上面那一点才是关键的,他两来自于同一个包,你们区别能有多大 hiveCtx = HiveContext(sc) #创建SQL上下文环境 input = hiveCtx.jsonFile(inputFile) #基本查询示例 input.registerTempTable( "tweets" ) #注册输入的SchemaRDD(SchemaRDD在Spark 1.3版本后已经改为DataFrame) #依据retweetCount(转发计数)选出推文 topTweets = hiveCtx.sql( "SELECT text,retweetCount FROM tweets ORDER BY retweetCount LIMIT 10" ) 我们可以看到,sqlcontext和hivecontext都是出自于pyspark.sql包,可以从这里理解的话,其实hive on spark和sparksql并没有太大差别
结构上Hive On Spark和SparkSQL都是一个翻译层,把一个SQL翻译成分布式可执行的Spark程序。而且大家的引擎都是spark SparkSQL和Hive On Spark都是在Spark上实现SQL的解决方案。Spark早先有Shark项目用来实现SQL层,不过后来推翻重做了,就变成了SparkSQL。这是Spark官方Databricks的项目,Spark项目本身主推的SQL实现。Hive On Spark比SparkSQL稍晚。Hive原本是没有很好支持MapReduce之外的引擎的,而Hive On Tez项目让Hive得以支持和Spark近似的Planning结构(非MapReduce的DAG)。所以在此基础上,Cloudera主导启动了Hive On Spark。这个项目得到了IBM,Intel和MapR的支持(但是没有Databricks)。—From SparkSQL与Hive on Spark的比较
Hive on Mapreduce和SparkSQL使用场景
Hive on Mapreduce场景 Hive的出现可以让那些精通SQL技能、但是不熟悉MapReduce 、编程能力较弱与不擅长 Java 语言的用户能够在HDFS大规模数据集上很方便地利用SQL 语言查询、汇总、分析数据,毕竟精通SQL语言的人要比精通Java语言的多得多 Hive适合处理离线非实时数据
SparkSQL场景 Spark既可以运行本地local模式,也可以以Standalone、cluster等多种模式运行在Yarn、Mesos上,还可以运行在云端例如EC2。此外,Spark的数据来源非常广泛,可以处理来自HDFS、HBase、 Hive、Cassandra、Tachyon上的各种类型的数据。 实时性要求或者速度要求较高的场所
Hive on Mapreduce和SparkSQL性能对比 具体实验参见: Spark SQL & Spark Hive编程开发, 并和Hive执行效率对比
结论:sparksql和hive on spark时间差不多,但都比hive on mapreduce快很多,官方数据认为spark会被传统mapreduce快10-100倍
关于Spark
简介
在Hadoop的整个生态系统中,Spark和MapReduce在同一个层级,即主要解决分布式计算框架的问题。

架构
Spark的架构如下图所示,主要包含四大组件:Driver、Master、Worker和Executor。

Spark特点 Spark可以部署在YARN上 Spark原生支持对HDFS文件系统的访问 使用Scala语言编写

部署模型 单机模型:主要用来开发测试。特点:Driver、Master、Worker和Executor都运行在同一个JVM进程之中。 伪集群模型:主要用来开发测试。特点:Master、Worker都运行在同一个JVM进程之中;Master、Worker和Executor都运行于同一台机器,无法跨机器运行; 独立集群(又叫做原生集群模式):在集群规模不是非常大的情况下,可用于生产环境。特点:Master、Worker和Executor都运行于独立的JVM进程。 YARN集群:YARN生态中的ApplicationMaster角色使用Apache开发好的Spark ApplicationMaster代替,每一个YARN生态中的NodeManager角色相当于一个Spark生态中的Worker角色,由NodeManger负责Executor的启动。 Mesos集群:暂无详细调研。
关于Spark SQL
简介
它主要用于结构化数据处理和对Spark数据执行类SQL的查询。通过Spark SQL,可以针对不同格式的数据执行ETL操作(如JSON,Parquet,数据库)然后完成特定的查询操作。一般来说,Spark每支持一种新的应用开发,都会引入一个新的Context及相应的RDD,对于SQL这一特性来说,引入的就是SQLContext和SchemaRDD。注意:在Spark1.3之后,SchemaRDD已经更名为DataFrame,但它本质就类似一个RDD,因为可以将DataFrame无缝的转换成一个RDD。

架构
Spark要很好的支持SQL,要完成解析(parser)、优化(optimizer)、执行(execution)三大过程。

处理顺序大致如下: SQlParser生成LogicPlan Tree; Analyzer和Optimizer将各种Rule作用于LogicalPlan Tree; 最终优化生成的LogicalPlan生成SparkRDD; 最后将生成的RDD交由Spark执行;
关于Hive on Spark
背景
Hive on Spark是由Cloudera发起,由Intel、MapR等公司共同参与的开源项目,其目的是把Spark作为Hive的一个计算引擎,将Hive的查询作为Spark的任务提交到Spark集群上进行计算。通过该项目,可以提高Hive查询的性能,同时为已经部署了Hive或者Spark的用户提供了更加灵活的选择,从而进一步提高Hive和Spark的普及率。

简介
Hive on Spark是从Hive on MapReduce演进而来,Hive的整体解决方案很不错,但是从查询提交到结果返回需要相当长的时间,查询耗时太长,这个主要原因就是由于Hive原生是基于MapReduce的,那么如果我们不生成MapReduce Job,而是生成Spark Job,就可以充分利用Spark的快速执行能力来缩短HiveQL的响应时间。
Hive on Spark现在是Hive组件(从Hive1.1 release之后)的一部分。

与SparkSQL的区别
SparkSQL和Hive On Spark都是在Spark上实现SQL的解决方案。Spark早先有Shark项目用来实现SQL层,不过后来推翻重做了,就变成了SparkSQL。这是Spark官方Databricks的项目,Spark项目本身主推的SQL实现。Hive On Spark比SparkSQL稍晚。Hive原本是没有很好支持MapReduce之外的引擎的,而Hive On Tez项目让Hive得以支持和Spark近似的Planning结构(非MapReduce的DAG)。所以在此基础上,Cloudera主导启动了Hive On Spark。这个项目得到了IBM,Intel和MapR的支持(但是没有Databricks)。

使用示例
大体与SparkSQL结构类似,只是SQL引擎不同。部分核心代码如下: val hiveContext = new HiveContext(sc) import hiveContext._ hql("CREATE TABLE IF NOT EXIST src(key INT, value STRING)") hql("LOAD DATA LOCAL PATH '/Users/urey/data/input2.txt' INTO TABLE src") hql("FROM src SELECT key, value").collect().foreach(println)
小结
结构上Hive On Spark和SparkSQL都是一个翻译层,把一个SQL翻译成分布式可执行的Spark程序。比如一个SQL: SELECT item_type, sum(price) FROM item GROUP item_type;
上面这个SQL脚本交给Hive或者类似的SQL引擎,它会“告诉”计算引擎做如下两个步骤:读取item表,抽出item_type,price这两个字段;对price计算初始的SUM(其实就是每个单独的price作为自己的SUM)因为GROUP BY说需要根据item_type分组,所以设定shuffle的key为item_type从第一组节点分组后分发给聚合节点,让相同的item_type汇总到同一个聚合节点,然后这些节点把每个组的Partial Sum再加在一起,就得到了最后结果。不管是Hive还是SparkSQL大致上都是做了上面这样的工作。
需要理解的是,Hive和SparkSQL都不负责计算,它们只是告诉Spark,你需要这样算那样算,但是本身并不直接参与计算。
Spark Shark | 即 Hive on Spark
a.在实现上是把HQL翻译成Spark上的RDD操作,然后通过Hive的metadata获取数据库里的表信息,Shark获取HDFS上的数据和文件夹放到Spark上运算。
b.它的最大特性就是快以及与Hive完全兼容
c.Shark使用了Hive的API来实现query parsing和logic plan generation,最后的Physical Plan execution阶段用Spark代替Hadoop MR。
d.通过配置Shark参数,Shark可以自动在内存中缓存特定的RDD,实现数据重用,进而加快特定数据集的检索。
e.Shark通过UDF实现特定的数据分析学习算法,使得SQL数据查询和运算分析结合在一起,最大化RDD的重复使用。

Spark SQL
a.是基于Catalyst(翻译为催化剂)引擎的交互式大数据SQL技术,使用SchemaRDD来操作SQL,比Shark支持更过的查询表达式。
b.支持Hive|HBase|Oracle
交互式SQL处理框架Spark SQL
a.SparkSQL的四个特点:
1.能在Scala代码里写SQL,支持简单的SQL语法检查,能把RDD指定为Table存储起来。对SQL的支持主要依赖Catalyst(催化剂)查询优化框架,在把SQL解析成逻辑执行计划之后,利用Catalyst包里的一些类和接口,执行了一些简单的执行计划优化
最后变成RDD的计算。
2.支持Parquet(arquet是面向分析型业务的列式存储格式)文件的读写,且保留Schem.Parquet是一个列式存储格式的文件系统,使用Parquet进行文件读写可以极大地降低对CPU和磁盘I/O的消耗。
3.支持直接多JSON格式数据的操作。
4.能在Scala代码里访问Hive元数据,能执行hive语句,并且把结果取回作为RDD使用。Shark依赖Hive的metastore,解析器能把hql执行变成Spark的计算,SparkSQL的前身是Shark,而Shark的前身是HIVE.
5.Shark对于Hive的依赖太多,为了摆脱依赖性,SparkSQL无论在数据兼容|性能优化|组件扩展都得到了极大的方便。
b.SparkSQL的性能:
1.Shark的出现,使得SQL-on-hadoop的性能比hive有了10~100倍的提高。摆脱Hive的限制,SSQL的性能也很优秀
在2014年7月1日的Spark Summit上,Databricks宣布终止对Shark的开发,将重点放到Spark SQL上。Databricks表示,Spark SQL将涵盖Shark的所有特性,用户可以从Shark 0.9进行无缝的升级。
本次Databricks推广的Shark相关项目一共有两个,分别是Spark SQL和新的Hive on Spark(HIVE-7292),在介绍这两个项目之前,我们首先关注下被终止的项目Shark。
Shark及项目终止原因
About Shark
Shark发布于3年前,那个时候,Hive可以说是SQL on Hadoop的唯一选择,负责将SQL编译成可扩展的MapReduce作业。鉴于Hive的性能以及与Spark的兼容,Shark项目由此而生。
Shark即Hive on Spark,本质上是通过Hive的HQL解析,把HQL翻译成Spark上的RDD操作,然后通过Hive的metadata获取数据库里的表信息,实际HDFS上的数据和文件,会由Shark获取并放到Spark上运算。
Shark的最大特性就是快和与Hive的完全兼容,且可以在shell模式下使用rdd2sql()这样的API,把HQL得到的结果集,继续在scala环境下运算,支持自己编写简单的机器学习或简单分析处理函数,对HQL结果进一步分析计算。
除去Spark本身的迭代计算,Shark速度快的原因还在于其本身的改造,比如:
partial DAG execution:对join优化,调节并行粒度,因为Spark本身的宽依赖和窄依赖会影响并行计算和速度
基于列的压缩和存储:把HQL表数据按列存,每列是一个array,存在JVM上,避免了JVM GC低效,而压缩和解压相关的技术是Yahoo!提供的。
终止Shark的原因
在会议上,Databricks表示,Shark更多是对Hive的改造,替换了Hive的物理执行引擎,因此会有一个很快的速度。然而,不容忽视的是,Shark继承了大量的Hive代码,因此给优化和维护带来了大量的麻烦。随着性能优化和先进分析整合的进一步加深,基于MapReduce设计的部分无疑成为了整个项目的瓶颈。
因此,为了更好的发展,给用户提供一个更好的体验,Databricks宣布终止Shark项目,从而将更多的精力放到Spark SQL上。
两个相关/替代项目介绍
About Spark SQL
既然不是基于Hive,Spark SQL究竟有什么样的改变,这里我们不妨看向 张包峰的博客。Spark新发布的Spark SQL组件让Spark对SQL有了别样于Shark基于Hive的支持。参考官方手册,具体分三部分:
其一,能在Scala代码里写SQL,支持简单的SQL语法检查,能把RDD指定为Table存储起来。此外支持部分SQL语法的DSL。
其二,支持Parquet文件的读写,且保留Schema。
其三,能在Scala代码里访问Hive元数据,能执行Hive语句,并且把结果取回作为RDD使用。
第一点对SQL的支持主要依赖了Catalyst这个新的查询优化框架(下面会给出一些Catalyst的简介),在把SQL解析成逻辑执行计划之后,利用Catalyst包里的一些类和接口,执行了一些简单的执行计划优化,最后变成RDD的计算。虽然目前的SQL解析器比较简单,执行计划的优化比较通配,还有些参考价值,所以看了下这块代码。目前这个PR在昨天已经merge进了主干,可以在SQL模块里看到这部分实现,还有catalyst模块看到Catalyst的代码。下面会具体介绍Spark SQL模块的实现。
第二点对Parquet的支持不关注,因为我们的应用场景里不会使用Parquet这样的列存储,适用场景不一样。
第三点对Hive的这种结合方式,没有什么核心的进展。与Shark相比,Shark依赖Hive的Metastore,解析器等能把hql执行变成Spark上的计算,而Hive的现在这种结合方式与代码里引入Hive包执行hql没什么本质区别,只是把hive hql的数据与RDD的打通这种交互做得更友好了。
About HIVE-7292
HIVE-7292更像是Spark SQL成为标准SQL on Spark项目的补充,首先它是一个Hive on Spark Project,旨在服务已有Hive投入的机构,这个项目将Spark作为一个替代执行引擎提供给Hive,从而为这些机构提供一个迁往Spark的途径,提供一个更流畅的Hive体验。
随着Spark SQL的引入和新的Hive on Apache Spark方向的努力( HIVE-7292 ),许多人询问我们在这两个项目中的位置,以及它们与Shark的关系。在今天的 Spark峰会 上,我们宣布,我们停止了Shark的开发,并会专注于Spark SQL,它将提供Shark特性的超集,以便于现有的Shark用户继续使用。Spark SQL提供了从Shark 0.9的无缝升级,以及一些诸如通用Spark程序的集成等新特性。
Shark
三年前Shark项目开始的时候,Hive(on MapReduce)是SQL on Hadoop的唯一选择。Hive把SQL编译成可扩展的MapReduce作业,而且可以支持多种格式(通过它的SerDes)。但是其性能并不理想。为了交互式地执行查询,许多公司部署了昂贵的专用企业数据仓库(EDWs),这需要严格的、冗长的ETL流程。
Hive和EDWs之间的性能对比在工业界引起了关于在通用数据处理引擎上进行查询处理的内在缺陷的巨大争论。许多人认为SQL交互需要一个昂贵的专用系统用于查询处理(如EDWs)。Shark成为了 一种较早的交互式SQL on Hadoop系统 ,而且是唯一一种基于通用运行环境(Spark)构建的。它表明了所有导致Hive慢的缺陷都不是根本性的,像Spark这样的通用引擎就能同时达到两方面的要求:和EDW一样快,和Hive/MapReduce一样可扩展。
为什么你应该关注这个看似比较学术的争论呢?各种组织都在寻找能给它们带来商业优势的方法,它们使用了很多超出SQL提供的上卷和下钻能力的技术。基于通用环境构建一个SQL查询引擎统一了许多不同的、强大的模型,例如batch、streaming、机器学习。这使得数据科学家和工程师能够更快的执行更复杂的方法。Shark的观点很快被接受了,甚至催生了Hive的一些重要改进。
从Shark到Spark SQL
Shark基于Hive源码构建,并通过替换Hive的物理执行引擎获得了性能上的提升。虽然这种方法让Shark用户能更快的执行Hive查询,但是Shark从Hive继承了大量复杂的源码,因而导致难以优化和维护。随着我们逐步逼近性能优化的极限和集成复杂的SQL分析,我们被那些按照MapReduce设计的遗产所束缚。
正因为如此,我们停止了Spark作为一个单独项目的开发,并把所有的开发资源转向Spark SQL,Spark的一个新组件。我们借鉴了Shark的经验用到Spark SQL中,并重新设计以更好了利用Spark。这种新途径让我们更快的创新,最终为用户交付更好的体验。
对于 SQL用户 ,Spark SQL提供了最先进的SQL性能并兼容Shark/Hive。像Shark一样,Spark SQL支持所有的Hive数据格式,用户定义函数(UDF),和Hive metastore。Spark1.1.0引入新的特性后, TPC-DS performance 中,Spark SQL性能比Shark高一个数量级。
对于 Spark用户 ,Spark SQL成为了处理(半)结构化数据和诸如JSON、Parquet、Hive或EDWs等有模式的数据源的细腰(narrow-waist)。它确实统一了SQL和复杂分析,允许用户混合SQL和更多编程API以实现高级分析。
对于 开源黑客 ,Spark SQL提供了一种新的简洁的方法去构建查询计划。在这个框架下添加新的优化很简单。我们已经完全被开源社区对于Spark SQL的热情所折服,多亏这个新设计。仅仅三个月,就有40多为贡献者提交了代码。谢谢。
Hive on Spark(HIVE-7292)
虽然Spark SQL逐渐成为SQL on Spark的标准,但是我们知道许多组织已经使用了Hive。这里面也有很多公司想迁移到Spark。Hive社区提出了一个 新举措 ,这样能使Spark作为Hive的一个可选执行引擎。对于上述组织,参照上述引文可以把执行引擎迁移到Spark。我们很高兴能与Hive社区一起为用户提供更平顺的体验。
总之,我们坚信Spark SQL会是基于Spark的SQL和结构化数据处理的未来。我们将努力工作,并在随后几个releases带来更多特性。对于有遗留Hive部署的公司,Hive on Spark会为他们提供支持。
英文原文:发表于2014年7月1日
Shark, Spark SQL, Hive on Spark, and the future of SQL on Apache Spark
Impala与Shark,Drill等的比较
开源组织Apache也发起了名为Drill的项目来实现Hadoop上的Dremel,目前该项目正在开发当中,相关的文档和代码还不多,可以说暂时还未对Impala构成足够的威胁。从Quora上的问答来看,Cloudera有7-8名工程师全职在Impala项目上,而相比之下Drill目前的动作稍显迟钝。具体来说,截止到2012年10月底,Drill的代码库里实现了query parser, plan parser,及能对JSON格式的数据进行扫描的plan evaluator;而Impala同期已经有了一个比较完毕的分布式query execution引擎,并对HDFS和HBase上的数据读入,错误检测,INSERT的数据修改,LLVM动态翻译等都提供了支持。当然,Drill作为Apache的项目,从一开始就避免了某个vendor的一家独大,而且对所有Hadoop流行的发行版都会做相应的支持,不像Impala只支持Cloudera自己的发行版CDH。从长远来看,谁会占据上风还真不一定。
除此之外,加州伯克利大学AMPLab也开发了名为Shark的大数据分析系统。从长远目标来看,Shark想成为一个既支持大数据SQL查询,又能支持高级数据分析任务的一体化数据处理系统。从技术实现的角度上来看,Shark基于Scala语言的算子推导实现了良好的容错机制,因此对失败了的长任务和短任务都能从上一个“快照点”进行快速恢复。相比之下,Impala由于缺失足够强大的容错机制,其上运行的任务一旦失败就必须“从头来过”,这样的设计必然会在性能上有所缺失。而且Shark是把内存当作第一类的存储介质来做的系统设计,所以在处理速度上也会有一些优势。实际上,AMPLab最近对Hive,Impala,Shark及Amazon采用的商业MPP数据库Redshift进行了一次对比试验,在Scan Query,Aggregation Query和Join Query三种类型的任务中对它们进行了比较。图2就是AMPLab报告中Aggregation Query的性能对比。在图中我们可以看到,商业版本的Redshift的性能是最好的, Impala和Shark则各有胜负,且两者都比Hive的性能高出了一大截。
参考:
Shark对Hive的兼容性总结
前世今生:Hive、Shark、spark SQL
impala与hive的比较以及impala的有缺点
大数据
2018-08-13 14:44:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
问题
“把 Kafka 作为长期存储有问题吗?” 这是一个非常常见的问题,我们知道,只要把数据保留时间设置为“永久”,或者开启日志压缩,数据就会被一直保存
把数据长期存储在 Kafka,这个做法并不疯狂,很多人已经在这么用,并且 Kafka 的设计中也涵盖了这种用法,下面是一些实际应用的场景
应用场景
(1)你有一个应用,使用了事件模式,并需要对变更日志进行存储,理论上可以使用很多系统来存储日志,但是 Kafka 直接解决了很多此类场景的问题,例如日志的不可变,纽约时报就使用 Kafka 来存储他们所有文章的数据
(2)在应用中有一个内存缓存,数据源于 Kafka,这时可以把 Kafka topic 中的日志压缩,应用重新启动时,从偏移量为0的位置重新读取数据到缓存
(3)需要对来自 Kafka 的流数据进行流计算,当流计算逻辑发生变化时,我们希望重新计算一遍,这时就可以把偏移量置为0,重头计算
(4)Kafka 常被用于捕获数据库的变更,关心数据变化的应用就可以从中获取变更记录,做相应的业务操作,这时出现了一个新的应用,需要全部的数据快照,如果对一个大型产品数据执行全量 dump 操作是不现实的,非常耗时,但我们可以对 Kafka 中的记录在0偏移量重新加载一遍
为什么可以?
这些长期存储的场景都是真实可行的,因为 Kafka 就是这么设计的
数据在 Kafka 中是持久化到硬盘的,有数据检查,有多副本来容错,并且持续累加的数据不会使性能变慢
实际应用案例中,已经有存储 PB 量级数据的 Kafka cluster 在运行
人们之所以对 kafka 长期存储数据的用法存在疑虑,是因为我们通常认为 kafka 是一个消息队列
使用“消息队列”时有一个原则: 不要在消息队列中存储消息
因为,读消息时就要移除这个消息、消息系统的扩张能力不足、消息系统也缺少强壮的复制特性
传统消息系统不重视消息的存储,而 kafka 认为这点是非常关键的,认为消息系统的基础功能就是存储,即使一个消息很快被消费,那也是需要短暂的存储,必须要保证消费者能够接收到消息,必须提供容错存储机制
所以,kafka 的设计中有以下特点: kafka 存储可被重新读取的持久数据 kafka 是一个分布式系统,以 cluster 形式运行,可以弹性的扩展和缩减,有容错复制系统,具有高可用性 kafka 允许实时的数据流处理,而不是一次处理一条消息
kafka 已经不是一个传统的消息队列,而应该归类到“流处理平台”
Kafka 会成为数据库吗?
既然 kafka 这么牛,很适合长期储存,那么 kafka 会不会发展为一个数据库呢?
答案是不会,主要原因有2个: 数据库主要是关于查询的,kafka 是顺序读写机制,如果加入随机访问机制,对 kafka 没有什么好处 kafka 的发展目标不在于成为第1001个数据库,而是要成为主流的流数据处理平台,成为现代数字业务中的核心系统
小结
kafka 已经不是一个简单的消息系统,kafka 在不断壮大,有 connector 可以方便的连接其他系统,有 stream api 进行流计算,最近又推出 KSQL,流处理的代码都不用我们写了,用 sql 就可以方便的进行流处理
大数据
2018-08-13 14:11:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
个人认为, Kafka与Redis PUB/SUB之间最大的区别在于Kafka是一个完整的系统,而Redis PUB/SUB只是一个套件(utility)——没有冒犯Redis的意思,毕竟它的主要功能并不是PUB/SUB。
先说Redis吧,它首先是一个内存数据库,其提供的PUB/SUB功能把消息保存在内存中(基于channel),因此如果你的消息的持久性需求并不高且后端应用的消费能力超强的话,使用Redis PUB/SUB是比较合适的使用场景。比如官网说提供的一个网络聊天室的例子:模拟IRC,因为channel就是IRC中的服务器。用户发起连接,发布消息到channel,接收其他用户的消息。这些对于持久性的要求并不高,使用Redis PUB/SUB来做足矣。
而Kafka是一个完整的系统,它提供了一个高吞吐量、分布式的提交日志(由于提供了Kafka Connect和Kafka Streams,目前Kafka官网已经将自己修正为一个分布式的流式处理平台,这里也可以看出Kafka的野心:-)。除了p2p的消息队列,它当然提供PUB/SUB方式的消息模型。而且,Kafka默认提供了消息的持久化,确保消息的不丢失性(至少是大部分情况下)。另外,由于消费元数据是保存在consumer端的,所以对于消费而言consumer被赋予极大的自由度。consumer可以顺序地消费消息,也可以重新消费之前处理过的消息。这些都是Redis PUB/SUB无法做到的。
最后总结一下,
Redis PUB/SUB使用场景:
1. 消息持久性需求不高
2. 吞吐量要求不高
3. 可以忍受数据丢失
4. 数据量不大
Kafka使用场景:
上面以外的其他场景:)
1. 高可靠性
2. 高吞吐量
3. 持久性高
4. 多样化的消费处理模型
大数据
2018-08-13 14:04:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
哈喽大家好呀,仅经过了一段时间大数据相关的博文又和大家见面了,笔者之前有写过一套Hadoop大数据相关的博客,为什么今天又要开坑呢?当然是有原因,随着不断的学习了解,慢慢意识到之前做法存在很多缺陷,最终对比了比较成熟的解决方案EMR和CDH,最终选择了使用CDH来搭建大数据管理平台,那么我们就开始新的一趴,企业级大数据管理平台CDH的学习吧!
附上:
喵了个咪的博客: w-blog.cn
cloudera官网: https://www.cloudera.com/
官方文档地址: https://www.cloudera.com/documentation/enterprise/latest.html
一 , CDN介绍和解决的问题
CDH是由cloudera进行开发的大数据一站式平台管理解决方案,基于Hadoop生态的第三方发行版本,这样的描述相信大家还是挺难理解的,我们一起来梳理下CDH带来的改观.
作坊和工厂有什么区别? 一个是做出来东西就好了,一个是精细化流水线生产
用这个来对比自建Hadoop和CDH再好不过,要理解其中的区别我们需要先对CDH有个基础的认知,先从了解CDH解决了常见的什么问题
组件兼容 复杂的生态环境。在Hadoop生态圈中,组件的选择、使用,比如Hive,Mahout,Sqoop,Flume,Spark,Oozie等等,需要大量考虑兼容性的问题,版本是否兼容,组件是否有冲突,编译是否能通过等。经常会浪费大量的时间去编译组件,解决版本冲突问题。 CDH每个版本都会有兼容认证都是经过严格的测试之后公布的,理论上来说只要统一CDH版本就不会出现兼容问题
稳定安全 不同的版本会有不同的漏洞很容易被被利用,又不敢轻易更新 版本更新快。通常情况,比如CDH每个季度会有一个update,每一年会有一个release。基于稳定版本Apache Hadoop,并应用了最新Bug修复或Feature的patch
安装配置管理 复杂的集群部署、安装、配置。通常按照集群需要编写大量的配置文件,分发到每一台节点上,容易出错,效率低下,还需要大量的查阅资料文档。 统一的网页进行安装配置,非常详细的文档以及配置的分类注解以及推荐配置(基本都已经是最优配置)
资源监控管理运维 复杂的集群运维。对集群的监控,运维,需要安装第三方的其他软件,如ganglia,nagois等,运维难度较大。 运维简单。提供了管理、监控、诊断、配置修改的工具,管理配置方便,定位问题快速、准确,使运维工作简单,有效。
企业服务 只能求助社区的帮助,响应差,解决问题需要碰运气. 代码基于Apache协议,100%开源。同时提供企业付费服务一对一支持,作为保障的后盾 PS: 使用CDH部署集群不能代替对各个组件进行单独的学习了解的工作,非常推荐大家从单个组件安装部署开始最后在统一使用CDH部署
二 , 准备工作
环境准备 CentOS 7.4 64位 JDK 1.8 Cloudera Manager 5.15.0
需要准备一台cm服务器 两台master服务器 使用三台节点服务器 服务器最低要求 4核心8G
所有节点修改hostname > hostnamectl --static set-hostname cm > hostnamectl --static set-hostname master-1 > hostnamectl --static set-hostname master-2 > hostnamectl --static set-hostname slave-1 > hostnamectl --static set-hostname slave-2 > hostnamectl --static set-hostname slave-3
修改节点的hosts可以直接通过主机名进行访问 > vim /etc/hosts # 修改为大家自己服务器的IP地址 192.168.3.10 cm 192.168.3.21 master-1 192.168.3.22 master-2 192.168.3.31 slave-1 192.168.3.32 slave-2 192.168.3.33 slave-3
依赖文件安装包准备 > mkdir -p /app/install > cd /app/install > wget http://archive.cloudera.com/cm5/cm/5/cloudera-manager-centos7-cm5.15.0_x86_64.tar.gz > wget http://archive.cloudera.com/cdh5/parcels/5.15.0/CDH-5.15.0-1.cdh5.15.0.p0.21-el7.parcel > wget http://archive.cloudera.com/cdh5/parcels/5.15.0/CDH-5.15.0-1.cdh5.15.0.p0.21-el7.parcel.sha1 > wget http://pic.w-blog.cn/mysql-connector-java.jar JDK1.8需要自行下载 jdk-8u101-linux-x64.tar.gz
最终我们可以看到有如下文件:
下载慢可选多线程下载工具 axel cd /app/install wget http://www.ha97.com/code/axel-2.4.tar.gz tar zxvf axel-2.4.tar.gz cd axel-2.4 ./configure make make install cd ..
所有节点关闭防火墙和selinux
关闭防火墙: systemctl stop firewalld.service systemctl disable firewalld.service firewall-cmd --state
关闭selinux: vim /etc/selinux/config 找到SELINUX改为: SELINUX=disabled
所有节点ssh免密码登录
先在cm 上执行: ssh-keygen -t rsa #一路回车到完成 ssh-copy-id -i ~/.ssh/id_rsa.pub root@cm #将公钥拷贝到本机的authorized_keys上
再在其他节点分别执行以下命令:
注意此处不变,将公钥拷贝到cm的authorized_k ssh-keygen -t rsa ssh-copy-id -i ~/.ssh/id_rsa.pub root@cm
在CM上,将authorized_keys分发到其他节点服务器: scp ~/.ssh/authorized_keys root@master-1:~/.ssh/ scp ~/.ssh/authorized_keys root@master-2:~/.ssh/ scp ~/.ssh/authorized_keys root@slave-1:~/.ssh/ scp ~/.ssh/authorized_keys root@slave-2:~/.ssh/ scp ~/.ssh/authorized_keys root@slave-3:~/.ssh/
大数据
2018-08-13 09:13:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1、将txt文本文件放置hdfs目录下
2、登录hive并进入到指定数据库
3、创建表 create external table if not exists fun_user_external ( tid INT, userid STRING, pwd STRING, create_time BIGINT, email STRING ... ) ROW FORMAT DELIMITED FIELDS TERMINATED BY '`' STORED AS TEXTFILE 建表语句中主要的是最后一部分:ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘`’ STORED AS TEXTFILE
load data inpath '/tmp/fun_user.txt' into table fun_user_external; load data local inpath '/tmp/fun_user.txt' into table fun_user_external;
上面两条数据导入语句,如果有 local 这个关键字,则这个路径应该为本地文件系统路径,数据会被拷贝到目标位置;如果省略掉 local 关键字,那么这个路径应该是分布式文件系统中的路径,这种情况下,数据是从这个路径转移到目标位置的。
大数据
2018-08-11 21:26:00