JVM垃圾回收算法
标记-清除(mark-sweep)
步骤:
1.标记出所需要回收的对象
2.在标记完成后统一回收所有被标记的对象
缺点:
1.每次进行垃圾回收的时候,会暂停当前用户线程的执行
2.垃圾回收器见个性的检查,并且标记和清除的过程相对较慢
3.在标记清楚之后可能产生大量的内存碎片,导致一旦需要为大对象分配内存空间时,由于找不到足够大的内存空间,而不得已引发另一次gc的执行。
标记-复制(mark-copy)
步骤:
1.将可用的内存按照容量分为大小相等的两块,使用区和空闲区
2.当这块内存用完了,就将还存活的对象复制到另外一个上面,然后再把已使用过的内存空间一次性清理掉
优点:
不会产生内存碎片
缺点:
1.原有的空间被缩小了一半,空间利用率降低
2.标记复制算法在对象存活率较高的情况下就要进行较多的对象复制操作,效率会变低
3.垃圾回收过程也会暂停用户程序的执行
标记-整理(mark-compact)
步骤:
1.标记
2.让所有存活的对象都像一端移动,然后直接清理掉端边界以外的内存
此算法结合了标记-清除和标记-整理两个阶段。第一个阶段从根节点开始标记所有被引用的对象,第二个阶段比较整个堆,把为标记的对象压缩到堆的其中一块,按顺序排放。此算法避免了标记-清除的内存碎片问题,同时也避免了标记-复制的空间利用率问题
缺点:
暂停当前应用的执行,非实时性的回收
垃圾回收器
分代收集方法论:不同的对象的生命周期是不一样的
将对象按生命周期的不同划分为:新生代、年老代、永久代
其中,永久代主要存放类的信息,所以与java对象的回收关系不大,与回收息息相关的是新生代和年老代
新生代:是所有对象产生的地方
新生代采用了标记-复制的算法
划分为三个部分:eden区、survivor区(from和to),默认比例是8:1:1
当eden区被对象填满时,就会执行minor gc,并把所有的对象转移到其中一个survivor区。这样在一段时间内,总会有一个空的survivor区。经过多次gc周期后,仍然存活下来的对象会被转移到年老代内存空间中。通常这是新生代有资格提升到年老代通过设定的阈值来完成的。
年老代:新生代经历了n此回收后仍没有被清除的对象
年老代采用标记-整理算法
在年老代内存被占满时通常会触发full gc,回收整个堆内存
永久代:用户存放静态文件,比如java类,方法等
永久代堆垃圾回收没有显著的影响
jvm
java虚拟机运行时数据区域被分为五个区域
1.方法区,用于存放类结构信息,包括常量池、静态变量、构造函数等
2.java heap,存储java实例和对象的地方,也是gc的主要区域
3.java stack,java栈总是和线程关联在一起,每当创建一个线程,jvm就会为这个线程创建一个对应的java stack。在这个java栈中又包含了多个栈帧,没运行一个方法就创建一个栈帧,用于存储局部变量表、操作栈、方法返回值等。每一个方法从调用到执行完成的过程,就对应一个栈帧入栈和出栈的过程。所以java栈是私有的
4.程序计数器,用于保存当前线程执行的内存地址。由于jvm程序是多线程的,线程轮流切换,所以为了保证线程切换回来后,还能恢复原先状态,就需要一个独立的计数器,记录之前的中断的地方,程序计数器也是线程私有的。
5.本地方法栈,和java栈的作用差不多,只不过是为jvm使用的native方法服务的
总结:
线程私有的数据区域:
1.java虚拟栈
2.本地方法栈
线程共享的数据区域:
1.堆
2.方法区
hdfs
优点:
1.高容错,副本策略
2.适合批处理,移动计算而不是移动数据
3.适合存储大数据文件
4.可以部署在廉价的机器上
缺点
1.高延迟访问
2.不适合存储大量小文件
3.不支持随机读写,仅支持append
client
1.切分block
2.与namenode通信,获取文件所在的位置
3.与datanode通信,读取或写入文件
namenode
1.接收客户端读写请求
2.保存原数据信息
3.管理datanode,调节各datanode的存储负载
datanode
1.接收客户端读写请求
2.存储文件block
3.定期向namenode汇报自身所持的块的信息
secondarynamenode
1.辅助namenode,分担其工作量
2.定期合并fsimage和edits,并推送给namenode
3.紧急情况,可辅助恢复namenode
zkfc
1.监控各自namenode,将监控的情况汇报给zookeeper
2.接收zookeeper的选举结果,确认另外一个namenode是否存活,将自己监控的namenode提升为active状态
journalnode
1.写数据的时候只需要保证半数以上的节点写入成功就可以了,超过半数的原因为了防止脑裂问题
2.最终一致性
3.存储的是edit文件
hdfs写数据流程
1.客户端向namenode通信请求上传文件
2.namenode会检查要上传的文件是否存在,并返回结果给客户端
3.如果可以上传,客户端对要上传的文件进行切分,并向namenode通信第一个block要上传的位置
4.namenode会挑选出负载较小的三台datanode给客户端
5.客户端挑选其中一台datanode建立pipeline连接,同时,第一台和第二台,第二台和第三台建立pipeline连接,并逐级返回给客户端
6.客户端将第一个block读取到本地缓冲中,并以packet为单位进行传输(64kb),第一台datanode收到数据后传输给第二台,第二台传输给第三台
7.当一个block传输完成后,以同样的方式请求第二个block该如何上传,直至文件上传完成
hdfs读数据流程
1.客户端与namenode通信请求读取某个文件
2.namenode会校验该文件是否存在,存在的话会返回文件所在的datanode服务器
3.客户端挑选一台datanode(就近原则,然后随机)建立socket
4.datanode开始发送数据(从磁盘读取数据流,以packet为单位来做校验)
5.客户端以packet为单位进行接收,现在本地缓冲,然后写入目标文件
MapReduce
ResourceManager:是yarn的资源控制框架的中心模块,负责集群中所有资源的统一管理和分配。它接收来自NM的汇报,建立AM,并将资源派送给AM
NodeManager:NM是RM在每台机器上的代理,负责容器的创建,并监控他们的资源使用情况(cpu、内存、磁盘及网络等),以及向RM提供这些资源的使用报告
ApplicationMaster:yarn中每一个应用都会启动一个AM,负责向RM申请资源,请求NM启动container,并告诉container做什么事情
Container:资源容器,yarn中所有的应用都是container之上运行的,AM也是在container上运行的,不过AM的container是RM申请的。
1.container是yarn中资源的抽象,它封装了某个节点上一定量的资源(cpu和内存两类资源)
2.container由ApplicaitonMaster向ResourceManager申请的,由ResourceManager的资源调度器异步分配给ApplicationMaster
3.container的运行是由AplicationMaster向资源所在的NodeManager发起的,container运行时需提供内部执行的任务命令以及该命令执行所需的环境变量和外部资源(比如词典文件、可执行文件、jar等)
另外,一个应用所需的container分为两大类
1.运行ApplicationMaster的container,这是ResourceManager申请和启动的,用户提交应用程序时,可指定唯一的ApplicationMaster所需的资源
2.运行各类任务的container,这是由ApplicationMaster向ResourceManager申请的,并由ApplicationMaster与NodeManager通信启动的
整个MapReduce的过程分为
Map shuffle combine Reduce
------map端的shuffle
在map端首先接触的是InputSplit,在InputSplit中含有datanode中的数据,每一个InputSplit都会分配一个Mapper任务
当key/value被写入缓冲区之前,都会被序列化为字节流,MapReduce提供了partition接口,它的作用是根据key或者value及reduce的数量来决定当前的这对输出数据最终应该交由哪个reduce task处理。默认对key hash后再以reduce数据取模。默认的取模方式只是为了平均reduce的处理能力。
虽然partition接口会计算出一个值来决定某个输出会交给哪个reduce处理,但是在缓冲区中不会实现物理上的分区,而是将结果加载到key-value后面。物理上的分区是磁盘上进行的。
每个map有一个环形缓冲区,用于存储任务的输出,默认大小100M,一旦缓冲区达到阈值80%,一个后台线程就把内容移除到本地磁盘中指定的目录。在这一步会执行两个操作排序和combine(前提是设置了combine)
spill线程把缓冲区的数据写到磁盘前,会把它进行一个二次排序,首先根据数据所属的partition排序,然后每个partition中再按key排序。输出包括一个索引文件和数据文件。如果设定了combine,将在排序输出的基础上运行。combine就是一个简单的reducer操作,他在执行map任务的节点本身运行,先对map的输出做一次简单的reduce,使得map的输出更紧凑,更少的数据会被写入磁盘和传送reducer。spill文件保存在mapred.local.dir指定的目录中,map任务结束后删除。
每次移除都会在磁盘生成一个溢出文件,如果map的输出结果很大,有多次这样的溢出发生,磁盘上就会有多个溢出文件存在。而如果map的输出很小以至于最终也没有达到阈值,那最后会将其缓冲区的内容写入磁盘。
因为最终的文件最有一个,所以需要将这些溢出问爱你归并在一起,这个过程叫做merge。因为merge是将溢出文件合并到一个文件,所以可能也会有相同的key存在,在这个过程中如果client设置了combine,也会使用combine来合并相同的key。
溢出操作时写到了磁盘,并不一定就是最终的结果,因为最终的结果是要有一个文件,除非map的输出很小以至于没有发生溢出(也就是说磁盘只有一个文件)。
-----reduce端shuffle
copy阶段
reduce端默认有5个数据复制线程从map端复制数据,其通过http方式得到map对应的分区的输出文件。reduce端并不是等map端执行完成后将数据传过来,而是直接去map端copy输出文件。
merge阶段
reduce端的shuffle也有一个环形缓冲区,它的大小比map灵活,由copy阶段获得的数据,会存放在这个缓冲区中。同样,当达到阈值是会发生溢出操作,这个过程如果设置了combiner也是会执行的,这个过程会一直执行直到所有的map输出都被复制过来,如果形成了多个磁盘文件还会进行合并,最后一次合并的结果作为reduce的输入而不是写入到磁盘中。
当reduce的输入文件确定后,整个shuffle操作才最终结束了。之后就是reduce的执行,最后reduce会把结果存在hdfs上。
hbase
hbase是一个高可用,高性能,面向列,可伸缩,实时读写的分布式数据库
利用hdfs作为文件存储系统,利用mapreduce来处理hbase中海量数据,利用zookeeper作为分布式协调服务
主要存储非结构和半结构化数据
hbase优点
1.大,一个表可以由上亿行,上百万列
2.面向列,面向列的存储和权限控制,列独立检索
3.稀疏,对于为null的列,并不占用存储空间,因此,表的设计可以很稀疏
4.无模式,每一行都是一个一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中不同的行可以有截然不同的列
5.数据多版本,每个单元中的数据可以有多个版本,默认情况下,版本号自动分配,版本号就是单元格插入的时间戳
6.数据类型单一,hbase中的数据都是字符串
hbase的数据模型
rowkey:用于唯一标识hbase中的一条数据,不可重复,按照字典顺序,只能存储64kb的字节数组,因此一般rowkey设计要简短
timestamp:hbase自动赋值时间戳,作为版本号,64位整型,hbase每个cell存储单位对同一份数据有多个版本,通过时间戳区分版本版本之间的差异,按时间倒序排序
cf:列族,可包含多个列,权限控制,存储以及调优都是在列族层面进行的,hbase把同一个列族里面的数据存储在同一个目录下,有几个文件保存storefile
column:列,对应key,一列可以在多个版本中维护不同的数据
cell:是未解析的字节数组,由{rowkey, column(=
各个角色功能
client
包含访问hbase的接口,并维护cache来加快对hbase的访问
zookeeper
1.保证任何时候,集群中只有一个master
2.保存所有的region寻址入口
3.实时监控regionserver的上下线信息,并通知master
4.存储habse的schema和表的元数据信息
master
1.为regionserver分配region
2.负责regionserver的负载均衡
3.发现失效的regionserver并重新分配其它的regionserver工作
4.管理用户对表的增删改操作
regionserver
1.维护多个region,处理这些region的io请求,真正的增删改查操作
2.水平切分运行中变得过大的region
region
每个region保存表中某段连续的数据,每个表一开始只有要给region,随着数据量的不断增加,当达到一定的阈值时,region就会被regionserver水平切分成两个新的region,当region很多时,将会保存到其他的regionserver上
store
一个region由多个store组成,每一个store对应一个列族,stroe包含memorystore和storefile
hbase写流程
1.client通过zookeeper的调度,向regionserver发出写数据请求,在region中写数据
2.数据被写入memstore,直到memstore达到阈值
3.memstore中的数据被flush成一个storefile
4.随着storefile文件的不断增加,当其数量增长到一定阈值,触发compact合并操作,将多个storefile合并成一个storefile,同时进行版本的合并和数据的删除
5.storefile通过不断的compact合并操作,逐步形成越来越大的storefile
6.当这个storefile大小超过了一定阈值后,触发split操作,把当前region spilt成两个新的region,父region下线,新spilt的两个region分配到相应的regionserver上,是得原先的region压力得以分流到两个region上
hbase读数据流程
1.client访问zookeeper,查找root表所在的位置
2.从root表中获取存放目标数据的region信息,从而找到对应的regionserver
3.通过regionserver的内存分为memorystore和blockcache两部分,memstore主要用于写数据,blockcache主要用于读数据。请求先到memstore中查数据,查不到就到blockcache中查,再查不到就会到storefile上读,并把读的结果放入blockcacje中
hbase优化的方法
1.较少的调整
hbase中有几个内容,如region、hfile,所以通过一些方法减少这些带来的io开销调整
region:如果没有预建分区,那么随着region中条数的增加,region会进行分裂,这将增加io开销,所以解决方法就是根据你的rowkey预建分区,减少region的动态分裂
hfile:hfile是数据的底层存储文件,在每个memstore进行刷新时会生成一个hfile,当hfile增加到一定的时候,会将属于这个region的hfile进行合并,这个步骤带来的开销时不可避免的,到那时合并后hfile大小如果大于设定的阈值,那就会重新分裂,为了减少这样无畏的io开销,简易估计项目数据量的大小,给hfile设定一个合适的值
2.减少启停
数据库事务机制就为了更好的实现批量导入,减少数据库开启关闭带来的开销,那么hbase中也存在频繁开始关闭问题
关闭compact,在闲时手动compact
因为hbase中存在minor compact,也就是对hfile进行合并,所谓合并就是io读写,大量hfile进行肯定会带来i哦开销,甚至io风暴,所以为了避免这种不受控的意外发生,建议关闭自动compact,在闲时手动进行
通过hbase-shell或者javaapi的put来实现大量数据的写入,那么性能肯定查并且还可能带来一些意想不到的问题,所以当需要大量离线数据时建议使用bulkload
3.较少数据
开始过滤,提高查询性能
开启bloomfilter,bloomfilter是列族级别的过滤,在生成一个storefile同时会生成一个metablock,用于查询时过滤数据
使用压缩,一般推荐使用snappy和lzo压缩
4.合理设计
rowkey设计,应具备以下几个属性
散列性:散列性能够保证相同相似的rowkey聚合,相异的rowkey分散,有利于查询
简短性:rowkey作为key的一部分存储在hfile中,如果为了可读性将rowley设计的过长,那么将会增加存储压力
唯一性:rowkey必须具备明显的区别
hbase中rowfilter和bloomfilter原理
1.rowfilter原理简析
rowfilter顾名思义就是对rowkey进行过滤,那么rowkey的过滤无非就是相等 大于greater 大于等于 小于等于和不等于集中过滤方式。hbase中rowfilter采用比较符结合比较器进行过滤
比较器的类型如下
BinaryComparator
BinaryPrefixComparator
NullComparator
BitComparator
RegexStringComparator
SubStringComparator
2.bloomfilter原理简析
主要功能:提供随机读的性能
存储开销:bloomfilter是列族级别的配置,一旦表格中开始了bloomfilter,那么在生成storefile的同时会生成一份包含bloomfilter结构的文件metablock,所以增加一定的存储和内存开销
粒度控制:row和rowcol
bloomfilter原理
内部是一个bit数组,初始值为0,
插入元素时进行hash并映射到数组中的某一个index,将其置为1,再进行多次不同的hash算法,将映射到的index置为1,同一个index只需置一次
查询时使用跟插入时相同的hash算法,如果再对应的index的值为1,那么就可以认为该元素可能存在,注意,只是可能存在,所以bloomfilter只能保证过滤掉不包含的元素,而不能保证误判
region如何预建分区
hbaseshell
create 't1','f1',SPLITS => ['10','20','30']
create 't1','f1',SPLIT_FILE => 'split.txt'
java api
Byte[][] splitKeys = {{1,2,3},{4,5,6}}
Admin.createTable(tableDesc, splitkeys)
Regionserver宕机如何处理
1.zookeeper会监控regionserver的上下线情况,当zk发现某个regionserver宕机后会通知master
2.该regionserver会停止对外提供服务,就是它所负责的region暂时停止对外提供服务
3.master会将该regionserver所负责的region转移到其他的region上,并且会对regionserver上存在的memstore中还未持久化到磁盘的数据进行恢复
4.这个恢复工作是由wal重播来完成的