1、hive的数据倾斜
现象:
在执行MR任务的时候,大多数的reduce节点都执行完毕,而只有几个reduce节点运行很慢或者一直卡在99%,导致整个MR任务运行很慢。
原因:
这是因为某一个或几个key的数据量要比其他key要多很多,导致这一个reduce节点运行很慢
key分布不均匀
sql语句本身就会倾斜
业务导致
建表考虑不周
解决思路:
1、在map阶段解决
2、对key进行操作
解决方法:
1、使用combine方法在map端提前进行一个reduce计算,大大减少到reduce端时的数据量。但是combine方法计算类似平均值的需求时会出现误差。
2、开启map端join
3、能先group by 就先group by ,这样会先进行一个聚合从而减少数据量
4、对key进行操作,自定义分区器,将key均匀分布
5、 参数调节
hive.map.aggr = true
Map 端部分聚合,相当于Combiner
hive.groupby.skewindata=true
6、SQL调优
如何Join:关于驱动表的选取,选用join key分布最均匀的表作为驱动表。做好列裁剪和filter操作,以达到两表做join的时候,数据量相对变小的效果。
大小表Join:使用map join让小的维度表(1000条以下的记录条数) 先进内存。在map端完成reduce.
大表Join大表:把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果。
count distinct大量相同特殊值:count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。
group by维度过小:采用sum() group by的方式来替换count(distinct)完成计算。
特殊情况特殊处理:在业务逻辑优化效果的不大情况下,有些时候是可以将倾斜的数据单独拿出来处理。最后union回去。
7、小结
使map的输出数据更均匀的分布到reduce中去,是我们的最终目标。由于Hash算法的局限性,按key Hash会或多或少的造成数据倾斜。大量经验表明数据倾斜的原因是人为的建表疏忽或业务逻辑可以规避的。在此给出较为通用的步骤:
1、采样log表,哪些user_id比较倾斜,得到一个结果表tmp1。由于对计算框架来说,所有的数据过来,他都是不知道数据分布情况的,所以采样是并不可少的。
2、数据的分布符合社会学统计规则,贫富不均。倾斜的key不会太多,就像一个社会的富人不多,奇特的人不多一样。所以tmp1记录数会很少。把tmp1和users做map join生成tmp2,把tmp2读到distribute file cache。这是一个map过程。
3、map读入users和log,假如记录来自log,则检查user_id是否在tmp2里,如果是,输出到本地文件a,否则生成
参考文章:https://cloud.tencent.com/developer/article/1011039
2、redis 五中数据类型的应用场景
redis的五种数据类型:String,hash,list,set,zset
2.1、String
String是redis最基础的数据类型,可以是简单字符串,json,xml等复杂字符串,数字,二进制(视频,图片等)
- 使用场景:
1、缓存功能:字符串最经典的使用场景,redis最为缓存层,Mysq|作为储存层, 绝大部分请求数据都是redis中获取,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低
后端压力的作用。
2、计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,同时数据可以一步落地到其他的数据源。如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。
3、共享session: 出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上,用户刷新一次访问可能会要重新登录,为避免这个问题可以用redis将用户session集中管理,在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息都直接从redis中集中获取。
4、限速:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率。
2.2、hash
hash叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。
假设有User对象以JSON序列化的形式存储到Redis中,User对象有id,username、password、age、name等属性
如果在业务上只是更新age属性,其他的属性并不做更新我应该怎么做呢?如果仍然采用上边的方法在传输、处理时会造成资源浪费,hash可以很好的解决这个问题。
- 使用场景:
哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。所以常常用于用户信息等管理,但是哈希类型和关系型数据有所不同,哈希类型是稀疏的,而关系型数据库是完全结构化的,关系型数据库可以做复杂的关系查询,而redis去模拟关系型复杂查询,开发困难,维护成本高。
2.3、list
List是有序可重复的集合
ArrayList与LinkedList的区别
ArrayList使用数组+链表方式存储数据,所以根据索引查询数据速度快,而新增或者删除元素时需要设计到位移操作,所以比较慢。
LinkedList使用双向链接方式存储数据,每个元素都记录前后元素的指针,所以插入、删除数据时只是更改前后元素的指针指向即可,速度非常快,然后通过下标查询元素时需要从头开始索引,所以比较慢,但是如果查询前几个元素或后几个元素速度比较快。
总结
ArrayList在进行增删改时很麻烦
linkedList则无该问题,redis的list类型存储时采用linkedlist
redis存储list类型可以实现队列和堆栈,队列是先进先出,而堆栈是先进后出。
- lpush --> 从左边存值(堆栈)
- rpush --> 从右边存值(队列)
使用场景:
消息队列: redis的lpush+ brpop命令组合即可实现阻塞队列,生产者客户端是用lupsh从列表
左侧插入元素,多个消费者客户端使用brpop命令阻塞时的"抢列表尾部的元素,多个客户端
保证了消费的负载均衡和高可用性
消息队列模型:

文章列表:每个用户都有属于自己的文章列表,现在需要分页展示文章列表,此时可以考虑
使用列表,列表不但有序,同时支持按照索引|范围获取元素。
2.4、set
集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中不可重复的元素,且集合中
的元素是无序的,不能通过索引|下标获取元素,redis除 了支持集合内的增删改查,同时还支持多个集合
取交集、并集、集,并拾理的使用好集合类型,能在实际开发中解决很多实际问题。
使用场景:
标签(tag) :集合类型比较典型的使用场景,如一个用户对娱乐、体育比较感兴趣,另一个可能对新闻感兴趣,这些兴趣就是标签,有了这些数据就可以得到同一标签的人,以及用户的共同爱好的标签,这些数据对于户体验以及增强用户粘度比较重要。(用户和标签的关系维护应该放在一个事物内执行,防止部分命令失败造成数据不一致)
其他
- sadd=tagging (标签)
- spop/srandmember=random item (生成随机数,比如抽奖)
- sadd+ sinter=social Graph(社交需求)
2.5、zset
有集合和集合有着必然的联系,他保留了集合不能有重复成员的特性,不同得是,有集合中的元素是可以排序的,但是它和列表的使用索引下标作为排序依据不同的是,它给每个元素设置一个分数,作为排序的依据。(有序集合中的元素不可以重复, 但是csore可以重复, 就和一个班里的同学学号不能重复,但考试成绩可以相同)。
使用场景:
排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护,可能是多方面:按照时间、按照播放量、按照获得的赞数等。

被折叠的 条评论
为什么被折叠?



