阿里java高级工程师面试题

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介:

1,java堆,分新生代老年代,新生代有Eden,from surviver,to surviver三个空间,堆被所有线程共。eden内存不足时,发生一次minor GC,会把from survivor和eden的对象复制到to survivor,这次的to survivor就变成了下次的from survivor,经过多次minor GC,默认15次,达到次数的对象会从survivor进行老年代。1次new如果新生代装不下,则直接进入老年代。

2,HashMap和HashTable是使用数组+链表结构实现,根据Hash和table长度计算数组的下标index做操作,hashMap默认数组长度为16,hashMap对null值的key都放在table[0]的位置,table[index]形成1个链表,当然在新版jdk中链表节点数>8会变成红黑树结构。hashMap达到最大数量会扩容,扩容table长度变为2倍,每个元素(table中)但重新计算index放到新的table中。

3,堆的年轻代和老年代。

堆的年轻代大则老年代小,GC少,但是每次时间会比较长。年轻代小则老年代大,会缩短每次GC的时间,但是次数频繁。可以让老年代尽量缓存常用对象,JVM默认年轻代和老年代的大小比例为1:2,。观察峰值老年代内存,不影响full GC,加大老年代可调1:1,但是要给老年代预留三分之一的空间。减少使用全局变量和大对象 ,调整新生代,老年代到最合适。

4,字节流不会用到内存缓冲区,文件本身直接操作。字符流操作使用内存缓存区,用缓存存操作文件。字符流在输出前将所有内容暂时保存到内存中,即缓存区暂时存储,如果想不关闭也将字符流输出则可以使用flush方法强制刷出。字节字符转化可能存在系统编码lang,要制定编码。getbyte字节流使用更加广泛。

5,中文占用2个字节,read()函数读1个字节把A会读入的原因。ASCII码是8位,A在ASCII码中有对应码,A只要8位就能表示,但是unicode是支持ASCII码的,在unicode中表示A是使用低8位的ASCII码,补上高8位的0,read()1分字节就已经读入A的ASCII码,打印时会给其高8位补上0,所以显示正常A。

6,唤醒一个阻塞的线程

如因为Sleep,wait,join等阻塞,可以使用interrupted exception异常唤醒。

7,内存溢出可能原因和解决。

原因可能是A,数据加载过多,如1次从数据库中取出过多数据   B,集合类中有对对象的引用,用完后没有清空或者集合对象未置空导致引用存在等,是的JVM无法回收  C,死循环,过多重复对象 D,第三方软件的bug       E,启动参数内存值设定的过小。

例如方法:修改JVM启动参数,加内存(-Xms,-Xmx);错误日志,是否还有其他错误;代码走查

8,redis使用单线程模型,数据顺序提交,redis支持主从模式,mencache只支持一致性hash做分布式;redis支持数据落地,rdb定时快照和aof实时记录操作命令的日志备份,memcache不支持;redis数据类型丰富,有string,hash,set,list, sort set,而memcache只支持简单数据类型;memcache使用cas乐观锁做一致性。

jedis操作Hash:hmset, hmget, hdel, hkeys

jedis操作List: lpush,lrange按照范围取出,rpush, del, sort等keyjedis操作Set:sadd,srem移除noname,smembers, sismember, scard等。

使用场景例如

Hash:存储读取更新用户多个属性

List:微博TimeLine,消息列表

Set:共同好友,二度好友,用唯一性可以统计网站所有独立IP,好友推荐根据tag求交集,大于threshold就可以推荐。

sortset:set增加1个权重score参数

其他场景:A订阅发布系统,redis对某个key消息发布及订阅,当1个key消息发布后,所有订阅它的客户端都会收到相应消息,例如实时消息系统,即时聊天,群聊等。

事务-常用EX,EC提交执行的命令,在server不出问题,可以保证一连串的命令是顺序执行额;提供1个watch功能,对1个key作watch,然后再执行transation。



9,Class.forName()将类加载到JVM,还会对类解释,执行static块,而ClassLoader也加载到JVM,但是不会执行static块,并且只有调用了new Instance方法才会调用构造函数。

