常见大数据问题

一、基础知识

1.1 哈希函数
  • 哈希函数又称散列函数,其输入域可以是非常大的范围,但是输出域是固定范围
  • 性质
    • 典型的哈希函数都拥有无限的输入值域
    • 输入值相同时,返回值一样
    • 输入值不同时,返回值可能一样,也可能不一样
  • 哈希函数优劣的关键
    • 不同输入值得到的哈希值,整体均匀地分布在输出域上
1.2 Map-Reduce
  • Map-Reduce分为两个阶段
    • Map阶段
      • 通过哈希函数把大任务分成多个子任务
      • 同样哈希值的子任务会被分配到同一个计算节点
    • Reduce阶段
      • 子任务并发处理,然后合并结果
  • Map-Reduce难点不在于理论,而在于工程,需要考虑以下问题
    • 备份的考虑,分布式存储的设计细节,以及容灾策略
    • 任务分配策略与任务进度跟踪的细节设计,节点状态的呈现
    • 多用户权限的控制
  • 应用实例,用Map-Reduce统计一篇文章中每个单词出现的个数
    • 预处理,去掉标点符号、处理英文连字符等,得到只包含单词的文本
    • Map阶段, 对每个单词生成词频为1的记录,例如(man, 1)。此时如果一个单词出现了多次,则有多个词频为1的记录。通过哈希函数得到每个单词的哈希值,根据哈希值把统计任务分成不同的子任务。相同的单词哈希值相同,会被分到相同的子任务中。
    • Reduce阶段,在每个子任务中,合并相同单词的词频统计。最后把所有子任务中的词频统计合并,即得到结果。
1.3 外排序
  • 外排序与内排序是相对应的两个概念
    • 内排序指排序过程中所有数据都放在内存中的排序算法,我们熟悉的冒泡排序、选择排序、插入排序、快速排序、堆排序、归并排序等都是内排序
    • 外排序指排序过程中只有部分数据会放在内存中的排序算法,一般应用于内存不足或数据量过大的场景
  • 外排序由两个不同的阶段组成
    • 第一阶段,采用适当地内部排序方法对输入文件的每个片段进行排序,将排好序的片段写到外存中,这样每个片段的数据时有序的
    • 第二阶段,利用归并算法,归并第一阶段生成的片段,直到得到一个包含所有数据的大归并段为止
  • 应用实例
    • 假设要对外存中4500个记录进行排序,但是内存中只能存放750个记录
    • 在第一阶段,每次读取750个记录到内存进行内排序,得到6个有序的片段(片段1-片段6)
    • 第二阶段,利用归并算法对所有片段进行两两合并,具体方法如下
      • 将内存分为三部分,每部分可保存250个记录,其中两个输入缓冲区,一个输出缓冲区
      • 首先对第一阶段得到的片段1和片段2进行归并,从片段1和片段2各读取250各记录到输入缓冲区,对两个输入缓冲区的记录进行合并,合并方式类似于归并排序,就不详细说了
      • 如果输出缓冲区满,则把输出缓冲区的记录写到磁盘(写到一个大小为1500的文件,因为片段1和片段2合并后大小为1500)
      • 如果某个输入缓冲区为空,则从对应的片段再次读取250个记录
      • 重复以上过程,直到所有记录被合并成一个大片段,此时排序完成
1.4 解答关键
  • 主要使用分而治之的思想解决大数据问题。即通过哈希函数将大任务分流到机器或分流成小文件
  • 另外,解决大数据问题常用的工具有hashMap和bitMap

二、大数据问题

2.1 对10亿个IPv4的IP地址进行排序,每个IP只会出现一次
  • 想法,IPv4地址长度为4字节,因此可以把IPv4地址转化为32位无符号整数unsigned int
  • 解答步骤
    • 申请长度为 2 32 2^{32} 232的bitMap,即长度为 2 32 2^{32} 232的bit类型数组,数组的每个位置的值要么是0要么是1
    • 遍历给出的10亿个IPv4地址,把每个IP地址对应的bitMap位置(通过IP -> unsigned int得到位置)设为1
    • 遍历bitMap,相应位置为1则得到一个IP地址(通过unsigned int -> IP)。遍历完成后得到的IP地址序列就是有序的
  • 空间复杂度分析
    • 本解法的空间主要消耗在bitMap,一个长度为 2 32 2^{32} 232的bit类型数组占用的内存空间大约是512M
