序列化

喵了个喵,我又遇到瓶颈了

[TOC]

一、序列化和反序列化的定义和场景

序列化:将对象写入到IO流中

反序列化:从IO流中恢复对象

序列化机制将实现序列化的Java对象转化为字节数组序列。可以使对象可以脱离程序而独立运行

场景和要求:保存到磁盘;在网络中传输。要保存到磁盘和在远程传输的java对象要求都必须是可序列化的。

image-20190907150807138

二、序列化和反序列化的java实现

Serializable接口

一个标记接口,不用实现任何方法。一旦实现了此接口,该类的对象就是可序列化的。

序列化步骤

1 创建ObjectOutputStream输出流;2 调用ObjectOutputStream对象的writeObject输出可序列化对象。

若对象不是序列化对象,序列化是将抛出 NotSerializableException 异常

反序列化步骤

1 创建ObjectInputStream输入流;2 调用ObjectInputStream对象的readObject()得到可序列化对象

demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class People implements Serializable {
private String name;
private String city;

public void setCity(String city) {
this.city = city;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
People people = new People();
people.setCity("成都");
people.setName("假老练");
People people1 = new People();
people1.setCity("北京");
people1.setName("风车车");
try {
FileOutputStream fileOutputStream = new FileOutputStream("object.txt");
ObjectOutputStream os = new ObjectOutputStream(fileOutputStream);
os.writeObject(people);
} catch (Exception e) {
e.printStackTrace();
}
try {
FileInputStream fileInputStream = new FileInputStream("object.txt");
ObjectInputStream os = new ObjectInputStream(fileInputStream);
People peopleResult = (People) os.readObject();
} catch (Exception e) {
e.printStackTrace();
}
}
}

如果需要序列化的类的属性含有非基本数据类型和String类型,即引用类型,那么该引用类型也比如可序列化。否则依然会抛出 NotSerializableException 异常

serialVersionUID的作用

Java 的序列化,通过在运行时判断类的serialVersionUID来验证版本一致性。

在进行反序列化时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。实测如果id一致,属性发生较小变化,对象也会创建出来,并将属性按属性名对号入座。

当实现序列化的时候,建议显式定义serialVersionUID,若不显式定义 serialVersionUID 的值,Java 会根据类细节自动生成 serialVersionUID 的值。可能造成以下两个问题。1.如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。2.类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,也有可能会导致不同的serialVersionUID,即不同机器或不同版本jdk反序列化可能失败。

##总计

  1. 序列化是将对象写入到IO字节流,反序列化是从IO字节流中恢复对象
  2. 序列化的两个主要作用是用来存储和网络传输

进程,线程与多核,多cpu之间的关系

喵了个喵,我又遇到瓶颈了

[TOC]

cpu架构和工作原理

计算机有5大基本组成部分,运算器,控制器,存储器,输入和输出。运算器和控制器封装到一起,加上寄存器组和cpu内部总线构成中央处理器(CPU)。cpu的根本任务,就是执行指令,对计算机来说,都是0,1组成的序列,cpu从逻辑上可以划分为3个模块:控制单元、运算单元和存储单元。这三个部分由cpu总线连接起来。

image-20190902202929616

CPU的运行原理就是:控制单元在时序脉冲的作用下,将指令计数器里所指向的指令地址(这个地址是在内存里的)送到地址总线上去,然后CPU将这个地址里的指令读到指令寄存器进行译码。对于执行指令过程中所需要用到的数据,会将数据地址也送到地址总线,然后CPU把数据读到CPU的内部存储单元(就是内部寄存器)暂存起来,最后命令运算单元对数据进行处理加工。周而复始,一直这样执行下去。

多核cpu和多cpu

架构

多个物理CPU,CPU通过总线进行通信,效率比较低。

image-20190904121329148

多核CPU,不同的核通过L2 cache进行通信,存储和外设通过总线与CPU通信

image-20190904121349591

cpu的缓存

CPU缓存是位于CPU与内存之间的临时数据交换器,它的容量比内存小的多但是交换速度却比内存要快得多。CPU缓存一般直接跟CPU芯片集成或位于主板总线互连的独立芯片上。

