【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) 装载 -- 查找并装载类型的二进制数据…

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

【分布式】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可以在不影响写性能的情况下提升集群的性能。 ② 会话,指客户端会话,一个客户端连接是指客户端和服务端之间的一个TCP长连接,Zookeeper对外的服务端口默认为2181,客户端启动的时候,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够心跳检测与服务器保持有效的会话,也能够向Zookeeper服务器发送请求并接受响应,同时还能够通过该连接接受来自服务器的Watch事件通知。 ③ 数据节点,第一类指构成集群的机器,称为机器节点,第二类是指数据模型中的数据单元,称为数据节点-Znode,Zookeeper将所有数据存储在内存中,数据模型是一棵树,由斜杠/进行分割的路径,就是一个ZNode,如/foo/path1,每个ZNode都会保存自己的数据内存,同时还会保存一些列属性信息。ZNode分为持久节点和临时节点两类,持久节点是指一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在Zookeeper上,而临时节点的生命周期和客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。另外,Zookeeper还允许用户为每个节点添加一个特殊的属性:SEQUENTIAL。一旦节点被标记上这个属性,那么在这个节点被创建的时候,Zookeeper会自动在其节点后面追加一个整形数字,其是由父节点维护的自增数字。 ④ 版本,对于每个ZNode,Zookeeper都会为其维护一个叫作Stat的数据结构,Stat记录了这个ZNode的三个数据版本,分别是version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)、aversion(当前ZNode的ACL版本)。 ⑤ Watcher,Zookeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,Zookeeper服务端会将事件通知到感兴趣的客户端。 ⑥ ACL,Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,其定义了如下五种权限: · CREATE:创建子节点的权限。 · READ:获取节点数据和子节点列表的权限。…

Continue Reading 【分布式】Zookeeper与Paxos

【分布式】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…

Continue Reading 【分布式】Chubby与Paxos

【分布式】一致性协议

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

Continue Reading 【分布式】一致性协议

【分布式】分布式架构

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

Continue Reading 【分布式】分布式架构

【目录】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服务端启动 15. 【分布式】Zookeeper的Leader选举 16. 【分布式】Zookeeper的服务器角色 17. 【分布式】Zookeeper请求处理 18. 【分布式】Zookeeper数据与存储

Continue Reading 【目录】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)…

Continue Reading 【分布式】Zookeeper数据与存储

【分布式】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会话管理的分桶策略,其核心是为会话安排一个区块,以便会话清理程序能够快速高效地进行会话清理。…

Continue Reading 【分布式】Zookeeper请求处理

【分布式】Zookeeper使用–命令行

一、前言 在学习了Zookeeper相关的理论知识后,下面接着学习对Zookeeper的相关操作。 二、Zookeeper部署 Zookeeper的部署相对来说还是比较简单,读者可以在网上找到相应的教程,点这里,笔者不再累赘。 Zookeeper有三种运行形式:集群模式、单机模式、伪集群模式。 以下实验都是在单机模式下进行。 三、服务端   bin目录下常用的脚本解释 zkCleanup  清理Zookeeper历史数据,包括食物日志文件和快照数据文件 zkCli      Zookeeper的一个简易客户端 zkEnv    设置Zookeeper的环境变量 zkServer     Zookeeper服务器的启动、停止、和重启脚本 3.1 运行服务 进入bin目录,使用zkServer.sh start启动服务 使用jps命令查看,存在QuorumPeerMain进程,表示Zookeeper已经启动 3.2 停止服务 在bin目录下,使用zkServer.sh stop停止服务 使用jps命令查看,QuorumPeerMain进程已不存在,表示Zookeeper已经关闭 四、客户端 4.1 打开客户端 在服务端开启的情况下,运行客户端,使用如下命令:./zkCli.sh 连接服务端成功,若连接不同的主机,可使用如下命令:./zkCli.sh…

Continue Reading 【分布式】Zookeeper使用–命令行

【分布式】Zookeeper使用–Java API

一、前言 上一篇博客我们通过命令行来操作Zookeper的客户端和服务端并进行相应的操作,这篇主要介绍如何通过API(JAVA)来操作Zookeeper。 二、开发环境配置 首先打开Zookeeper服务端(上一篇博客有具体的方法),方便客户端连接。 配置开发环境环境可以有两种方式:① 直接下载相关的依赖Jar包,然后在IDE中添加依赖 ② 建立maven项目,使用maven进行依赖管理。 ① 手动添加依赖至IDE 步骤一:点击这里下载对应版本的Jar包,包括(jar、javadoc.jar、sources.jar),笔者对应下载的Zookeeper3.4.6版本。 步骤二:打开IDE(笔者使用eclispe),新建名为zookeeper_examples_none_maven的java项目。由于需要单独添加依赖,为了方便管理,笔者在项目下新建了jar文件夹,用于存放本项目的jar包(将步骤一下载的3个jar包存放至此文件夹下)。 步骤三:在eclipse中添加依赖 步骤四:新建包、Java类进行测试 Zookeeper_Constructor_Usage_Simple.java package com.hust.grid.leesf.examples; import java.io.IOException; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; public…

Continue Reading 【分布式】Zookeeper使用–Java API