互联网面试知识技术总结(javacore、jvm、redis、kafka、zookeeper、mysql、hystrix)-第三章

39,mybatis 一级缓存和二级缓存 1,一级缓存是SqlSession级别的缓存。在操做数据库时须要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不一样的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。若是中间sqlSession去执行commit操做(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样作的目的为了让缓存中存储的是最新的信息,避免脏读。我的认为一级缓存不是线程安全的,对于同一行数据,另一个线程写入数据(不使用mybatis组件),会致使session数据没法正常更新。   2,二级缓存是mapper级别的缓存,多个SqlSession去操做同一个Mapper的sql语句,多个SqlSession能够共用二级缓存,二级缓存是跨SqlSession的。 3,二级缓存默认是不开启的。html

40, MySQL 中的行级锁、表级锁和页级锁前端

InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,若是加排他锁可使用select ...for update语句,加共享锁可使用select ... lock in share mode语句。因此加过排他锁的数据行在其余事务种是不能修改数据的,也不能经过for update和lock in share mode锁的方式查询数据,但能够直接经过select ...from...查询数据,由于普通查询没有任何锁机制。java

在数据库的锁机制中,能够按照锁的粒度把数据库锁分为行级锁(InnoDB引擎)、表级锁(MyISAM引擎)和页级锁(BDB引擎)。 行级锁:MySQL中锁定粒度最细的一种锁,表示只针对当前操做的行进行加锁。行级锁能大大减小数据库操做的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。 特色:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。node

表级锁:MySQL中锁定粒度最大的一种锁,表示对当前操做的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB 都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。 特色:开销小,加锁快,不会出现死锁;锁定粒度大,发出锁冲突的几率最高,并发度最低。mysql

页级锁:MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以,采起了折衷的页级锁,一次锁定相邻的一组记录。BDB支持页级锁。 特色:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常。web

MySQL 经常使用存储引擎的锁机制 MyISAM和Memory采用表级锁(table-level locking) BDB采用页级锁(page-level locking)或表级锁,默认为页级锁; InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁。面试

在InnoDB 引擎中既支持行锁也支持表锁,那么何时会锁住整张表?何时只锁住一行呢? InnoDB 行锁是经过给索引上的索引项加锁来实现的,InnoDB行锁实现的特色意味着:只有经过索引条件检索数据,InnoDB才使用行级锁,不然,InnoDB将使用表锁。 在实际应用中,要特别注意 InnoDB 行锁的这一特性,否则的话,可能致使大量的锁冲突,从而影响并发性能。 在不经过索引条件查询的时候,InnoDB 确实使用的是表锁,而不是行锁redis

行级锁又分共享锁和排他锁。     共享锁:       名词解释:共享锁又叫作读锁,全部的事务只能对其进行读操做不能写操做,加上共享锁后在事务结束以前其余事务只能再加共享锁,除此以外其余任何类型的锁都不能再加了。       用法:SELECT id FROM table WHERE id in(1,2) LOCK IN SHARE MODE 结果集的数据都会加共享锁     排他锁:       名词解释:若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束以前,其余事务不能对其进行加任何锁,其余进程能够读取,不能进行写操做,需等待其释放。       用法:SELECT id FROM mk_user WHERE id=1 FOR UPDATE算法

行级锁与死锁 MyISAM中是不会产生死锁的,由于MyISAM老是一次性得到所需的所有锁,要么所有知足,要么所有等待。而在InnoDB 中,锁是逐步得到的,就形成了死锁的可能。 在 MySQL 中,行级锁并非直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,若是一条 SQL 语句操做了主键索引,MySQL 就会锁定这条主键索引;若是一条 SQL 语句操做了非主键索引,MySQL 就会先锁定该非主键索引,再锁定相关的主键索引。 在进行UPDATE、DELETE操做时,MySQL 不只锁定WHERE条件扫描过的全部索引记录,并且会锁定相邻的键值,即所谓的next-key locking 当两个事务同时执行,一个锁住了主键索引,在等待其余相关索引;另外一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。 发生死锁后,InnoDB通常均可以检测到,并使一个事务释放锁回退,另外一个获取锁完成事务。spring

避免死锁的方法 <1>若是不一样程序会并发存取多个表,尽可能约定以相同的顺序访问表,能够大大下降发生死锁的可能性; <2>在同一个事务中,尽量作到一次锁定所须要的全部资源,减小死锁产生几率; <3>对于很是容易产生死锁的业务部分,能够尝试使用升级锁定颗粒度,经过表级锁定来减小死锁产生的几率。

行锁优化 1 尽量让全部数据检索都经过索引来完成,避免无索引行或索引失效致使行锁升级为表锁。 2 尽量避免间隙锁带来的性能降低,减小或使用合理的检索范围。 3 尽量减小事务的粒度,好比控制事务大小,而从减小锁定资源量和时间长度,从而减小锁的竞争等,提供性能。 4 尽量低级别事务隔离,隔离级别越高,并发的处理能力越低。

参考:blog.csdn.net/qq_35246620… 41,乐观锁和悲观锁 悲观锁 老是假设最坏的状况,每次去拿数据的时候都认为别人会修改,因此每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了不少这种锁机制,好比行锁,表锁等,读锁,写锁等,都是在作操做以前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

乐观锁 老是假设最好的状况,每次去拿数据的时候都认为别人不会修改,因此不会上锁,可是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样能够提升吞吐量,像数据库提供的相似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

两种锁的使用场景 从上面对两种锁的介绍,咱们知道两种锁各有优缺点,不可认为一种好于另外一种,像乐观锁适用于写比较少的状况下(多读场景),即冲突真的不多发生的时候,这样能够省去了锁的开销,加大了系统的整个吞吐量。但若是是多写的状况,通常会常常产生冲突,这就会致使上层应用会不断的进行retry,这样反却是下降了性能,因此通常多写的场景下用悲观锁就比较合适。

42,索引失效   1.若是条件中有or,即便其中有条件带索引也不会使用(这也是为何尽可能少用or的缘由)   要想使用or,又想让索引生效,只能将or条件中的每一个列都加上索引   2.对于多列索引,不是使用的第一部分,则不会使用索引(使用组合索引没有符合最左原则,致使实际没能真实使用索引)   3.like查询以%开头   4.若是列类型是字符串,那必定要在条件中将数据使用引号引用起来,不然不使用索引   5.若是mysql估计使用全表扫描要比使用索引快,则不使用索引 6.索引没法存储null值,所以索引中有null,查询时,采用is null条件时,不能利用到索引,只能全表扫描。 7.not in ,not exist 参考:www.cnblogs.com/shynshyn/p/…

41.内存映射技术 内存映射文件都知道,它比传统的IO读写数据快不少,那么,它为何会这么快,从代码层面上来看,从硬盘上将文件读入内存,都是要通过数据拷贝,而且数据拷贝操做是由文件系统和硬件驱动实现的,理论上来讲,拷贝数据的效率是一 样的。其实,缘由是read()是系统调用,其中进行了数据 拷贝,它首先将文件内容从硬盘拷贝到内核空间的一个缓冲区,如图2中过程1,而后再将这些数据拷贝到用户空间,如图2中过程2,在这个过程当中,实际上完成 了两次数据拷贝 ;而mmap()也是系统调用,如前所述,mmap()中没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,因为mmap()将文件直接映射到用户空间,因此中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了 一次数据拷贝 。所以,内存映射的效率要比read/write效率高(通过测试,内存映射技术比常规的io读取,速度快上6倍左右) (blog.csdn.net/whoamiyang/…

JAVA NIO之浅谈内存映射文件原理与DirectMemory 在传统的文件IO操做中,咱们都是调用操做系统提供的底层标准IO系统调用函数 read()、write() ,此时调用此函数的进程(在JAVA中即java进程)由当前的用户态切换到内核态,而后OS的内核代码负责将相应的文件数据读取到内核的IO缓冲区,而后再把数据从内核IO缓冲区拷贝到进程的私有地址空间中去,这样便完成了一次IO操做。至于为何要画蛇添足搞一个内核IO缓冲区把本来只需一次拷贝数据的事情搞成须要2次数据拷贝呢? 我想学过操做系统或者计算机系统结构的人都知道,这么作是为了减小磁盘的IO操做,为了提升性能而考虑的,由于咱们的程序访问通常都带有局部性,也就是所谓的局部性原理,在这里主要是指的空间局部性,即咱们访问了文件的某一段数据,那么接下去极可能还会访问接下去的一段数据,因为磁盘IO操做的速度比直接访问内存慢了好几个数量级,因此OS根据局部性原理会在一次 read()系统调用过程当中预读更多的文件数据缓存在内核IO缓冲区中,当继续访问的文件数据在缓冲区中时便直接拷贝数据到进程私有空间,避免了再次的低效率磁盘IO操做(其实是预读机制)

www.cnblogs.com/lyftest/p/6…

42,kafka

典型的kafka集群中包含若干producer(能够是web前端产生的page view,或者是服务器日志,系统CPU、memory等),若干broker(Kafka支持水平扩展,通常broker数量越多,集群吞吐率越高),若干consumer group,以及一个Zookeeper集群。Kafka经过Zookeeper管理集群配置,选举leader,以及在consumer group发生变化时进行rebalance。producer使用push模式将消息发布到broker,consumer使用pull模式从broker订阅并消费消息

1,为了作到水平扩展,一个topic实际是由多个partition组成的(避免文件尺寸达到单机磁盘的上限,有效提高并发消费的能力),遇到瓶颈时,能够经过增长partition的数量来进行横向扩容。单个parition内是保证消息有序,同一个topic在不一样partition之间是没法保证有序的(每条消息的偏移量id保证消费有序),这须要业务方根据本身的业务来实现。 2,一个broker有多个topic,每一个topic的分区分散在多个broker之间,而且每一个分区在各个broker有备份(即每一个partition的非leader备份),可是每一个分区只有一个leader 3,异步复制,只要leader写完就算发送完成了,同步复制,得要全部follower写完才算发送完成 4,每一个topic将被分红多个partition,每一个partition在存储层面是append log文件。任何发布到此partition的消息都会被直接追加到log文件的尾部,每条消息在文件中的位置称为offset(偏移量),offset为一个long型数字,它是惟一标记一条消息,所以在一个partition内能够保证消息是顺序消费的。kafka并无提供其余额外的索引机制来存储offset,由于在kafka中几乎不容许对消息进行“随机读写”。对于consumer而言,它须要保存消费消息的offset(一个partition可能对应多个多个consumer,分布在多个consume_group里面,为每一个consumer分配一个offset,就能够保证线性消费了,实际上这个offset是存在zk里面,每一个consumer一个offset),对于offset的保存和使用,有consumer来控制;当consumer正常消费消息时,offset将会"线性"的向前驱动,即消息将依次顺序被消费。 4,在kafka中,一个partition中的消息只会被group中的一个consumer消费 5,一个partition最多只能对应一个consumer(一个consumer可能对应多个partition)

broker: 每一个正在运行的kafka节点 producer:消息生产者 consumer:消息的消费者 consumer group:消费者组,同一个消费者组只能有一个consumer能消费消息 kafka server :也叫做broker, 已部署kafka的服务器, 以broker.id来区分不一样的服务器 topic:主题, 主题中的每条消息包括key-value和timestamp。能够定义多个topic,每一个topic又能够划分为多个分区 partition:topic下的消息分区,经过key取哈希后把消息映射分发到一个指定的分区,每一个分区都映射到broker上的一个目录。通常每一个分区存储在一个broker上 replica:副本, 每一个分区按照生产者的消息达到顺序存放。每一个分区副本都有一个leader leader replica:leader角色的分区副本,leader角色的分区处理消息的读写请求. Leader和follower位于不一样的broker. follower replica:follower角色的分区副本,负责从Leader拉取数据到本地,实现分区副本的建立 zookeeper:严格来讲这不是kafka的组件。可是在Kafka集群中, 颇有必要经过Zookeeper管理kafka集群的配置、选举leader(每一个topic对应的partition的leader),以及在Consumer Group发生变化时进行rebalance。下面说一下kafka的哪些组件须要注册到zookeeper 为何要注册到zk集群? 1,Kafka集群经过Zookeeper来管理kafka的配置,选举leader; 2,在Consumer Group发生变化时进行rebalance 3,全部的topic与broker的对应关系都由zk维护

kafka的哪些组件须要注册到zookeeper? (1)Broker注册到zk(所以Broker和zk之间保持心跳,若是无意跳,broker意味着挂掉) 每一个broker启动时,都会注册到zk中,把自身的broker.id通知给zk。待zk建立此节点后,kafka会把这个broker的主机名和端口号记录到此节点

(2)Topic注册到zk 当broker启动时,会到对应topic节点下注册本身的broker.id到对应分区的isr列表中;当broker退出时,zk会自动更新其对应的topic分区的ISR列表,并决定是否须要作消费者的rebalance

(3)Consumer注册到zk 一旦有新的消费者组注册到zk,zk会建立专用的节点来保存相关信息。若是zk发现消费者增长或减小,会自动触发消费者的负载均衡。 (注意,producer不注册到zk)

消息如何被消费的? Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息;producer经过联系zk获取leader角色的消息分区码,把消息写到leader Producer使用push模式将消息发布到broker +————+ | broker | +————+ | | / PULL | | / Consumer使用pull模式从broker订阅并消费消息

参考:www.cnblogs.com/liyanbin/p/… www.cnblogs.com/likehua/p/3… www.jianshu.com/p/d3e963ff8… blog.csdn.net/dshf_1/arti…

leader选举(容灾) controller会在Zookeeper的/brokers/ids节点上注册Watch,一旦有broker宕机,它就能知道。当broker宕机后,controller就会给受到影响的partition选出新leader。controller从zk的/brokers/topics/[topic]/partitions/[partition]/state中,读取对应partition的ISR(in-sync replica已同步的副本)列表,选一个出来作leader。

kafka的数据存储 其实是以文件的形式存储在文件系统的。topic下有partition,partition下有segment,segment是实际的一个个文件,topic和partition都是抽象概念。 在目录/{topicName}-{partitionid}/下,存储着实际的log文件(即segment),还有对应的索引文件。 每一个segment文件大小相等,文件名以这个segment中最小的offset命名,文件扩展名是.log;segment对应的索引的文件名字同样,扩展名是.index。有两个index文件,一个是offset index用于按offset去查message,一个是time index用于按照时间去查

kafka中的zookeeper做用(consumer链接到哪一个broker,是由zk决定的,所以kafka的负载均衡是由zk完成的) 管理broker、consumer 建立Broker后,向zookeeper注册新的broker信息,实如今服务器正常运行下的水平拓展。具体的,经过注册watcher,获取partition的信息。 Topic的注册,zookeeper会维护topic与broker的关系,经过/brokers/topics/topic.name节点来记录。 Producer向zookeeper中注册watcher,了解topic的partition的消息,以动态了解运行状况,实现负载均衡。Zookeepr是没有管理producer,只是可以提供当前broker的相关信息。 Consumer可使用group形式消费kafka中的数据。全部的group将以轮询的方式消费broker中的数据,具体的按照启动的顺序。Zookeeper会给每一个consumer group一个ID,即同一份数据能够被不一样的用户ID屡次消费。所以这就是单播与多播的实现。以单个消费者仍是以组别的方式去消费数据,由用户本身去定义。Zookeeper管理consumer的offset跟踪当前消费的offset.

kafka的leader选举:www.cnblogs.com/aspirant/p/…

新版本的kafka对leader的选举是这样的:在Kafka集群中会有一个或者多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中全部分区和副本的状态。当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。当检测到某个分区的ISR集合发生变化时,由控制器负责通知全部broker更新其元数据信息。当使用kafka-topics.sh脚本为某个topic增长分区数量时,一样仍是由控制器负责分区的从新分配

在Kafka的早期版本中,并无采用Kafka Controller这样一个概念来对分区和副本的状态进行管理,而是依赖于Zookeeper,每一个broker都会在Zookeeper上为分区和副本注册大量的监听器(Watcher)。当分区或者副本状态变化时,会唤醒不少没必要要的监听器,这种严重依赖于Zookeeper的设计会有脑裂、羊群效应以及形成Zookeeper过载的隐患。在目前的新版本的设计中,只有Kafka Controller在Zookeeper上注册相应的监听器,其余的broker极少须要再监听Zookeeper中的数据变化,这样省去了不少没必要要的麻烦。不过每一个broker仍是会对/controller节点添加监听器的,以此来监听此节点的数据变化(参考ZkClient中的IZkDataListener),简单理解就是旧版本的leader和follower partition都在zk注册,致使zk变得沉重

Zookeeper羊群效应:若是有1000个客户端watch 一个znode的exists调用,当这个节点被建立的时候,将会有1000个通知被发送。这种因为一个被watch的znode变化,致使大量的通知须要被发送,将会致使在这个通知期间的其余操做提交的延迟,所以,只要可能,咱们都强烈建议不要这么使用watch。仅仅有不多的客户端同时去watch一个znode比较好,理想的状况是只有1个。 解决思路:使用zookeeper时,尽可能避免大量节点监控一个节点的行为

策略就是每一个client去建立一个顺序的znode /lock/lock-.ZooKeeper 会自动添加顺序号/lock/lock-xxx.咱们能够经过/lock getChildren 去拿到最小的顺序号。若是client不是最小的序列号,就再比本身小一点的znode上添加watch,因为序列号最小(最早建立的node)才是得到锁的,所以去通知下一个次小的便可,不用所有通知。 参考:www.cnblogs.com/bnbqian/p/4…

Kafka的消息读取为何不从follower读取? 1,mysql不用于高qps的读取,而且容许有延迟(能够在从库读取,信息存在不许确性)。可是kafka是为了低延迟和高吞吐量,只同步到部分的follower就完成消息的投递。 2,一个consumer对应一个partition的leader,若是对应多个,就出现了一条数据重复消息屡次。(除非消费一次leader,同时修改全部的follower的offset)

43,零拷贝技术(消除多余的拷贝次数,并不是一次都没拷贝) 因为数据实际上仍然由磁盘复制到内存,再由内存复制到发送设备,有人可能会声称这并非真正的"零拷贝"。然而,从操做系统的角度来看,这就是"零拷贝",由于内核空间内不存在冗余数据。应用"零拷贝"特性,出了避免复制以外,还能得到其余性能优点,例如更少的上下文切换,更少的CPU cache污染以及没有CPU必要计算校验和。

步骤一:mmap系统调用致使文件的内容经过DMA模块被复制到内核缓冲区中,该缓冲区以后与用户进程共享,这样就内核缓冲区与用户缓冲区之间的复制就不会发生。 步骤二:write系统调用致使内核将数据从内核缓冲区复制到与socket相关联的内核缓冲区中。 步骤三:DMA模块将数据由socket的缓冲区传递给协议引擎时,第3次复制发生。 参考:www.cnblogs.com/pengdonglin…

44,kafka若是作到百万级高吞吐量的(参考:blog.csdn.net/u010039929/…

生产端 1,能够将消息buffer起来,当消息的条数达到必定阀值时,批量发送给broker,即批量写入磁盘(批量写入,避免零碎写入屡次io的打开和关闭)。 2,消息写入到磁盘是顺序写入,充分利用磁盘的顺序读写性能。 3,多个partition同时写入,提升数据的并发写入效率。

broker端 基于内存映射技术实现的零拷贝,sendfile系统调用能够潜在的提高网络IO的性能:将文件的数据映射到系统内存中,socket直接读取相应的内存区域便可,而无需进程再次copy和交换. 其实对于producer/consumer/broker三者而言,CPU的开支应该都不大,所以启用消息压缩机制是一个良好的策略;压缩须要消耗少许的CPU资源,不过对于kafka而言,网络IO更应该须要考虑.能够将任何在网络上传输的消息都通过压缩。 kafka支持gzip/snappy等多种压缩

消费端 批量fetch多条消息,避免屡次pull操做过程当中的io操做带来的性能损耗。

另一种解读: 1、接收数据时写得快 (1)消息顺序写入磁盘 (2)消息集合批量发送 (3)采用由Producer,broker和consumer共享的标准化二进制消息格式,这样数据块就能够在它们之间自由传输,无需转换,下降了字节复制的成本开销。 (4)采用了MMAP(Memory Mapped Files,内存映射文件)技术。 (5)利用操做系统的页缓存来实现文件到物理内存的直接映射。完成映射以后对物理内存的操做在适当时候会被同步到硬盘上。 2、推送数据时发得快 (1)在生产端和消费端分别采起的push和pull的方式,也就是你生产端能够认为KAFKA是个无底洞,有多少数据可使劲往里面推送,消费端则是根据本身的消费能力,须要多少数据,你本身过来KAFKA这里拉取,KAFKA能保证只要这里有数据,消费端须要多少,都尽能够本身过来拿。 (2)采用页缓存和sendfile组合,意味着KAFKA集群的消费者大多数都彻底从缓存消费消息,而磁盘没有任何读取活动。 (3)批量压缩,支持Gzip和Snappy压缩协议。 (4)采用多分区设计,并发读写,加快读写速度。

kafka面试题:blog.csdn.net/linke118398…

45,单点登陆原理 单点登陆全称Single Sign On(如下简称SSO),是指在多系统应用群中登陆一个系统,即可在其余全部系统中获得受权而无需再次登陆,包括单点登陆与单点注销两部分,sso须要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其余系统不提供登陆入口,只接受认证中心的间接受权。间接受权经过令牌实现,sso认证中心验证用户的用户名密码没问题,建立受权令牌,在接下来的跳转过程当中,受权令牌做为参数发送给各个子系统,子系统拿到令牌,即获得了受权,能够借此建立局部会话,局部会话登陆方式与单系统的登陆方式相同

46,如何扩展spring 1,自定义注解或者自定义解析器。 2,BeanFactoryPostProcessor(调用时机是全部bean的定义信息都已经初始化好)和BeanPostProcessor(针对bean初始化提供扩展) 3,spring aop

47,zookeeper在工做中常见的做用:它是分布式系统中的协调系统,可提供的服务主要有:配置中心(像lion)、分布式同步(分布式锁)、rpc服务注册管理(rpc注册中心) Apache ZooKeeper是由集群(节点组)使用的一种服务,用于在自身之间协调,并经过稳健的同步技术维护共享数据。ZooKeeper自己是一个分布式应用程序,为写入分布式应用程序提供服务。

Zookeeper的角色:leader(负责进行投票的发起和决议,数据变动),follower(接受client读取请求,参与选举),observer(ZooKeeper集群的读取负载很高,能够设置一些observer服务器,以提升读取的吞吐量,不参与选举和投票),follower和Observer都是Learner。

ZooKeeper提供的常见服务以下 : 命名服务 - 按名称标识集群中的节点。它相似于DNS,但仅对于节点。 配置管理 - 加入节点的最近的和最新的系统配置信息。 集群管理 - 实时地在集群和节点状态中加入/离开节点。 选举算法 - 选举一个节点做为协调目的的leader。 锁定和同步服务 - 在修改数据的同时锁定数据。此机制可帮助你在链接其余分布式应用程序(如Apache HBase)时进行自动故障恢复。 高度可靠的数据注册表 - 即便在一个或几个节点关闭时也能够得到数据。

zookeeper入门:www.cnblogs.com/felixzh/p/5… zookeeper实际上以文件形式对节点进行管理,所以同一级目录下不存在重复节点

zookeeper选主流程(basic paxos) 当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式须要从新选举出一个新的leader,让全部的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。

ZooKeeper如何解决"脑裂" 3种可行的思路 (1) Quorums(法定人数,通常只有过半投票才能认可选主成功)法: 经过设置法定人数, 进而肯定集群的容忍度, 当集群中存活的节点少于法定人数, 集群将不可用.(或者限制全局至少一半以上节点投票才行) 好比: 3个节点的集群中, Quorums = 2 —— 集群能够容忍 (3 - 2 = 1) 个节点失败, 这时候还能选举出leader, 集群仍然可用; 4个节点的集群中, Quorums = 3 —— 集群一样能够容忍 1 个节点失败, 若是2个节点失败, 那整个集群就不可用了. (2) Redundant communications(冗余通讯): 集群中采用多种通讯方式, 防止一种通讯方式失效致使集群中的节点没法通讯. (3) Fencing(共享资源): 经过共享资源的方式, 将全部共享资源添加到集群中, 能对共享资源进行写操做(即加锁)的节点就是leader节点. 原文:blog.csdn.net/ma_shou_fen…

48,zookeeper面试题(segmentfault.com/a/119000001… 1.ZooKeeper是什么? ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务 2,ZooKeeper提供了什么? 文件系统和通知机制 3,Zookeeper通知机制 client端会对某个znode创建一个watcher事件,当该znode发生变化时,这些client会收到zk的通知,而后client能够根据znode变化来作出业务上的改变等。 4,zookeeper是如何保证事务的顺序一致性的? zookeeper采用了递增的事务Id来标识,全部的proposal(提议)都在被提出的时候加上了zxid,zxid其实是一个64位的数字,高32位是epoch(时期; 纪元; 世; 新时代)用来标识leader是否发生改变,若是有新的leader产生出来,epoch会自增,低32位用来递增计数。当新产生proposal的时候,会依据数据库的两阶段过程,首先会向其余的server发出事务执行请求,若是超过半数的机器都能执行而且可以成功,那么就会开始执行 5,机器中为何会有leader? 在分布式环境中,有些业务逻辑只须要集群中的某一台机器进行执行,其余的机器能够共享这个结果,这样能够大大减小重复计算,提升性能,因而就须要进行leader选举 6,部署方式?集群中的机器角色都有哪些?集群最少要几台机器 单机,集群,伪集群。Leader、Follower、Observer。集群最低3(2N+1)台,保证奇数,主要是为了选举算法。 7,集群若是有3台机器,挂掉一台集群还能工做吗?挂掉两台呢? 过半存活便可用。

8,zookeeper如何保证数据的一致性,而且如何进行leader和follower的选举? ZooKeeper使用的是ZAB协议做为数据一致性的算法, ZAB(ZooKeeper Atomic Broadcast ) 全称为:原子消息广播协议。zab有两种工做模式:恢复模式和广播模式。zab如何保证数据的一致性:全部事务请求必须由一个全局惟一的服务器(Leader)来协调处理,其余的服务器则成为Follower。Leader会将一个客户端的事务请求转换为一个Proposal(提议),而后分发为集群中全部的Follower。当有过半数的Follower进行了正确的反馈以后,Leader会向全部的Follower发出Commit消息,而后返回客户端成功。 Zab保证数据的一致性是典型的两阶段提交策略。

选举流程:找出一批zxid最大follower,开始投票(paxos算法),投票过半的节点就会成为leader。

Zab协议特色: 1)Zab 协议须要确保那些已经在 Leader 服务器上提交(Commit)的事务最终被全部的服务器提交。 2)Zab 协议须要确保丢弃那些只在 Leader 上被提出而没有被提交的事务。

参考:www.jianshu.com/p/2bceacd60…

9,ZK目录树中每一个节点对应一个Znode。每一个Znode维护这一个属性,当前版本、数据版本(zxid)、创建时间和修改时间等。znode的数据操做是原子性的(实际仍是乐观锁机制,node有版本号)。 zxid在leader和follower选举时颇有意义(找出全部zxid为最大的follower,就是全部follower中数据最新的,此时它能够做为leader),zookeeper每次的节点新增、删除,数据修改都会影响zxid递增。

10,zk的节点类型, 持久节点:该数据节点被建立后,就会一直存在于zookeeper服务器上,直到有删除操做来主动删除这个节点,使用场景:常见的配置中心(如点评的lion) 临时节点:临时节点的生命周期和客户端会话绑定在一块儿,客户端会话失效,则这个节点就会被自动清除。使用场景:①分布式锁(客户端挂掉没法保证心跳,超时致使会话结束,临时节点会被自动删除,锁能够被其它客户端使用),②服务注册中心:服务提供者在ZooKeeper的/dubbo/com.XXX.UserService/providers节点下建立子节点(机器),服务消费者在/dubbo/com.XXX.UserService/consumers建立临时节点 顺序节点:在建立临时或者永久节点时,能够给节点加上递增编号,能够很好解决分布式锁的羊群效应,当锁释放时,只须要通知同一级别的下一个最小节点获取锁,不须要所有通知。 参考:segmentfault.com/a/119000001…

48,分布式锁的实现方式(blog.csdn.net/u010963948/…) 背景:分布式环境下,保证某一段业务逻辑只能被某一台机器执行 实现方式: 1,基于数据库乐观锁的版本号机制实现分布式锁(读取一行记录的版本号,根据版本号去修改,若是修改为功,就表明抢锁成功)。原理:基于行级锁实现,优势:操做简单,容易理解。缺点:不适合高并发场景。 2,基于redis的setnx实现锁建立和释放。原理:基于redis写入操做的原子性(由于redis是单线程),优势:是全部分布式锁中性能最好的(基于内存操做),缺点:因为redis的master-slave同步不是绝对可靠,可能出现锁写入主节点,还没同步到slave(在cluster集群下,客户端加锁能够强制去slave读取一遍,校验锁是否同步成功,不成功就自旋等待) 3,基于zookeeper的临时节点建立实现锁建立和释放,缺点:有羊群效应,须要调用方本身去优化逻辑。

使用redis做为分布式锁注意的问题,cloud.tencent.com/developer/a… 举例:记得给锁加上超时时间,避免执行逻辑过程当中发生异常,致使锁没法被显式释放,锁就会被永久占用,致使其它线程没法再次使用。获取锁时,最好加上本身的线程id,以便在删除锁时,再次判断是否是当前线程的锁(若是不是,须要回滚当前事务)。 备注:setnx有潜在风险,先调用setnx设置锁,再调用expire设置超时,这一连串的操做非原子操做,可能超时未设置成功就发生异常,致使引起锁没法释放,应该调用set方法,锁和超时一块执行。

49,分布式事务的解决方案 分布式事务的应用场景(soa服务化的系统里对数据的操做在不一样的数据库,即保证业务数据在关联的系统中的流转正确性) 一、支付 最经典的场景就是支付了,一笔支付,是对买家帐户进行扣款,同时对卖家帐户进行加钱,这些操做必须在一个事务里执行,要么所有成功,要么所有失败。而对于买家帐户属于买家中心,对应的是买家数据库,而卖家帐户属于卖家中心,对应的是卖家数据库,对不一样数据库的操做必然须要引入分布式事务。 二、在线下单 买家在电商平台下单,每每会涉及到两个动做,一个是扣库存,第二个是更新订单状态,库存和订单通常属于不一样的数据库,须要使用分布式事务保证数据一致性。

解决方案 1,两阶段提交,须要中间协调器的参与,在prepare阶段,协调器向参与方(如支付宝和余额宝的相互转帐)向发起请求,而且开始执行任务,全部参与方执行成功给协调器回复yes,若是全部参与方都回复yes,协调器再通知业务方commit操做(完成事务提交),不然通知全部参与方回滚。

缺点: <1>同步阻塞问题。执行过程当中,全部参与节点都是事务阻塞型的。 当参与者占有公共资源时,其余第三方节点访问公共资源不得不处于阻塞状态。 <2>单点故障。因为协调者的重要性,一旦协调者发生故障。 参与者会一直阻塞下去。尤为在第二阶段,协调者发生故障,那么全部的参与者还都处于锁定事务资源的状态中,而没法继续完成事务操做。(若是是协调者挂掉,能够从新选举一个协调者,可是没法解决由于协调者宕机致使的参与者处于阻塞状态的问题) <3>数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求以后,发生了局部网络异常或者在发送commit请求过程当中协调者发生了故障,这回致使只有一部分参与者接受到了commit请求。 而在这部分参与者接到commit请求以后就会执行commit操做。可是其余部分未接到commit请求的机器则没法执行事务提交。因而整个分布式系统便出现了数据部一致性的现象。

2,3阶段提交须要中间协调器进行协调,第一阶段协调器向全部的参与方发出执行任务的请求(cancommit),若是回应能够,协调器通知参与方进入prepare,并执行任务。执行成功回应协调器,协调器通知全部参与方进入commit,否着回滚,中间还加入了超时机制

3.TCC模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操做。以在线下单为例,Try阶段会去扣库存,Confirm阶段则是去更新订单状态,若是更新订单失败,则进入Cancel阶段,会去恢复库存。总之,TCC就是经过代码人为实现了两阶段提交,不一样的业务场景所写的代码都不同,复杂度也不同,所以,这种模式并不能很好地被复用。 (下单tryLock库存,confirm(下单成功),cancel(下单失败还原库存))

4,消息驱动的方式,消息方案从本质上讲是将分布式事务转换为两个本地事务,而后依靠下游业务的重试机制达到最终一致性。基于消息的最终一致性方案对应用侵入性也很高,应用须要进行大量业务改造,成本较高。(好比下单成功(预约中),消息投递给库存扣减系统,若是库存扣减失败,回调给上游的订单系统)

参考:www.cnblogs.com/jiangyu666/…

49,dubbo rpc原理,参考:www.cnblogs.com/panxuejun/p… <1>服务注册、服务发现 ①服务提供者 服务提供者会在初始化启动时,首先在ZooKeeper的/dubbo/com.jeiker.UserService/providers节点下建立一个子节点(机器ip),写入本身的URL地址,这就表明了“com.jeiker.UserService”这个服务的一个提供者。 ②服务消费者 服务消费者会在启动时,读取并订阅ZooKeeper上/dubbo/com.jeiker.UserService/providers节点下的全部子节点(机器ip,这些机器ip会缓存在服务消费者端,防止zk挂掉,消费者仍能持续访问提供者),解析出全部提供者的URL地址来做为该服务地址列表,而后发起正常调用,同时,服务消费都还会在 ZooKeeper 的 /dubbo/com.jeiker.UserService/consumers节点下建立一个临时节点,并写入本身的URL地址,这就表明了com.jeiker.UserService这个服务的一个消费者。

<2>zookeeper在rpc框架中的模型 dubbo /
/
com.XX.service1 com.XX.service2 /
providers consumers /\ /
10.0.11.11 10.0.11.12 10.0.11.11 10.0.11.12

参考:blog.csdn.net/jeikerxiao/…

欢迎赞扬

相关文章
相关标签/搜索