10,java反射机制。

可以在运行时判断一个对象所属的类,构造一个类的对象,判断类具有的成员变量和方法,调用1个对象的方法。4个关键的类:Class,Constructor,Field,Method。    getConstructor获得构造函数/getDeclardConstructor; getField/getFields/getDeclardFields获得类所生命的所有字段;getMethod/getMethods/getDeclardMethod获得类声明的所有方法,正常方法是一个类创建对象,而反射是1个对象找到1个类。

11,Object类中的方法:clone(),但是使用该方法必须实现Java.lang.Cloneable接口,equal()方法判断引用是否一致,指向同一对象,即相等于==,只有覆写了equals()方法之后,才可以说不同。hashcode(),对象的地址, toString(), finalize()。

12,序列化和反序列化

序列化和反序列化即对象和字节序列间的转化,进程间传送文本图片音频等以二进制传送。JDK中ObjectOuputStream和ObjectInputStream为输出输入流,只有实现SeriaLizable/Externalizable接口的类才能被序列化。如Person对象传递给内存流使用DataConstractJsonSeralizer, MemoryStream stream = new MemoryStream(); DataConstractJsonSeralizer SER = new DataConstractJsonSeralizer(typeof(person));  ser.writeObjectStream(stream, person);显示json输出,StramReader sr = new StreamReader(stream1); sr.ReadToEnd()。

13,讲讲分布式唯一ID。

确定ID存储用64位,1个64位二进制1是这样的00000000.....1100......0101,切割64位,某段二进制表示成1个约束条件,前41位为毫秒时间,后紧接9位为IP,IP之后为自增的二进制,记录当前面位数相同情况下是第几个id,如现在有10台机器,这个id生成器生成id极限是同台机器1ms内生成2的14次方个ID。

分布式唯一ID = 时间戳 << 41位, int类型服务器编号 << 10,序列自增sequence。每个时间戳内只能生成固定数量如(10万)个自增号,达到最大值则同步等待下个时间戳,自增从0开始。将毫秒数放在最高位,保证生成的ID是趋势递增的,每个业务线、每个机房、每个机器生成的ID都是不同的。如39bit毫秒数|4bit业务线|2bit机房|预留|7bit序列号。高位取2016年1月1日1到现在的毫秒数,系统运行10年,至少需要10年x365天x24小时x3600秒x1000毫秒=320x10~9,差不多39bit给毫秒数,每秒单机高峰并发小于100,差不多7bit给每毫秒的自增号,5年内机房小于100台机器,预留2bit给机房,每个机房小于100台机器,预留7bit给每个机房,业务线小于10个,预留4bit给业务线标识。

64bit分布式ID(42bit毫秒+5bit机器ID+12位自增)等

生成分布式ID的方式:A,2个自增表,步长相互隔开   B,时间的毫秒或者纳秒  C,UUID         D,64位约束条件(如上)

14,NIO和IO的区别

第一点,NIO少了1次从内核空间到用户空间的拷贝。

ByteBuffer.allocateDirect()分配的内存使用的是本机内存而不是Java堆上的内存,和网络或者磁盘交互都在操作系统的内核空间中发生。allocateDirect()的区别在于这块内存不由java堆管理, 但仍然在同一用户进程内。

第二点,NIO以块处理数据,IO以流处理数据

第三点,非阻塞,NIO1个线程可以管理多个输入输出通道

15,内存泄漏

未对作废数据内存单元置为null,尽早释放无用对象的引用,使用临时变量时,让引用变量在推出活动域后自动设置为null,暗示垃圾收集器收集;程序避免用String拼接,用StringBuffer,因为每个String会占用内存一块区域;尽量少用静态变量(全局不会回收);不要集中创建对象尤其大对象,可以使用流操作;尽量使用对象池,不再循环中创建对象,优化配置;创建对象到单例getInstance中,对象无法回收被单例引用;服务器session时间设置过长也会引起内存泄漏。

16,对象克隆和实现方式