image-20190905092214302

随着多核CPU的发展,CPU缓存通常分成了三个级别:L1L2L3。级别越小越接近CPU,所以速度也更快,同时也代表着容量越小。L1 是最接近CPU的, 它容量最小(例如:32K),速度最快,每个核上都有一个 L1 缓存,L1 缓存每个核上其实有两个 L1 缓存, 一个用于存数据的 L1d Cache(Data Cache),一个用于存指令的 L1i Cache(Instruction Cache)。L2 缓存 更大一些(例如:256K),速度要慢一些, 一般情况下每个核上都有一个独立的L2 缓存; L3 缓存是三级缓存中最大的一级(例如3MB),同时也是最慢的一级, 在同一个CPU插槽之间的核共享一个 L3 缓存。

读取数据过程。就像数据库缓存一样,首先在最快的缓存中找数据,如果缓存没有命中(Cache miss) 则往下一级找, 直到三级缓存都找不到时,向内存要数据。一次次地未命中,代表取数据消耗的时间越长。

计算过程。程序以及数据被加载到主内存;指令和数据被加载到CPU的高速缓;CPU执行指令,把结果写到高速缓存;高速缓存中的数据写回主内存

进程和线程

进程是程序的一次执行,一个程序有至少一个进程,是资源分配的最小单位,资源分配包括cpu、内存、磁盘IO等。线程是程序执行的最小单位,一个进程有至少一个线程。

进程和线程在多核cpu,多cpu中的运行关系

多cpu的运行,是针对进程的运行状态来说的;多核cpu的运行,是针对线程的运行状态来说的。

操作系统会拆分CPU为一段段时间的运行片,轮流分配给不同的程序。对于多cpu,多个进程可以并行在多个cpu中计算,当然也会存在进程切换;对于单cpu,多个进程在这个单cpu中是并发运行,根据时间片读取上下文+执行程序+保存上下文。同一个进程同一时间段只能在一个cpu中运行,如果进程数小于cpu数,那么未使用的cpu将会空闲。

对于多核cpu,进程中的多线程并行执行,执行过程中存在线程切换,线程切换开销较小。对于单核cpu,多线程在单cpu中并发执行,根据时间片切换线程。同一个线程同一时间段只能在一个cpu内核中运行,如果线程数小于cpu内核数,那么将有多余的内核空闲。

总结

1 单CPU中进程只能是并发,多CPU计算机中进程可以并行。

2单CPU单核中线程只能并发,单CPU多核中线程可以并行。

3 无论是并发还是并行,使用者来看,看到的是多进程,多线程。

Hadoop系列(四)Hadoop三大核心之HDFS Java API

喵了个喵,我又遇到瓶颈了

[TOC]

HDFS 设计的主要目的是对海量数据进行存储,也就是说在其上能够存储很大量的文件。

HDFS 将这些文件分割之后,存储在不同的 DataNode 上,HDFS 提供了通过Java API 对 HDFS 里面的文件进行操作的功能,数据块在 DataNode 上的存放位置,对于开发者来说是透明的。

使用 Java API 可以完成对 HDFS 的各种操作,如新建文件、删除文件、读取文件内容等。下面将介绍 HDFS 常用的 Java API 及其编程实例。

概念

  • Configuration 封装了客户端或者服务器的配置
  • FileSystem 文件系统对象,用该对象的方法来对文件进行操作
  • FileStatus 用于向客户端展示系统中文件和目录的元数据
  • FSDatalnputStream HDFS 中的输入流,用于读取 Hadoop 文件
  • FSDataOutputStream HDFS 中的输出流,用于写 Hadoop 文件
  • Path 用于表示 Hadoop 文件系统中的文件或者目录的路径

具体操作

  1. 导入maven依赖包
1
2
3
4
5
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.1</version>
</dependency>
  1. 初始化配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Configuration conf;
FileSystem fileSystem;

