【JVM】JVM系列之Class文件(三)

一、前言 随着我们学习的不断深入,我相信读者对class文件很感兴趣,class文件是用户编写程序与虚拟机之前的桥梁,程序通过编译形成class文件,class文件之后会载入虚拟机,被虚拟机执行,下面我么来一起揭开class文件的神秘面纱。 二、什么是class文件 class文件是二进制文件,通常是以.class文件结尾的文件,它是以8位字节为基础单位的二进制流,各个数据项紧密排列在class文件中,数据项的基本类型为u1,u2,u4,u8,分别表示一个字节,两个字节,四个字节,八个字节的无符号数。 三、class文件数据结构 其实对于class文件而言,总体的数据结构看上去很规整,具体的结构如下图所示 下面我们将用一个例子详细讲解class文件的各个部分。 四、示例 public class Test implements Cloneable { private String name; public Test() { } public Test(String name) { this.name = name; } public…

【JVM】JVM系列之垃圾回收(二)

一、为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此。所以,垃圾回收是必须的。 二、哪些内存需要进行垃圾回收 对于虚拟机中线程私有的区域,如程序计数器、虚拟机栈、本地方法栈都不需要进行垃圾回收,因为它们是自动进行的,随着线程的消亡而消亡,不需要我们去回收,比如栈的栈帧结构,当进入一个方法时,就会产生一个栈帧,栈帧大小也可以借助类信息确定,然后栈帧入栈,执行方法体,退出方法时,栈帧出栈,于是其所占据的内存空间也就被自动回收了。而对于虚拟机中线程共享的区域,则需要进行垃圾回收,如堆和方法区,线程都会在这两个区域产生自身的数据,占据一定的内存大小,并且这些数据又可能会存在相互关联的关系,所以,这部分的区域不像线程私有的区域那样可以简单自动的进行垃圾回收,此部分区域的垃圾回收非常复杂,而垃圾回收也主要是针对这部分区域。 三、垃圾收集算法 任何垃圾收集算法都必须做两件事情。首先,它必须检测出垃圾对象。其次,它必须回收垃圾对象所使用的堆空间并还给程序。那么问题来了,如何检测出一个对象是否为垃圾对象呢?一般有两种算法解决这个问题。1. 引用计数算法 2. 可达性分析算法。 1.引用计数算法 堆中的每一个对象有一个引用计数,当一个对象被创建,并把指向该对象的引用赋值给一个变量时,引用计数置为1,当再把这个引用赋值给其他变量时,引用计数加1,当一个对象的引用超过了生命周期或者被设置为新值时,对象的引用计数减1,任何引用计数为0的对象都可以被当成垃圾回收。当一个对象被回收时,它所引用的任何对象计数减1,这样,可能会导致其他对象也被当垃圾回收。 问题:很难检测出对象之间的额相互引用(引用循环问题) 如下代码段可以从反面验证虚拟机的垃圾回收不是采用的引用计数。 package com.leesf.chapter3; public class ReferenceCountingGC { public Object instance = null; private static final int _1MB =…

【JVM】JVM系列之JVM体系(一)

一、前言   为什么要学习了解Java虚拟机 1.我们需要更加清楚的了解Java底层是如何运作的,有利于我们更深刻的学习好Java。 2.对我们调试错误提供很宝贵的经验。 3.这是合格的Java程序必须要了解的内容。 基于此,笔者打算出一个Java虚拟机的系列,加深自己对知识点的理解,同时也方便各位有需要的园友。 二、Java虚拟机的定义 Java虚拟机(Java Virtual Machine),简称JVM。当我们说起Java虚拟机时,可能指的是如下三种不同的东西: 1.抽象规范。 2.一个具体的实现。 3.一个运行中的虚拟机实例。 Java虚拟机抽象规范仅仅是一个概念,在《The Java Virtual Machine Specification》中有详细的描述。该规范的实现,可能来自多个提供商,并存在于多个平台上,它或者是全部由软件实现,或者是以硬件和软件相结合的方式来实现。当运行一个Java程序的时候,也就在运行一个Java虚拟机实例。注意,我们所说的Java平台无关性是指class文件的平台无关性,JVM是和平台相关的,不同操作系统对应不同的JVM。 三、Java虚拟机的总体框架图 下图是整个Java虚拟机的总体框架图,之后我们会经常涉及到。 四、Java虚拟机的体系结构 下图表示了Java虚拟机的结构框图,主要描述了JVM子系统和内存区。 五、Java虚拟机各组成部分 5.1 类装载子系统 类装载子系统负责查找并装载类型,Java虚拟机由两种类装载器:启动类装载器(Java虚拟机实现的一部分)和用户自定义类装载器(Java程序的一部分)。类装载子系统负责定位和导入二进制class文件,并且保证导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用。类装载器必须严格按照如下顺序进行类的装载。 1) 装载 — 查找并装载类型的二进制数据…

【分布式】Zookeeper与Paxos

一、前言 在学习了Paxos在Chubby中的应用后,接下来学习Paxos在开源软件Zookeeper中的应用。 二、Zookeeper Zookeeper是一个开源的分布式协调服务,其设计目标是将那些复杂的且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一些列简单的接口提供给用户使用。其是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它实现诸如数据发布/发布、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。其可以保证如下分布式一致性特性。 ① 顺序一致性,从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到Zookeeper中去。 ② 原子性,所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,即整个集群要么都成功应用了某个事务,要么都没有应用。 ③ 单一视图,无论客户端连接的是哪个Zookeeper服务器,其看到的服务端数据模型都是一致的。 ④ 可靠性,一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会一直被保留,除非有另一个事务对其进行了变更。 ⑤ 实时性,Zookeeper保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。 2.1 设计目标 Zookeeper致力于提供一个高性能、高可用、且具有严格的顺序访问控制能力(主要是写操作的严格顺序性)的分布式协调服务,其具有如下的设计目标。 ① 简单的数据模型,Zookeeper使得分布式程序能够通过一个共享的树形结构的名字空间来进行相互协调,即Zookeeper服务器内存中的数据模型由一系列被称为ZNode的数据节点组成,Zookeeper将全量的数据存储在内存中,以此来提高服务器吞吐、减少延迟的目的。 ② 可构建集群,一个Zookeeper集群通常由一组机器构成,组成Zookeeper集群的而每台机器都会在内存中维护当前服务器状态,并且每台机器之间都相互通信。 ③ 顺序访问,对于来自客户端的每个更新请求,Zookeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序。 ④ 高性能,Zookeeper将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,因此它尤其适用于以读操作为主的应用场景。 2.2 基本概念 ① 集群角色,最典型的集群就是Master/Slave模式(主备模式),此情况下把所有能够处理写操作的机器称为Master机器,把所有通过异步复制方式获取最新数据,并提供读服务的机器为Slave机器。Zookeeper引入了Leader、Follower、Observer三种角色,Zookeeper集群中的所有机器通过Leaser选举过程来选定一台被称为Leader的机器,Leader服务器为客户端提供写服务,Follower和Observer提供读服务,但是Observer不参与Leader选举过程,不参与写操作的过半写成功策略,Observer可以在不影响写性能的情况下提升集群的性能。 ②…

【分布式】Chubby与Paxos

一、前言 在上一篇理解了Paxos算法的理论基础后,接下来看看Paxos算法在工程中的应用。 二、Chubby Chubby是一个面向松耦合分布式系统的锁服务,GFS(Google File System)和Big Table等大型系统都是用它来解决分布式协作、元数据存储和Master选举等一些列与分布式锁服务相关的问题。Chubby的底层一致性实现就是以Paxos算法为基础,Chubby提供了粗粒度的分布式锁服务,开发人员直接调用Chubby的锁服务接口即可实现分布式系统中多个进程之间粗粒度的同控制,从而保证分布式数据的一致性。 2.1 设计目标 Chubby被设计成为一个需要访问中心化的分布式锁服务。 ① 对上层应用程序的侵入性更小,使用一个分布式锁服务的接口方式对上层应用程序的侵入性更小,应用程序只需调用相应的接口即可使用分布式一致性特性,并且更易于保持系统已有的程序结构和网络通信模式。 ② 便于提供数据的发布与订阅,在Chubby进行Master选举时,需要使用一种广播结果的机制来向所有客户端公布当前Master服务器,这意味着Chubby应该允许其客户端在服务器上进行少量数据的存储和读取(存储主Master地址等信息),也就是对小文件的读写操作。数据的发布与订阅功能和锁服务在分布式一致性特性上是相通的。 ③ 开发人员对基于锁的接口更为熟悉,Chubby提供了一套近乎和单机锁机制一直的分布式锁服务接口。 ④ 更便捷地构建更可靠的服务,Chubby中通常使用5台服务器来组成一个集群单元(Cell),根据Quorum机制(在一个由若干个机器组成的集群中,在一个数据项值的选定过程中,要求集群中过半的机器达成一致),只要整个集群中有3台服务器是正常运行的,那么整个集群就可以对外提供正常的服务。 ⑤ 提供一个完整的、独立的分布式锁服务,Chubby对于上层应用程序的侵入性特别低,对于Master选举同时将Master信息等级并广播的场景,应用程序只需要向Chubby请求一个锁,并且在获得锁之后向相应的锁文件写入Master信息即可,其余的客户端就可以通过读取这个锁文件来获取Master信息。 ⑥ 提供粗粒度的锁服务,Chubby针对的应用场景是客户端获得锁之后会进行长时间持有(数小时或数天),而非用于短暂获取锁的场景。当锁服务短暂失效时(服务器宕机),Chubby需要保持所有锁的持有状态,以避免持有锁的客户端出现问题。而细粒度锁通常设计为为锁服务一旦失效就释放所有锁,因为其持有时间很短,所以其放弃锁带来的代价较小。 ⑦ 高可用、高可靠,对于一个由5太机器组成的集群而言,只要保证3台正常运行的机器,整个集群对外服务就能保持可用,另外,由于Chubby支持通过小文件读写服务的方式来进行Master选举结果的发布与订阅,因此在Chubby的实际应用中,必须能够支撑成百上千个Chubby客户端对同一个文件进行监控和读取。 ⑧ 提供时间通知机制,Chubby客户端需要实时地感知到Master的变化情况,这可以通过让你客户端反复轮询来实现,但是在客户端规模不断增大的情况下,客户端主动轮询的实时性效果并不理想,且对服务器性能和网络带宽压力都非常大,因此,Chubby需要有能力将服务端的数据变化情况以时间的形式通知到所有订阅的客户端。 2.2 技术架构 Chubby的整个系统结构主要由服务端和客户端两部分组成,客户端通过RPC调用和服务端进行通信,如下图所示。 一个典型的Chubby集群(Chubby…

【分布式】一致性协议

一、前言 继续前面的学习,这篇我们来学习在分布式系统中最重要的一块,一致性协议,其中就包括了大名鼎鼎的Paxos算法。 二、2PC与3PC 在分布式系统中,每一个机器节点虽然能够明确知道自己在进行事务操作过程中的结果是成功或是失败,但是却无法直接获取到其他分布式节点的操作结果,因此,当一个事务操作需要跨越多个分布式节点的时候,为了保持事务处理的ACID的特性,需要引入协调者的组件来统一调度所有分布式节点的执行逻辑,而被调度的节点则被称为参与者,协调者负责调度参与者的行为并最终决定这些参与者是否要把事务真正进行提交,基于这个思想,衍生出了二阶段提交和三阶段提交两种协议。 2.1 2PC 2PC为Two-Phase Commit的简写,为二阶段提交协议将事务的提交过程分成了两个阶段来进行处理,并执行如下流程: 阶段一:提交事务请求 ① 事务询问,协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应。 ② 执行事务,各参与者节点执行事务操作(已经执行),并将Undo和Redo信息记入事务日志中。 ③ 各参与者向协调者反馈事务询问的响应,如果参与者成功执行了事务操作,那么就反馈给协调者Yes响应,表示事务可以执行;如果参与者没有成功执行事务,那么就反馈给协调者No响应,表示事务不可以执行。 第一阶段近似于是协调者组织各参与者对一次事务操作的投票表态的过程,因此二阶段提交协议的阶段一也被称为投票阶段。 阶段二:执行事务提交 协调者会根据各参与者的反馈情况来决定最终是否可以进行事务提交操作,正常情况包含如下两种可能: 1. 执行事务提交,假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务提交。 ① 发送提交请求,协调者向所有参与者节点发出Commit请求。 ② 事务提交,参与者接收到Commit请求后,会正式执行事务提交操作,并在完成提交之后释放在整个事务执行期间占用的事务资源。 ③ 反馈事务提交结果,参与者在完成事务提交之后,向协调者发送Ack消息。 ④ 完成事务,协调者接收到所有参与者反馈的Ack消息后,完成事务。 2. 中断事务,假如任意一个参与者向协调者反馈了No响应,或者在等待超时之后,协调者尚无法接收到参与者的反馈响应,就会中断事务。…

【分布式】分布式架构

一、前言   在大数据系统中,分布式系统已经成为一个无法避免的组件,如zookeeper已经成为了工业届的标准。所以对于大数据的研究,也必须要研究分布式系统的特点。 二、集中式系统 由一台或多台计算机组成的中心节点,数据集中存储在这个中心节点中,并且整个系统的所有业务单元都集中部署在这个中心节点上,系统的所有功能均由其集中处理。其部署简单,不用考虑多个节点间的分布式协作问题。 三、分布式系统 分布式系统是一个由硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。其拥有如下特点 3.1 分布性 分布式系统中的多台计算机都会在空间中随意分布,同时,机器的分布情况也会随时变动。 3.2 对等性 分布式系统中的计算机没有主/从之分,既没有控制整个系统的主机,也没有被控制的从机,组成分布式系统的所有计算机节点都是对等的,副本指的是分布式系统对数据和服务提供的一种冗余方式,为了对外提供高可用的服务,我们往往会对数据和服务进行副本处理。数据副本是指在不同的节点上持久化同一份数据,当某一个节点上存储的数据丢失时,可以从副本上读取到该数据,这是解决分布式系统数据丢失问题最为有效的手段。服务副本是只多个节点提供同样的服务,每个节点都有能力接受来自外部的请求并进行相应的处理。 3.3 并发性 同一分布式系统中的多个节点,可能会并发地操作一些共享资源,诸如数据库或分布式存储等,如何高效地协调分布式并发操作也成为了分布式系统架构与设计中最大的挑战之一。 3.4 缺乏全局时钟 典型的分布式系统由一系列在空间上随意分布的多个进程组成,具有明显的分布性,这些进程之间通过交换消息来进行互相通信,因此,在分布式系统中,很难定义两个时间究竟谁先谁后,原因就是因为分布式系统缺乏一个全局的时钟序列控制。 3.5 故障总是会发生 组成分布式系统的所有计算机,都有可能发生任何形式的故障,任何在设计阶段考虑到的异常情况,一定会在系统实际运行中发生。 四、分布式环境的问题 4.1 通信异常 从集中式到分布式,必然引入了网络因素,而由于网络本身的不可靠性,因此就引入了额外的问题。分布式系统各节点之间的网络通信能够正常进行,其延时也会远大于单机操作,在消息的收发过程中,消息丢失和消息延迟变得十分普遍。 4.2 网络分区 当网络发生异常情况时,导致分布式系统中部分节点之间的网络延时不断增大,最终导致组成分布式胸的所有节点中,只有部分节点之间能够正常通信,而另一些节点则不能,这种现象称之为网络分区,当网络分区出现时,分布式系统会出现局部小集群,在极端情况下,这些局部小集群会独立完成原本需要整个分布式系统才能完成的功能,包括对数据的事务处理,这就对分布式一致性提出了非常大的挑战。 4.3 三态…

【目录】Zookeeper目录

Zookeeper的目录整理如下 1. 【分布式】分布式架构 2. 【分布式】一致性协议 3. 【分布式】Chubby与Paxos 4. 【分布式】Zookeeper与Paxos 5. 【分布式】Zookeeper使用–命令行 6. 【分布式】Zookeeper使用–Java API 7. 【分布式】Zookeeper使用–开源客户端 8. 【分布式】Zookeeper应用场景 9. 【分布式】Zookeeper在大型分布式系统中的应用 10. 【分布式】Zookeeper系统模型 11. 【分布式】Zookeeper序列化及通信协议 12. 【分布式】Zookeeper客户端 13. 【分布式】Zookeeper会话 14. 【分布式】Zookeeper服务端启动…

【分布式】Zookeeper数据与存储

一、前言 前面分析了Zookeeper对请求的处理,本篇博文接着分析Zookeeper中如何对底层数据进行存储,数据存储被分为内存数据存储于磁盘数据存储。 二、数据与存储 2.1 内存数据 Zookeeper的数据模型是树结构,在内存数据库中,存储了整棵树的内容,包括所有的节点路径、节点数据、ACL信息,Zookeeper会定时将这个数据存储到磁盘上。 1. DataTree DataTree是内存数据存储的核心,是一个树结构,代表了内存中一份完整的数据。DataTree不包含任何与网络、客户端连接及请求处理相关的业务逻辑,是一个独立的组件。 2. DataNode DataNode是数据存储的最小单元,其内部除了保存了结点的数据内容、ACL列表、节点状态之外,还记录了父节点的引用和子节点列表两个属性,其也提供了对子节点列表进行操作的接口。 3. ZKDatabase Zookeeper的内存数据库,管理Zookeeper的所有会话、DataTree存储和事务日志。ZKDatabase会定时向磁盘dump快照数据,同时在Zookeeper启动时,会通过磁盘的事务日志和快照文件恢复成一个完整的内存数据库。 2.2 事务日志 1. 文件存储 在配置Zookeeper集群时需要配置dataDir目录,其用来存储事务日志文件。也可以为事务日志单独分配一个文件存储目录:dataLogDir。若配置dataLogDir为/home/admin/zkData/zk_log,那么Zookeeper在运行过程中会在该目录下建立一个名字为version-2的子目录,该目录确定了当前Zookeeper使用的事务日志格式版本号,当下次某个Zookeeper版本对事务日志格式进行变更时,此目录也会变更,即在version-2子目录下会生成一系列文件大小一致(64MB)的文件。 2. 日志格式 在配置好日志文件目录,启动Zookeeper后,完成如下操作 (1) 创建/test_log节点,初始值为v1。 (2) 更新/test_log节点的数据为v2。 (3) 创建/test_log/c节点,初始值为v1。 (4)…

【分布式】Zookeeper请求处理

一、前言 在前面学习了Zookeeper中服务器的三种角色及其之间的通信,接着学习对于客户端的一次请求,Zookeeper是如何进行处理的。 二、请求处理 2.1 会话创建请求 Zookeeper服务端对于会话创建的处理,大体可以分为请求接收、会话创建、预处理、事务处理、事务应用和会话响应六大环节,其大体流程如 1. 请求接收 (1) I/O层接收来自客户端的请求。NIOServerCnxn维护每一个客户端连接,客户端与服务器端的所有通信都是由NIOServerCnxn负责,其负责统一接收来自客户端的所有请求,并将请求内容从底层网络I/O中完整地读取出来。 (2) 判断是否是客户端会话创建请求。每个会话对应一个NIOServerCnxn实体,对于每个请求,Zookeeper都会检查当前NIOServerCnxn实体是否已经被初始化,如果尚未被初始化,那么就可以确定该客户端一定是会话创建请求。 (3) 反序列化ConnectRequest请求。一旦确定客户端请求是否是会话创建请求,那么服务端就可以对其进行反序列化,并生成一个ConnectRequest载体。 (4) 判断是否是ReadOnly客户端。如果当前Zookeeper服务器是以ReadOnly模式启动,那么所有来自非ReadOnly型客户端的请求将无法被处理。因此,服务端需要先检查是否是ReadOnly客户端,并以此来决定是否接受该会话创建请求。 (5) 检查客户端ZXID。正常情况下,在一个Zookeeper集群中,服务端的ZXID必定大于客户端的ZXID,因此若发现客户端的ZXID大于服务端ZXID,那么服务端不接受该客户端的会话创建请求。 (6) 协商sessionTimeout。在客户端向服务器发送超时时间后,服务器会根据自己的超时时间限制最终确定该会话超时时间,这个过程就是sessionTimeout协商过程。 (7) 判断是否需要重新激活创建会话。服务端根据客户端请求中是否包含sessionID来判断该客户端是否需要重新创建会话,若客户单请求中包含sessionID,那么就认为该客户端正在进行会话重连,这种情况下,服务端只需要重新打开这个会话,否则需要重新创建。  2. 会话创建 (1) 为客户端生成sessionID。在为客户端创建会话之前,服务端首先会为每个客户端分配一个sessionID,服务端为客户端分配的sessionID是全局唯一的。 (2) 注册会话。向SessionTracker中注册会话,SessionTracker中维护了sessionsWithTimeout和sessionsById,在会话创建初期,会将客户端会话的相关信息保存到这两个数据结构中。 (3) 激活会话。激活会话涉及Zookeeper会话管理的分桶策略,其核心是为会话安排一个区块,以便会话清理程序能够快速高效地进行会话清理。…