克隆的对象可能包含一些已经修改过的属性,而new1个对象属性都还是初始化时候的值,被复制克隆的类要实现Clonable接口,覆盖clone()方法,访问修饰符为public,方法中调用super.clone()得到所需要的复制方法,类中的属性类也需要实现Clonable接口,覆写clone()方法,并在super中也调用子属性类的clone()复制,才可以实现深拷贝。

或者写到流中序列化的方式来实现,不必考虑引用类型中还包含引用类型,直接用序列化来实现对象的深复制拷贝,即将对象写到流,再从流中读出来,需要实现seriazation接口。

17,redis内存数据上升到一定大小会执行数据淘汰策略,redis提供了6种数据淘汰策略。

LRU:从已设置过期时间的数据集合中挑选最近最少使用的数据淘汰

random:从已设置过期时间的数据中挑选任意数据淘汰

ttl:从已设置过期时间的数据集合中挑选将要过期的数据淘汰。

notenvision:禁止驱逐数据

如mysql中有2千万数据,redis只存储20万的热门数据。LRU或者TTL都满足热点数据读取较多,不太可能超时特点。

redis特点:速度块,O(1),丰富的数据类型,支持事物原子性,可用于缓存,比memecache速度块,可以持久化数据。

常见问题和解决:Master最好不做持久化如RDB快照和AOF日志文件;如果数据比较重要,某分slave开启AOF备份数据,策略为每秒1次,为了主从复制速度及稳定,MS主从在同一局域网内;主从复制不要用图状结构,用单向链表更为稳定 M-S-S-S-S。。。。;redis过期采用懒汉+定期,懒汉即get/set时候检查key是否过期,过期则删除key,定期遍历每个DB,检查制定个数个key;结合服务器性能调节并发情况。

过期淘汰,数据写入redis会附带1个有效时间,这个有效时间内该数据被认为是正确的并不关心真实情况,例如对支付等业务采用版本号实现,redis中每一份数据都维持1个版本号,DB中也维持1份,只有当redis的与DB中的版本一致时,才会认为redis为有效的,不过仍然每次都要访问DB,只需要查询version版本字段即可。

18,异步化,生产接口每秒钟10万并发,消费者用异步慢慢消费。缓存模式空间换时间,把1两亿的数据名单打到缓存。服务降级,把不重要的任务放弃;静态资源离线包下载机制,在wify下会主动提前把静态下载前端层保护可请将用户请求延长,点击后主动给它随机等待2s的时间/2分钟之内不能请求;后端做部分接口的开关,设置超短耗时时间,原来只用5ms的只给20ms。

系统一段时间内会自动重试,重试多次后就认为是失败了,检查支付接口返回该订单的钱,支付操作如果回复错误则回滚扣库存的事务,没返回则会记录进行中pendding状态,结束整个过程,等通知失败/成功,AB系统之间会出现死循环补偿,如B退单不成功,一般就是记录错误日志了。超时每隔一段时间去定时回调服务定时回滚,一定次数还是超时则提示用户联系客服,订单库存可以不会滚,记录状态,如果一直调用支付不成功,则让用户自己去处理联系客服,可以不回滚用户的数据,金额扣了才算真正完成,是一种简单粗暴的做法。

公共配置抽象成存储到zookeeper配置中心或者redis等,DB也存储一份,各应用监听ZK的配置变化,可以建一个配置web管理页面。

19,dubbo用ProxyFactoty代理工厂将HelloServiceImpl封装成1个Inoke执行,即ProxyFactory.getInvoke(ref, (Class)接口,注册URL,解码参数),并将Invoke导出成1个Exporter,包括去注册中心ZK注册服务。Invoke有本地执行的Invoke,远程通信执行的Invoke。