public HdfsAPI() {
conf = new Configuration();
conf.set("dfs.replication", "2");
conf.set("dfs.blocksize", "128m");
try {
fileSystem = FileSystem.get(new URI("hdfs://${NameNode}:9000"), conf, "hadoop");
} catch (Exception e) {
e.printStackTrace();
}

}
  1. get文件 get
1
2
3
4
public void testGet() throws IllegalArgumentException, IOException {
fileSystem.copyToLocalFile(new Path("/output/part.txt"), new Path("~/Downloads"));
fileSystem.close();
}
  1. 获取文件信息 ls
1
2
3
4
5
6
7
8
9
10
11
12
public void testLs() throws IllegalArgumentException, IOException {
RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true);
while (listFiles.hasNext()) {
LocatedFileStatus status = listFiles.next();
System.out.println("路径:" + status.getPath());
System.out.println("块大小:" + status.getBlockSize());
System.out.println("文件长度:" + status.getLen());
System.out.println("副本数:" + status.getReplication());
System.out.println("块的位置信息:" + Arrays.toString(status.getBlockLocations()) + "\n");
}
fileSystem.close();
}
  1. 创建目录,多级目录 mkdir
1
2
3
4
public void testMkdir() throws IllegalArgumentException, IOException {
fileSystem.mkdirs(new Path("/output/test/testmk"));
fileSystem.close();
}
  1. 删除文件,目录 rm
1
2
3
4
5
6
7
public void testDeldir() throws IllegalArgumentException, IOException {
boolean delete = fileSystem.delete(new Path("/output/test/testmk"), true);
if (delete) {
System.out.println("文件已经删除");
}
fileSystem.close();
}
  1. 读取hdfs文件内容
1
2
3
4
5
6
7
8
9
10
11
12
public void testReadData() throws IOException {
FSDataInputStream in = fileSystem.open(new Path("/test.txt"));//hdfs自带流打开文件
BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8"));//读入流并放在缓冲区
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}

in.close();
br.close();
fileSystem.close();
}
  1. 读取hdfs中文件中指定偏移的内容
1
2
3
4
5
6
7
8
9
public void testRandomReadData() throws IOException {
FSDataInputStream in = fileSystem.open(new Path("/test.txt"));
in.seek(12);//定位到12位置开始读
byte[] buf = new byte[16];//往后读取16个位
in.read(buf);//ba流读到buf中
System.out.println(new String(buf));
in.close();
fileSystem.close();
}
  1. 数据写到hdfs中
1
2
3
4
5
6
7
8
9
10
11
public void testWriteData() throws IOException {
FSDataOutputStream out = fileSystem.create(new Path("/yy.jpg"), false);
FileInputStream in = new FileInputStream("~/Download/wechatpic_20190309221605.jpg");
byte[] buf = new byte[1024];
int read = 0;
while ((read = in.read(buf)) != -1) {
out.write(buf, 0, read);
}
out.close();
fileSystem.close();
}

Hadoop系列(三)Hadoop三大核心之HDFS shell常用命令

喵了个喵,我又遇到瓶颈了

[TOC]

HDFS常用命令

help 查看所有命令

[172.23.7.9:hadoop]$ hadoop fs help

查看路径文件

[172.23.7.9:hadoop]$ hadoop fs -ls /

创建文件夹

[172.23.7.9:hadoop]$ hadoop fs -mkdir /test

创建多级文件夹

[172.23.7.9:hadoop]$ hadoop fs -mkdir -p /test/test1/test2

查看指定目录下和子目录下所有文件

[172.23.7.9:hadoop]$ hadoop fs -ls -R /test

上传文件

[172.23.7.9:hadoop]$ hadoop fs -put part.txt /test

or

[172.23.7.9:hadoop]$ hadoop fs -copyFromLocal part.txt /test

下载文件

[172.23.7.9:hadoop]$ hadoop fs -get /test/part.txt ~/test

or

[172.23.7.9:hadoop]$ hadoop fs -copyToLocal /test/part.txt ~/test

合并下载

[172.23.7.9:hadoop]$ hadoop fs -getmerge /test/part0.txt /test/part1.txt ./temp.txt