2.2 对10亿人的年龄进行排序
  • 想法,年龄是一个有范围的整数,可以假设年龄分布在[0, 200)的区间内
  • 解答步骤
    • 申请一个大小为200的数组
    • 遍历给出的10亿个年龄记录,根据年龄将其放进对应的数组位置
    • 遍历数组,从数组位置中取出所有的年龄记录。最后得到的年龄记录序列就是有序的
2.3 有一个包含20亿个全是32位整数的大文件,在其中找到出现次数最多的数,内存限制2G
  • 想法
    • 最简单的方法是使用hashMap,其key为文件中的整数,占用4字节;其value为出现次数,由于一共有20亿个整数,因此可能的最大出现次数为20亿,value也需要占用4字节。根据前面的分析,一个(key, value)对需要8字节,极限情况下,有20亿个(key, value),占用大约16G内存,明显超出了题目限制。
    • 内存优先的情况下解决大数据问题,我们需要分而治之,具体步骤如下
  • 解答步骤
    • 使用哈希函数将大文件中的整数分流到多个小文件中
    • 统计每个小文件中整数出现次数,得到每个小文件中出现次数最多的整数
    • 比较所有小文件中出现最多的整数,得到全部小文件中出现最多的整数
2.4 32位无符号整数的范围是0~ 2 32 2^{32} 232-1。现在有一个正好包含40亿个无符号整数的文件,所以在整个范围中必然有没出现过的数。可以使用最多10M的内存,只用找到一个没出现过的数,该如何找?
  • 想法
    • 看到题目后第一想法是用bitMap做,长度为 2 32 2^{32} 232的bitMap占用内存为512M,远远超过了题目限制,因此不可行
    • 解决这个问题的方法还是分而治之,一个32位无符号整数占用4个字节,计算10M的内存可以保存多少个32位无符号整数,然后我们把0~ 2 32 2^{32} 232-1的区间分成多个小区间,每个小区间都可以装进10M内存中
  • 解答步骤
    • 把大区间按照前面所述的方法分成多个小区间
    • 如果某个小区间不满,则肯定有至少一个没出现过的数属于这个小区间
    • 针对不满的小区间,使用bitMap找到没有出现的数,问题解决
2.5 某搜索公司一天的用户搜索词汇量是海量的,假设有百亿的数据量,请设计一种求出每天最热100词的可行办法
  • 想法
    • topN问题可用堆来解决
  • 解答步骤
    • 使用哈希函数把百亿条记录分配到不同的计算节点
    • 根据计算节点的内存大小限制,分配到每个计算节点的记录再次使用哈希函数分流到不同的小文件
    • 处理每个计算节点的每个小文件,每个小文件进行词频统计,维护一个大小为100的小根堆得到每个小文件的top100搜索词
    • 由每个计算节点上所有小文件的小根堆,得到每个计算节点的top100,这部分也由小根堆实现
    • 由每个计算节点的小根堆,得到百亿记录中的top100,这部分同样由小根堆实现,问题解决
2.6 工程师常用服务器集群来设计和实现数据缓存,以下是常见的策略。1,无论是添加、查询还是删除数据,都先将数据的id通过哈希函数转换成一个哈希值,记为key。2,如果目前机器有N台,则计算key%N的值,这个值就是该数据所属的机器编号,无论是添加、删除还是查询操作,都只在这台机器上进行。请分析这种缓存策略可能带来的问题,并提出改进的方案
  • 想法
    • 这种缓存策略的问题是如果增加或删除机器,数据迁移的代价很大
    • 改进方案是一致性哈希
  • 解答步骤
    • 假设哈希函数的哈希值范围是[0, MAX]
    • 把0到MAX首位相连形成一个环
    • 将每台机器的id通过哈希函数转换成一个哈希值,找到这个哈希值在环上的位置
    • 对于数据,也将id通过哈希函数转换成一个哈希值,找到这个哈希值在环上的位置,然后从该位置顺时针移动,遇到的第一个机器,就是这个数据所属的机器
  • 优势
    • 一致性哈希的优点在于增加或删除计算节点时,只会影响到部分的数据,而不是像普通方法那样会影响到所有的数据
    • 至于为什么只会影响到部分数据,把环画出来分析一下就知道了,比较简单
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值