20,每次扣减库存时加上1个请求流水编号,上层请求扣减库存没拿到结果的话,重新查询1次做重试操作,量不大都是加锁处理。减少锁的时间,牺牲幂等性,扣减为DB下地操作,查询扣减和设置合成1步,中间没有网络请求。利用缓存,通过写log记录操作,异步合并日志及更新,重启时cache失效,读log恢复,避免重复提交,写操作不建议重试快速失败。多个商品同时增减库存,可使用订单号做幂等处理,应用层对单个商品减库存,操作排队,商品消息ID路由在1个应用server处理,读本地缓存,失效再redis,DB采用乐观锁,组提交,1次减库存多个订单的购买量。可将同一个key下库存m分为n组k1......kn,每组数为m/n,扣减依次在各组扣减,减少并发冲突。队列装满后关闭队列进入,然后用户轮训自己是否抢到了异步ajax,用户资源队列固定长度。2个队列,1个销售的资源队列放入redis,有另外1个队列用来装抢购的会员的uid。

红包状态正常,并成功将状态改为“已领取”,且消息发送成功,用户端开始消费该消息,如果消费失败/超时,用MQ做重试做幂等,直到成功,每条消息有唯一编号且保证消息处理成功与去重表的日志同时出现。

热点将hot data拆分,分在不同库和不同表,分散热点Data,减轻DB并发更新热点带来RT升高和应用连接超时。SQL在mysql层加以限制,SQL超时/thradrunning到1定值则拒绝SQL执行,一定时间异步将结果写入DB,nginx对IP做限制,可能误杀。