复制

[172.23.7.9:hadoop]$ hadoop fs -cp /test/part.txt /output

移动

[172.23.7.9:hadoop]$ hadoop fs -mv /test/part.txt /output

删除

[172.23.7.9:hadoop]$ hadoop fs -rm /test/part.txt

强制删除

[172.23.7.9:hadoop]$ hadoop fs -rm -r /test/part.txt

查看文件内容

[172.23.7.9:hadoop]$ hadoop fs -cat /test/part.txt

显示文件大小

[172.23.7.9:hadoop]$ hadoop fs -du -h /test/part.txt

test

[172.23.7.9:hadoop]$ hadoop fs -test -[ezd] /test/part.txt

选项:
-e 检查文件是否存在。如果存在则返回0。
-z 检查文件是否是0字节。如果是则返回0。
-d 如果路径是个目录,则返回1,否则返回0。

web界面

http://xx.xx.xx.xx:9870/explorer.html#/

image-20190830010745946

Hadoop系列(二)Hadoop三大核心之HDFS基础

喵了个喵,我又遇到瓶颈了

[TOC]

针对海量数据,核心问题始终是计算和存储。当数据集的大小超过一台独立物理计算机的存储能力时,就有必要对它进行分区并存储到多台机器上。跨机器存储的文件系统就被成为分布式文件系统。分布式系统架构于网络之上,势必引入网络编程的复杂性,如何实现容忍节点故障但不丢失数据,是HDFS的重要挑战。

hdfs基础

Hadoop 自带HDFS分布式文件系统:Hadoop Distributed Filesystem。也简称DFS。主要用来解决海量数据的存储问题。

HDFS有以下两点特性

  • 文件系统:用于存储文件,通过统一目录树定位
  • 分布式:很多机器共同支撑其功能

重要概念

数据块

和一般的文件系统一样,HDFS也有块(block)的概念,HDFS上的文件也被划分为块大小的多个分块作为独立的存储单元。

Hadoop 1.x 默认大小为64MB, 2.x和3.x均为128MB。具体指定版本的默认值,可参见官网块的定义。HDFS的块比磁盘的块大,是为了最小化寻址开销,减少寻址定位所需时间。

与磁盘文件系统不一样的是*HDFS中小于一个块大小的文件不会占据整个块的空间 *例:当一个1MB的文件存储在一个128MB的块中时,文件只使用1MB的磁盘空间,而不是128MB。当一个150M的文件要存储到HDFS中,将会拆分成2个块,大小分别是128M、22M。

设置数据块的好处:

(1)一个文件的大小可以大于集群任意节点磁盘的容量

(2)容易对数据进行备份,提高容错能力,块丢失可快速从其它节点复制

(3)使用抽象块概念而非整个文件作为存储单元,大大简化存储子系统的设计

HDFS集群有两类节点以管理节点-工作节点的方式运行。即NameNode和DataNode。

NameNode(NN)

文件系统的管理节点。管理文件系统的命名空间,维护着文本系统树及整棵树内所有文件和目录。基于内存存储,在内存中保存着文件系统每个文件和每个数据块的引用关系以及块信息等。文件目录在NameNode重启后,需要重建。

功能:

  • 接收客户端读写服务
  • 收集DataNode汇报的Block列表信息

DataNode(DN)

文件系统的工作节点,多个节点共同工作。本地磁盘目录存储数据,文件形式。

功能:

  • 文件形式存储数据(Block)
  • 存储Block的元数据信息文件 (md5)
  • 启动时向NameNode汇报block信息
  • 与NameNode保持心跳连接(3s/次)

NameNode虽然以内存方式存储,但是NameNode也会在适当时候持久化两类文件到磁盘。

  • fsimage:NameNode启动时对整个文件系统的快照
  • edit logs:NameNode启动后,对文件系统的改动序列

image-20190827232356723

