这篇文章我们来看下zk底层数据存储的技术细节,在ZooKeeper中,数据存储分为内存数据存储和磁盘数据存储 1. 内存数据 ZooKeeper的数据模型是一棵树,可以类比为一个内存数据库,存储了整棵树的内容,包括节点路径,节点数据及其ACL信息等,ZooKeeper会定时将这个数据存储到磁盘上。接下来看一下几个关键的数据模型。 1.1. DataTree ZooKeeper内存数据存储的核心组件,代表了内存中一份完整的数据 。 DataTree 的数据结构如下: 1.2. DataNode DataNode是数据存储的最小单元,包含着对父节点的引用。还有其他几个属性 byte [] data : 保存节点的数据 Long acl: acl map长度 StatPersisted stat :节点状态 Set<String> children : 当前节点的子节点列表 还提供了几个操作接口: 添加子节点:往set集合中添加子节点信息 public synchronized boolean addChild(String child) { if (children == n....
前面几篇文章讲了服务器启动的流程,对于选举过程是一笔带过,这篇文章主要讲述Leader选举的实现细节。 Leader 选举是ZooKeeper中最重要的技术之一,也是保证分布式数据一致性的关键所在。我们从选举算法概述、服务器启动Leader选举、服务器运行期间Leader选举三个方面探讨实现细节。 1. 选举算法概述 服务器启动期间Leader选举 选举的条件是集群中至少有两台机器。主要流程如下: 每个server发出一个投票 接收各个服务器的投票消息 处理投票 统计投票 改变服务器状态 服务器运行期间的Leader选举 ZooKeeper集群在正常运行过程中,是不会进行leader选举过程的,只有当Leader机器挂掉之后,才会进行新一轮的Leader选举。选举过程和服务器启动期间Leader选举是一致的。 变更状态 每个server发出一个投票 接收来自各个服务器的投票 处理投票 统计投票 改变服务器状态 QuorumPeer.OrderState定义了服务器的四种状态,分表是: LOOKING: 寻找Leader状态,服务器处于该状态时,表示集群中没有leader,需要进入lea....
开发人员主要使用zk的客户端,所以我们先来了解zk客户端的创建过程原理。 1. 概述 zk客户端的核心组件如下: ZooKeeper实例 :客户端入口 ClientWatcherManager :客户端Watcher管理器 HostProvider:客户端地址列表管理器 ClientCnxn:客户端核心线程。包含两个线程,即SendThread和EventThread。前者是一个I/O线程,主要负责ZooKeeper客户端和服务端之间的网络I/O通信,后者是一个事件线程,主要负责对服务端事件进行处理。 类图说明: ZooKeeper客户端的初始化与启动环节,实际上就是ZooKeeper对象的实例化过程,分析一个zk客户端的构造方法: public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly, HostProvider aHostProvider, ZKClientConfi....
业界存在不少消息中间件产品,实现各不相同。这篇文章主要介绍基于ZooKeeper实现的分布式队列。分布式队列,简单来说分为两大类,一种是常规的先入先出队列,另一种是要等到所有元素集聚之后才能统一安排执行的Barrier模型。 1. FIFO:先入先出 FIFO队列是一种非常典型的按序执行的队列模型:先进入队列的请求操作完成后,才会开始处理后面的请求。 使用zk实现FIFO队列,和zk对于共享锁的实现类似。FIFO队列就类似于一个全局的共享锁模型。所有客户端都会到一个节点(比如queue_fifo)下创建一个临时顺序节点。 创建完节点,根据如下四个步骤确定执行顺序。 1.通过调用getChildren() 接口来获取 /queue_fifo节点下的所有子节点,即获取队列中的所有元素。 2.确定自己的节点序号在所有子节点中的顺序 3.如果自己不是序号最小的子节点,那么就需要进入等待,同时向比自己序号小的最后一个节点注册Watcher监听 4.接收到Watcher通知后,重复步骤1 整个通过流程如下图所示: 2. Barrier:分布式屏障 Barrier在分布式系统中特指系统之间的一个协....
本文章先概述一下zk的主要应用场景,然后重点讲述其分布式锁的实现。 1.应用场景概述 1.1.数据发布/订阅 数据发布/订阅系统,即所谓的配置中心。意思就是发布者将数据发布到zk的n个节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和数据的动态更新。 1.2.负载均衡 zk作为路由,client从zk那里拿到可用的server地址(最好做个缓存),通过自己的负载均衡算法得到要连接的地址,client去连接指定server。server要做的是,当server启动后去zk注册自己(创建临时文件),子节点变化时(比如当某台server宕机),server与zk的链接会断掉,zk会自动删除该临时文件。 1.3.命名服务 命名服务是分布式系统中最基本的公共服务之一。要命名的对象包括集群中的机器列表,服务名称等。zk实现命名服务的方式:通过调用zk节点创建的API接口创建一个顺序节点,并且在API返回值中返回这个节点的完整名字。 1.4.分布式协调/通知 zk中特有的Watcher注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至是不同系统之间的协调与....
paxos算法是莱利斯·兰伯特于1990年提出的一种基于消息传递且具有高度容错特性的一致性算法。是目前公认的解决分布式一致性问题最有效的算法之一。在常见的分布式系统中,总会发生机器宕机或者网络异常等情况。paxos算法就是要解决就是如果在一个会发生上述异常的分布式系统中,快速且正确的在集群内部对某个数据的值达成一致,并且保证不论发生以上任何异常,都不会破坏整个系统的一致性。 1. 历史故事 1982年,lamport与另外两人共同发表了论文The Byzantine Generals Problem,提出了一种计算机容错理论。在理论描述过程中,为了能更加形象的表达,lamport设想了下面一种场景: 拜占庭帝国有多支军队,不同军队的将军之间要指定统一的行动计划,从而选择做出进攻或者撤退的决定,同时,各个将军在地理上都是被隔离开来的,只能依靠军队的通讯员进行通信。然而在所有的通讯员中可能会存在叛徒,这些叛徒可以任意篡改消息,从而达到欺骗将军的目的。 这就是著名的拜占庭将军问题,从理论上来说,在分布式计算领域,试图在异步系统和不可靠的信道上达成一致状态是不可能的,所以在研究的过程中,往往假....
随着计算机系统规模越来越大,将所有业务单元部署在一个或者若干个大型主机上的体系结构,已经越来越不满足当今计算机系统,尤其是大型互联网系统的发展,各种灵活多变的系统架构模型层出不穷。同时,随着微型计算机的发展,越来越多廉价的PC机成为了各大企业IT架构的首选,分布式的处理方式越来越受到业界的青睐,计算机系统经历着一场从集中式到分布式架构的转变。 1. 从集中式到分布式 自20世纪60年代大型主机被发明出来以后,凭借其超强的计算和I/O处理能力以及在安全性和稳定性方面的卓越表现,在很长一段时间,大型主机引领了计算机行业以及商业计算领域的发展。最知名的企业当属IBM,其发明的 System/360系列大型主机,是计算机发展史上的一个里程碑,与波音707,福特T型车齐名,并称为20世纪最重要的三大商业成就,并一度成为大型主机的代名词,从那时起,IT界进入了大型主机时代。 随着大型主机的到来,计算机系统架构也进入集中式处理的时代。大型主机由于卓越的性能、良好的稳定性,其在单机处理能力方面的优势非常明显。使得IT系统快速进入了集中式处理阶段。但是20世纪80年代后,计算机向微型化和网络化的发展趋势....
1、jps找到Java进程 20512 ApacheJMeter.jar 20228 Launcher 21636 Launcher 21637 Bootstrap 21670 JConsole 20935 22106 Jps 19006 Application 2、jmap -histo:live 21637 | head -10 num #instances #bytes class name ---------------------------------------------- 1: 1320645 31695480 javassist.ClassPathList 2: 1320645 21130320 javassist.ClassClassPath 3: 90687 13635976 [C 4: 8075 6046544 [B 5: 39467 3473096 java.lang.reflect.Method 6: 93919 3005408 java.util.HashMap$Node 7: 89005 2136120 java.lang.String 3、
通过网络链路和交换机移动数据又两种基本方法:电路交换和分组交换。上一篇文章说过了分组交换网络,现在讨论一下电路交换网络 1. 电路交换基本概念 在电路交换网络中,在端系统间通信会话期间,预留了端系统间通信沿路径所需要的资源(缓存,链路传输速率),在分组交换网络中,这些资源是不预留的。会话的报文按需使用这些资源,其后果可能是不得不等待接入通信线路。 传统的电话网络就是电路交换网络的例子。 2. 电路交换网络中复用 链路中的电路是通过频分复用(Frequency-Division-Multiplexing,FDM)或时分复用(Time-Division-Multiplexing)来实现的。对于FDM,链路的频谱由跨越链路创建的所有连接所共享。特别是,在连接期间链路为每条链路专用一个频段。在电话网络中,这个频段通常具有4khz的宽度。 对于TDM链路,时间被划分为固定区间的帧,并且每帧又被划分为固定数量的时隙,当网络跨越一条链路创建一条连接时,网络在每个帧中为该连接指定一个时隙。这些时隙专门由该连接单独使用,一个时隙可用于传输该连接的数据。 3. 分组交换和电路交换的对比 分组交换不适合实时....
为了从源系统向端系统发送一个报文,源将长报文划分为较小的数据块。称之为‘分组’,每个分组都经过通信链路和分组交换机。 1. 存储转发传输 存储转发机制是指在交换机能够开始向输出链路传输该分组的第一个比特之前,必须接收到整个分组。 比如有一个路由器连接的两个端系统构成的简单网络,数据传输速度为R bps,距离为L,则在时刻L/R 秒,路由器接收到整个分组,开始向输出链路传输分组。在时刻2L/R时刻,路由器传输完整个分组,并且整个分组被目的地接收,延时为2L/R。 2. 排队时延和分组丢失 每个分组交换机有多条链路与之相连。对于每条相连的链路,该分组交换机具有一个输出缓存,它用于存储路由器准备发往哪条链路的分组。这个输出缓存在分组交换中起着重要的作用。如果到达的分组需要传输到某条链路,但发现该链路正忙于传输其他分组。该到达分组必须在该输出缓存中等待。因此,除了存储转发时延以外,分组还要承受输出缓存的排队时延。这些时延是变化的,取决于网络中的拥塞程度。因为缓存空间的大小是有限的。一个到达的分组可能发现该缓存已经被其他等待传输的分组完全充满了。在此情况下,将出现丢包。 3. 转发表和路由选择协....
微服务架构是近些年来在软件架构领域出现的一个新名词,虽然其诞生时间不长,但是其在各种技术资料,演讲、文章中出现的频率让大家意识到了它对软件架构领域带来的影响。 1. 什么是微服务架构 对于微服务很难有一个确切的定义,就像对于NoSql和函数式编程的概念一样,大家都有一个大致的认识,但是下个准确的定义比较难。 摘录一段马丁- 福勒先生的话: 微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。 1.1 多微才算微 两种错误的认识: 按代码行数判断。 实现相同的功能,不同的语言代码量不同 按重写时间判断。成员工作经验、技术背景、熟悉技术栈的不同,需要的开发时间也不同 正确的认识: 团队觉得好才是真的好 那一般也遵循两个原则 业务独立性。要保证微服务是一个具有业务独立性的单元 团队自主性。考虑到沟通成本,统一服务开发人数不建议超过10人。当人数过多时,考虑再拆分服务。 1.2 单一职责 每个微服务,应该处理单一的业务....
Java并发多线程学习笔记 标签(): java 多线程 并发编程 艺术 原子操作的实现原理 #1、术语 比较并交换 compare and swap(一个新值和旧值,比较旧值有没有发生变化,如果没有发生变化则交换成新值) CPU流水线 CPU pipeline -- 内存顺序冲突 Memory order violation -- 一般由假共享内存引起,出现冲突时,cpu流水线必须清空 #2、处理器如何实现原子操作 32位IA-32处理器使用缓存加锁或总线加锁的方式来处理多处理器之间的原子操作 一般情况下处理器会自动保证基本内存操作的原子性,但是复杂的内存操作则并不能自动保证原子性。比如跨总线宽度,跨多个缓存行和跨页表的访问。 处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。 ##1.总线锁 总线锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞,那该处理器可以独占共享内存。 ##2.缓存锁 频繁使用的内存会缓存在处理器的L1,L2,L3高速缓存里 缓存锁定是指内存区域如果被缓存在处理器的缓存行中,并且在lock操作期....
问题描述 今日测试微信客服消息接口、发过去之后微信发给用户的是乱码,Google了一下,解决办法很多,但是都不能解决我的问题。我用的是Apache的httpClient。 之前一直是乱码的代码: entity = new StringEntity(JSON.toJSONString(postForm)); entity.setContentEncoding(StandardCharsets.UTF_8.toString()); entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); 我是用了utf-8编码,ContentEncoding是utf-8,但是还是乱码。。。。经过一番尝试,map转json的时候编码可能发生了变化。 我把代码这样写了一下,StringEntity()的时候也加了一下编码。问题解决了。 entity = new StringEntity(JSON.toJSONString(postForm), "UTF-8"); entity.setContentEncoding(StandardC....
Git命令 标签(空格分隔): git co 是checkout的意思,配置了别名。 ##1. 把远程没有拉取过的分支拉取到本地 git co master // 会把远程的master拉到本地,并且建立关联 ##2. 创建本地分支并推送到远程 1. git co -b test // 创建本地分支test 2. git co -b test // 创建本地分支test 3. git push origin wei // 把本地分支推到远程 ##3. 本地分支和远程分支建立关联 git push --set-upstream origin test // 当前分支为test ##4. 把本地的某个分支提交到远程某个分支 git ps origin test:test // 把本地的test提交到远程test ##5. 把远程分支拉到本地 git checkout origin/remoteName -b localName ##6. 删除远程一个分支 git push origin :wei // 删除远程分支wei ##7. Git add 撤销 执行了Git a....