21,SpringAOP,XML配置<aop:config>,切面<aop:aspect>切点<aop:pointcut>,连接切点和通知方法<aop:before>和<aop:after>等,注解可以直接使用@before执行方法@after ,@before(“pointcut()”) ,@after("pointcut"), @Aroud("excutete()),@AfteReturning,@AfterThrowing,可作日志事务,权限等待,AOP即通过把具体的类创建对应的 代理类,从代理类来对具体进行操作。                      

目标实现了接口,默认采用JDK实现AOP,也可以强制使用CGlib来实现AOP,目标没有实现接口的话,则必须采用CGlib,Spring自动在JDK和CGlib切换。如果要求spring强制使用CGlib实现AOP,则可以配置,添加Cglib库。。。jar, Spring配置文件中加入<aop:aspecj-autoproxy proxy-target-Class=true>                                                                                                                                                                                   

22,MyISM采用表级锁,对Myism表读不会阻塞读,会阻塞同表写,对Myism写则会阻塞读和写,即一个线程获得1个表的写锁后,只有持有锁的线程可以对表更新操作,其他线程的读和写都会等待。

InnoDB,采用行级锁,支持事务,例如只对a列加索引,如果update ...where a=1 and b=2其实也会锁整个表, select 使用共享锁,update insert delete采用排它锁,commit会把锁取消,当然select by id for update也可以制定排它锁。

23,实时队列采用双队列模式,生产者将行为记录写入Queue1,worker服务从Queue1消费新鲜数据,如果异常则写入Queue2(主要保存异常数据),RetryWorker会监听Queue2,消费异常数据,如果还未处理成功按照一定的策略等待或者将异常数据再写入Queue2,如果数据发生积压可以调整worker的消费游标,从最新数据重新开始消费,保证了最新data得到处理,中间未处理的一段则可以启动backupWorker指定起止游标在消费完指定区间的数据后,backupWorker会自动停止。

DB降级开关后,可直接写入redis(storm),同时将数据写入一份到Retry队列,在开启DB降级开关后消费Retry队列中的数据,从而把数据写入到mysql中,达到最终一致性。MYSQL切分为分片为2的N次方,例如原来分为两个库d0和d1均放在s0服务器上,s0同时有备机s1,扩容只要几步骤:确保s0到s1服务器同步顺利,没有明显延迟;s0暂时关闭读写权限;确保s1已经完全同步到s0更新;s1开放读写权限;d1的dns由s0切换到s1;s0开放读写权限。

24,DB的特性和隔离级别

4大特性:原子性,一致性,分离性,持久性

隔离级别:

读提交:写事务禁止读

读未提交:写事务允许读

可重复读:写事务禁止读事务,读禁止写

序列化:全部禁止

详细说明:读提交1个事务开始写则全部禁止其他事务访问该行。读未提交1个事务开始写则不允许其他事务同时写,但可以读。可重复读 读事务会禁止写事务,写事物则禁止其他任何事务。序列化性能最低,全部禁止,串行执行。 MYSQL默认的是可重复读。

25,帖子服务、元数据服务、帖子搜索服务,提供索引数据存储,tid和uid查询直接从帖子服务从元数据返回,其他检索查询有帖子搜索服务从索引数据检索并返回,帖子服务增删改查用MQ同步到帖子搜索服务,搜索服务修改索引的数据(索引树,倒排表),索引表t_mapping(tid,uid)。

300亿数据在全量索引库中,数百万一天内修改过的数据在一天库中,50万小时内修改过的数据在小时库中,在update请求时,只会操作最低级别的索引例如小时库。小时库,1小时合并一次,合并到天库,天库一天合并1次,合并到全量库中。

26,讲一下NIO和网络传输

NIO Reactor反应器模式,例如汽车是乘客访问的实体reactor,乘客上车后到售票员处Acceptor登记,之后乘客便可休息睡觉了,到达乘客目的地后,售票员Aceptor将其唤醒即可。持久TCP长链接每个client和server之间有存在一个持久连接,当CCU(用户并发数量)上升,阻塞server无法为每个连接运行1个线程,自己开发1个二进制协议,将message压缩至3-6倍,传输双向且消息频率高,假设server链接了2000个client,每个client平均每分钟传输1-10个message,1个messaged的大小为几百字节/几千字节,而server也要向client广播其他玩家的当前信息,需要高速处理消息的能力。Buffer,网络字节存放传输的地方,从channel中读写,从buffer作为中间存储格式,channel是网络连接与buffer间数据通道,像之前的socket的stream。

27,缓存击透

预加载;

加载DB时同步,其他则等待;

DB端做SQL合并,Queue合并排队处理;

部分缓存设置为永不过期;

先清除缓存,读取数据时候则等待500ms,500ms缓存应该已经加载完成;

采用双key缓存,A1为原始缓存,A2为拷贝缓存;

如果DB为空null则g给redis设置1个NFC空nei容。

28,Dubbo源码使用了哪些设计模式

A,工厂模式,ExtenstionLoader.getExtenstionLoader(Protocol.class).getAdaptiveExtenstion()

B,装饰器模式+责任链,以provider的调用链为例,具体调用链代码是在protocolFilterWrapper的buildInvokeChain完成的,将注解中含有group=provider的Filter实现,调用顺序为EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter -> ExceptionFilter -> TimeoutFilter -> MonitorFilter -> TraceFilter。装饰器模式和责任链混合使用,Echo是回声测试请求,ClassLoaderFilter则只是在其主功能上添加了功能。

C,观察者模式,provider启动时需要与注册中心交互,先注册自己的服务,再订阅自己的服务,订阅时采用了观察者模式,注册中心每5s定时检查是否有服务更新,有更新则向服务提供者发送1个notify消息后即可运行NotifyListener的notity方法,执行监听器方法。

D,动态代理模式。  扩展JDK的ExtensionLoaderdeAdaptive实现,根据调用阶段动态参数决定调用哪个类,生成代理类的代码是ExtensionLoader的createAdaptiveExtenstionClassLoader方法。

29,平衡二叉树,左右高度之差不超过1,Add/delete可能造成高度>1,此时要旋转,维持平衡状态,避免二叉树退化为链表,让Add/Delete时间复杂度但控制在O(log2N),旋转算法2个方法,1是求树的高度,2是求2个高度最大值,1个空树高度为-1,只有1个根节点的树的高度为0,以后每一层+1,平衡树任意节点最多有2个儿子,因此高度不平衡时,此节点的2棵子树高度差为2。例如单旋转,双旋转,插入等。

红黑树放弃完全平衡,追求大致平衡,保证每次插入最多要3次旋转就能平衡。

30,多线程同步锁

A,RentrantLock,可重入的互斥锁,可中断可限时,公平锁,必须在finally释放锁,而synchronize由JVM释放。可重入但是要重复退出,普通的lock()不能响应中断,lock.lockInterruptbly()可响应中断,可以限时tryLock(),超时返回false,不会永久等待构成死锁。

B,Confition条件变量,signal唤醒其中1个在等待的线程,signalall唤醒所有在等待的线程await()等待并释放锁,与lock结合使用。

C,semaphore信号量,多个线程比(额度=10)进入临界区,其他则阻塞在临界区外。

D,ReadWriteLock,读读不互斥,读写互斥,写写互斥。

E,CountDownLantch倒数计时器,countdown()和await()

F,CyCliBarrier

G,LockSupport,方法park和unpark

31,栈溢出的原因

是否递归的调用;大量循环;全局变量是否过多;数组,List,Map数据是否过大;用DDMS工具检查地方。

内存溢出的原因

过多使用了static;static最好只用int和string等基本类型;大量的递归或者死循环;大数据项的查询,如返回表的所有记录,应该采用分页查询。检查是否有数组、List、map中存放的是对象的引用而不是对象,这些引用会让对应对象不能被释放。

栈过大会导致内存占用过多,频繁页交换阻碍效率。

32,说一下http/2

Http/2采用二进制格式而不是文本

Http/2是完全多路复用的,而非有序并阻塞的。

Http/2使用报头压缩

Http/2让服务器可以将响应主动推送到客户端缓存中。

33,说一下内存泄露

A,HashMap,vector等容易(静态集合类), 和应用程序生命周期一样,所引用的所有对象Object也不能释放。

B,当集合类里面的对象属性被修改后,再调用remove()不起作用,hashcode值发生了改变

C,其对象add监听器,但是往往释放对象时忘记去删除这些监听器

D,各种连接记得关闭

E,内部类的引用

F,调用其他模块,对象作用参数

G,单例模式,持有外部对象引用无法收回。

内存泄露例子

Vector<String> A = new Vector<String>();

for(int i = 0; i < 100; i++){

Object o = new Object ();

A.add(o);

o = null;

}

 ........

内存溢出的例子

StringBuffer b = new StringBuffer ();

for(int i =0; i < 100; i++){

for(int j =0; i < 100; j++){

b.append(*);

}

}

34,SpirngMVC的生命周期 和 SpringBean的生命周期

SpirngMVC的生命周期 :

A,DispatcherSerlvet(前端控制器)

B,-》 HandlerMapping(处理器映射器),根据xml注解查找对应的Hander -》 返回Handler

C,-》处理器适配器去执行Handler

D,-》Handler执行完成后给处理器适配器返回ModelAndView

E,-》前端控制器请求视图解析器去执行视图解析,根据逻辑视图名解析成真正的视图JSP,向前端控制器返回view

F,-》前端控制器进行视图渲染,将模型数据放到request-》返回给用户

SpringBean的生命周期:

Instance实例化-》设置属性值-》调用BeanNameAware的setBeanName方法-》调用BeanPostProsessor的预初始化方法-》调用InitializationBean的afterPropertiesSet()的方法-》调用定制的初始化方法callCustom的init-method-》调用BeanPostProsessor的后初始化方法-》Bean可以使用了 -》 容器关闭-》 调用DisposableBean的destroy方法-》调用定制的销毁方法CallCustom的destroy-method。

35,AQS,抽象队列同步器

AQS定义2种资源共享方式:独占与share共享

独占:只能有1个线程运行

share共享:多个线程可以同p执行如samphore/countdownlanch

AQS负责获取共享state的入队和/唤醒出队等,AQS在顶层已经实现好了,AQS有几种方法:acquire()是独占模式下线程共享资源的顶层入口,如获取到资源,线程直接返回,否则进入等待队列,直到获取到资源为止。tryAcquire()将线程加入等待队列的尾部,并标志为独占。acquireQueued()使线程在等待队列中获取资源,一直到获取资源后不返回,如果过程被中断也返回true,否则false。

线程在等待过程中被中断是不响应的,获取资源才补上中断。将线程添加到队列尾部用了CAS自旋(死循环直到成功),类似于AutomicInteger的CAS自旋volatile变量。

start->tryAcquire -> 入队 -> 找安全点 -> park等待状态 -> 当前节点成对头 -> End

36,单例模式的7种写法

懒汉2种,枚举,饿汉2种,静态内部类,双重校验锁(推荐)。

37,lucence倒排索引

三个文件:字典文件,频率文件,位置文件。词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。

field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典文件中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。

关键字是按字符顺序排列的(lucene没有使用B树结构),因此lucene可以用二元搜索算法快速定位关键词

假设要查询单词 “live”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。   

对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。对数字的压缩,数字只保存与上一个值的差值。

38,ZooKeeper分布式高可用

ZooKeeper 运行期间,集群中至少有过半的机器保存了最新数据。集群超过半数的机器能够正常工作,集群就能够对外提供服务。

zookeeper可以选出N台机器作主机,它可以实现M:N的备份;keepalive只能选出1台机器作主机,所以keepalive只能实现M:1的备份。

通常有以下两种部署方案:双机房部署(一个稳定性更好、设备更可靠的机房,这个机房就是主要机房,而另外一个机房则更加廉价一些,例如,对于一个由 7 台机器组成的 ZooKeeper 集群,通常在主要机房中部署 4 台机器,剩下的 3 台机器部署到另外一个机房中);三机房部署(无论哪个机房发生了故障,剩下两个机房的机器数量都超过半数。在三个机房中都部署若干个机器来组成一个 ZooKeeper 集群。假设机器总数为 N,各机房机器数:N1 = (N-1)/2 ,N2=1~(N-N1)/2 ,N3 = N - N1 - N2 )。

水平扩容就是向集群中添加更多机器,Zookeeper2种方式(不完美),一种是集群整体重启,另外一种是逐台进行服务器的重启。











本文转自yunlielai51CTO博客,原文链接:http://blog.51cto.com/4925054/2083722 ,如需转载请自行联系原作者

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
24天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
64 2
|
13天前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
40 14
|
4天前
|
存储 NoSQL 架构师
阿里面试:聊聊 CAP 定理?哪些中间件是AP?为什么?
本文深入探讨了分布式系统中的“不可能三角”——CAP定理,即一致性(C)、可用性(A)和分区容错性(P)三者无法兼得。通过实例分析了不同场景下如何权衡CAP,并介绍了几种典型分布式中间件的CAP策略,强调了理解CAP定理对于架构设计的重要性。
28 4
|
23天前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
29天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
1月前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
18天前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
25 6
|
22天前
|
存储 NoSQL 算法
阿里面试:亿级 redis 排行榜,如何设计?
本文由40岁老架构师尼恩撰写,针对近期读者在一线互联网企业面试中遇到的高频面试题进行系统化梳理,如使用ZSET排序统计、亿级用户排行榜设计等。文章详细介绍了Redis的四大统计(基数统计、二值统计、排序统计、聚合统计)原理和应用场景,重点讲解了Redis有序集合(Sorted Set)的使用方法和命令,以及如何设计社交点赞系统和游戏玩家排行榜。此外,还探讨了超高并发下Redis热key分治原理、亿级用户排行榜的范围分片设计、Redis Cluster集群持久化方式等内容。文章最后提供了大量面试真题和解决方案,帮助读者提升技术实力,顺利通过面试。
|
25天前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
72 2
|
26天前
|
SQL 关系型数据库 MySQL
阿里面试:1000万级大表, 如何 加索引?
45岁老架构师尼恩在其读者交流群中分享了如何在生产环境中给大表加索引的方法。文章详细介绍了两种索引构建方式:在线模式(Online DDL)和离线模式(Offline DDL),并深入探讨了 MySQL 5.6.7 之前的“影子策略”和 pt-online-schema-change 方案,以及 MySQL 5.6.7 之后的内部 Online DDL 特性。通过这些方法,可以有效地减少 DDL 操作对业务的影响,确保数据的一致性和完整性。尼恩还提供了大量面试题和解决方案,帮助读者在面试中充分展示技术实力。