只有在NameNode重启时,edit logs才会合并到fsimage文件中,从而得到一个文件系统的最新快照。但是在产品集群中NameNode是很少重启的,这也意味着当NameNode运行了很长时间后,edit logs文件会变得很大。这会引发以下严重问题:1.edit logs文件会变的很大,不容易管理;2.重启会花费很长时间,因为有很多改动,可能经历好几个小时甚至几十个小时,这是不能容忍的。

Secondary NameNode (SNN)

SecondaryNameNode就是来帮助解决上述问题的,职责是帮助NN合并edits log成fsimage,减少NameNode启动时间

SNN 合并edits触发条件:
1.定期触发。默认一小时。
2.时间未到的情况,edits log大小超过容量也会触发。默认 64M。

配置文件core-site.xml 可设置时间间隔(fs.checkpoint.period )和edits log容量(fs.checkpoint.size)。

5D3FAC2F-F9B2-4F08-B5EA-68771B0BA0F8

Hadoop 特点

HDFS也是按照Master和Slave的结构。分NameNode、SecondaryNameNode、DataNode这几个角色。

img

因其架构方案,拥有很多特点:
保存多个副本,且提供容错机制,副本丢失或宕机自动恢复(默认存3份)。
  可运行在廉价的机器上
  适合大数据的处理。HDFS默认会将文件分割成block。然后将block按键值对存储在HDFS上,并将键值对的映射存到内存中。

当然HDFS也有其局限性:
1.低延时数据访问。在用户交互性的应用中,应用需要在ms或者几个s的时间内得到响应。由于HDFS为高吞吐率做了设计,也因此牺牲了快速响应。对于低延时的应用,可以考虑使用HBase或者Cassandra。
2.大量的小文件。标准的HDFS数据块的大小是64M,存储小文件并不会浪费实际的存储空间,但是无疑会增加了在NameNode上的元数据,大量的小文件会影响整个集群的性能。
3.多用户写入,修改文件。HDFS的文件只能有一个写入者,而且写操作只能在文件结尾以追加的方式进行。它不支持多个写入者,也不支持在文件写入后,对文件的任意位置的修改。
但是在大数据领域,分析的是已经存在的数据,这些数据一旦产生就不会修改,因此,HDFS的这些特性和设计局限也就很容易理解了。HDFS为大数据领域的数据分析,提供了非常重要而且十分基础的文件存储功能。

Hadoop HA

可靠性

  1. 冗余备份
    每个文件存储成一系列数据块(Block)。为了容错,文件的所有数据块都会有副本(副本数量即复制因子,可配置)(dfs.replication)
  2. 副本存放
    采用机架感知(Rak-aware)的策略来改进数据的可靠性、高可用和网络带宽的利用率
  3. 心跳检测
    NameNode周期性地从集群中的每一个DataNode接受心跳包和块报告,收到心跳包说明该DataNode工作正常
  4. 安全模式
    系统启动时,NameNode会进入一个安全模式。此时不会出现数据块的写操作。
  5. 数据完整性检测
    HDFS客户端软件实现了对HDFS文件内容的校验和(Checksum)检查(dfs.bytes-per-checksum)。

单点故障问题

因为NameNode部署为单点失效,存在单点故障问题,当NameNode,那么客户端或MapReduce作业均无法读写查看文件。注意HDFS已有存储不会丢失。

解决方案:

启动一个拥有文件系统元数据的新NameNode(这个一般不采用,因为复制元数据非常耗时间)
配置一对活动-备用(Active-Sandby)NameNode,活动NameNode失效时,备用NameNode立即接管,用户不会有明显中断感觉。
    共享编辑日志文件(借助NFS、zookeeper等)
    DataNode同时向两个NameNode汇报数据块信息
    客户端采用特定机制处理 NameNode失效问题,该机制对用户透明

Hadoop系列(一)开篇简介

喵了个喵,我又遇到瓶颈了

[TOC]

谁说大象不会跳舞

Hadoop是什么

Hadoop的官网:http://hadoop.apache.org/

官网定义:The Apache Hadoop software library is a framework that allows for the distributed processing of large data sets across clusters of computers using simple programming models.

Hadoop: 适合大数据的分布式存储和计算平台

现为Apache顶级开源项目,Hadoop不是指具体一个框架或者组件,它是Apache软件基金会下用Java语言开发的一个开源分布式计算平台。实现在大量计算机组成的集群中对海量数据进行分布式计算,适合大数据的分布式存储和计算平台。

举个简单例子:假如说你有一个篮子水果,你想知道苹果和梨的数量是多少,那么只要一个一个数就可以知道有多少了。如果你有一个集装箱水果,这时候就需要很多人同时帮你数了,这相当于多进程或多线程。如果你很多个集装箱的水果,这时就需要分布式计算了,也就是Hadoop。Hadoopd之所谓会诞生,主要是由于进入到大数据时代,计算机需要处理的数据量太过庞大。这时就需要将这些庞大数据切割分配到N台计算机进行处理。当大量信息被分配到不同计算机进行处理时,要确保最终得到的结果正确就需要对这些分布处理的信息进行管理,hadoop就是这样的一套解决方案。

总结

1、Hadoop是Apache旗下的一套开源适合大数据的分布式存储和计算平台平台

2、Hadoop提供的功能:利用服务器集群,根据户自定义业逻辑对海量数进行分布式处理

hadoop的概念:

  狭义上: 就是apache的一个顶级项目:apahce hadoop

  广义上: 就是指以hadoop为核心的整个大数据处理体系

Hadoop的起源

HADOOP最早起源于Nutch。Nutch的设计目标是构建一个大型的全网搜索引擎,为Apache Lucene项目的一部分,包括网页抓取、索引、查询等功能,但随着抓取网页数量的增加,遇到了严重的可扩展性问题——如何解决数十亿网页的存储和索引问题。
这个问题的解决方案源于Google的三大论文 :GFS ,BigTable和MapReduce。受此启发的Doug Cutting(Hadoop之父)等人用业余时间实现了DFS和MapReduce机制。2006年2月从Nutch被分离出来,成为一套完整独立的软件,起名为Hadoop。

Hadoop的成长过程经历了:Lucene–>Nutch—>Hadoop

三篇论文的核心思想逐步演变,最终:

GFS—->HDFS
Google MapReduce—->Hadoop MapReduce
BigTable—->HBase

Hadoop版本与架构核心

Apache开源社区版本,现已到3.x

Hadoop1.0版本两个核心:HDFS+MapReduce

Hadoop2.0版本,引入了Yarn。核心:HDFS+Yarn+Mapreduce

​ Yarn是资源调度框架。能够细粒度的管理和调度任务。此外,还能够支持其他的计算框架,比如spark等。

img

Hadoop3.0版本,未引入新核心,在原核心上,升级了很多东西。具体参见官网

Hadoop的核心组件:

  1)Hadoop Common:支持其他Hadoop模块的常用工具。

  2) Hadoop分布式文件系统(HDFS™):一种分布式文件系统,可提供对应用程序数据的高吞吐量访问。

  3) Hadoop YARN:作业调度和集群资源管理的框架。

  4) Hadoop MapReduce:一种用于并行处理大型数据集的基于YARN的系统。

  大数据的处理主要就是存储计算

如果说安装hadoop集群,其实就是安装了两个东西: 一个操作系统YARN 和 一个文件系统HDFS。其实MapReduce就是运行在YARN之上的应用。

操作系统   文件系统   应用程序
win7     NTFS    QQ,WeChat
YARN     HDFS    MapReduce

Hadoop理念

Hadoop可运行于一般的商用服务器上,具有高容错、高可靠性、高扩展性等特点

特别适合写一次,读多次的场景

适合场景

  • 大规模数据
  • 流式数据(写一次,读多次)
  • 商用硬件(一般硬件)

不适合场景

  • 低延时的数据访问
  • 大量的小文件
  • 频繁修改文件

PS

Hadoop起源的三个google论文 中文版

GFS Google的分布式文件系统Google File System
BigTable 一个大型的分布式数据库
MapReduce Google的MapReduce开源分布式并行计算框架

|