Java面试——架构设计与分布式

目录

一、用 Java 自己实现一个 LRU

二、分布式集群下如何做到唯一序列号

三、设计一个秒杀系统,30分钟没付款就自动关闭交易

四、如何使用 Redis 和 Zookeeper 实现分布式锁

五、如果有人恶意创建非法连接,怎么解决

六、分布式事务的原理

七、什么是一致性 hash

八、什么是 Restful,讲讲你理解的 Restful

九、如何设计一个良好的API

十、如何设计建立和保持100w的长连接

十一、解释什么是MESI协议(缓存一致性)

十二、说说你知道的几种HASH算法,简单的也可以

十三、什么是paxos算法, 什么是zab协议

十四、一个在线文档系统,文档可以被编辑,如何防止多人同时对同一份文档进行编辑更新

十五、线上系统突然变得异常缓慢,你如何查找问题

十六、说说你平时用到的设计模式

十七、Dubbo的原理

十八、一次RPC请求的流程是什么

十九、自己实现过rpc么,原理可以简单讲讲。Rpc要解决什么问题

二十、异步模式的用途和意义

二十一、编程中自己都怎么考虑一些设计原则的,比如开闭原则,以及在工作中的应用

二十二、设计一个社交网站中的“私信”功能,要求高并发、可扩展等等。 画一下架构图

二十三、MVC模式,即常见的MVC框架

二十四、聊下曾经参与设计的服务器架构并画图,谈谈遇到的问题,怎么解决的

二十五、应用服务器怎么监控性能,各种方式的区别

二十六、如何设计一套高并发支付方案,架构如何设计

二十七、如何实现负载均衡,有哪些算法可以实现

二十八、Zookeeper的用途,选举的原理是什么

二十九、Zookeeper watch机制原理

三十、Mybatis的底层实现原理

三十一、请思考一个方案,实现分布式环境下的countDownLatch

三十二、后台系统怎么防止请求重复提交

三十三、描述一个服务从发布到被消费的详细过程

三十四、讲讲你理解的服务治理

三十五、如何做到接口的幂等性

三十六、如何做限流策略,令牌桶和漏斗算法的使用场景

三十七、什么叫数据一致性,你怎么理解数据一致性

三十八、分布式服务调用方,不依赖服务提供方的话,怎么处理服务方挂掉后,大量无效资源请求的浪费

三十九、dubbo的泛化调用怎么实现的,如果是你,你会怎么做

四十、远程调用会有超时现象,如果做到优雅的控制,JDK自带的超时机制有哪些,怎么实现的


一、用 Java 自己实现一个 LRU


LRU(Least Recently Used:最近最少使用):简单的说,就是保证基本的Cache容量,如果超过容量则必须丢掉最不常用的缓存数据,再添加最新的缓存。每次读取缓存都会改变缓存的使用时间,将缓存的存在时间重新刷新。其实,就是清理缓冲的一种策略。
我们可以通过双向链表的数据结构实现 LRU Cache,链表头(head)保存最新获取和存储的数据值,链表尾(tail)既为最不常使用的值,当需要清理时,清理链表的 tail 即可,并将前一个元素设置为tail。结构图如下:
     Java面试——架构设计与分布式_第1张图片
Java 代码实现:1)、通过原理的分析,我们可以维护一个双向链表结构,如下:LRUNode 实体类,主要理解 prev 和 next 属性,结合上面的链表结构图,就可以理解为,当此对象为 3 时 , prev 应指向 2 , next 应指向 4 。此类为下面类的类种类。

/**
 * @ClassName:       LRUNode
 * @Description:    定义一个链表类,包含head(指针的上一个对象),tail(指针的下一个对象)类种类
 * @author:          zzx
 * @date:            2019年3月4日        下午10:32:58
 */
 class LRUNode {
	private String key;
	private Object value;
	//当前对象的上一个对象
	LRUNode prev;
	//当前对象的下一个对象
	LRUNode next;
	
	/**
	 * @param key  value
	 * @desc 带有参数的构造器 
	 */
	public LRUNode(String key,Object value) {
		this.key=key;
		this.value=value;
	}
}

2)、我们通过 HashMap 实现一个缓存类 LRUCache 我们通过逻辑处理,对最少使用的数据进行删除。代码如下:

/**
 * @ClassName:       LRUCache
 * @Description:    实现 LRU策略 清除缓存(当缓存大小>=指定大小时)
 * @author:          zzx
 * @date:            2019年3月4日        下午11:42:11
 */
public class LRUCache {
	private int capacity;
	/**
	 * @desc 用来存储 key 和 LRUNode对象 充当缓存,且 hashmap 中的数据不会自动清理,需要我们手动清理
	 */
	private HashMap hashMap;
	
	//数据链表 第一个对象
	private LRUNode head;
	//数据链表 最后一个对象
	private LRUNode tail;
	
	//带参数 capacity 缓存打下的构造器
	public LRUCache(int capacity) {
		this.capacity=capacity;
		//创建对象时,创建一个hashmap 充当缓存
		hashMap = new HashMap();
	}
	/**
	 * @Description:    向链表中插入数据
	 * @return:         void   
	 */
	public void set(String key , Object value) {
		//通过 key 查询链表中是否存在此对象
 		LRUNode lruNode = hashMap.get(key);
 		//缓存中有值时
 		if(lruNode != null) {
 			//为key 附新值,替换就值
 			lruNode.value = value;
 			//更新链表指针
 			appendTail(lruNode,false);
 		//缓存中无值时	
 		}else {
 			//新对象
 			lruNode = new LRUNode(key, value);
 			//判断 hashMap 是否大于缓存大小
 			if(hashMap.size() >= capacity) {
 				appendTail(tail,true);
 			}
 			//存取新值
 			hashMap.put(key, lruNode);
 		}
 		
 	    //将新值设置为 head
 		setHead(lruNode);
	}
	
	/**
	 * @Title:             appendTail
	 * @Description:     更新链表的前后指针,新增数据公用
	 */
	public void appendTail(LRUNode lNode,boolean flag) {
		//存在上一个对象 prev
		if(lNode.prev != null) {
			//当前对象的上一个对象指向,当前对象的下一个对象。例如:2<-3(当前对象)->4 更新后: 2——>4
			lNode.prev.next = lNode.next;
		//如果不存在,下一个对象为 head 对象(暂不考虑更改对象)
		}else {
			head=lNode.next;
		}
		
		//存在下一个对象 next
		if(lNode.next != null) {
			// 4——>2
			lNode.next.prev=lNode.prev;
		}else {
			//如果当前对象是最后一个对象,则上一个对象就为最后一个对象
			tail=lNode.prev;
		}
		
		lNode.prev=null;
		lNode.next=null;
		//如果内存不足,需要删除tail
		if(flag) {
			hashMap.remove(lNode.key);
		}
	}
	
	/**
	 * @Title:             setHead
	 * @Description:     设置链表的 头 节点
	 * @param:           node   
	 * @return:         void   
	 */
	public void setHead(LRUNode node) {
		if(head != null) {
			node.next=head;
			head.prev=node;
		}
		head=node;
		if(tail == null) {
			tail=node;
		}
	}
}

二、分布式集群下如何做到唯一序列号


分布式架构下,生成唯一序列号是设计系统常常会遇到的一个问题。例如,数据库使用分库分表的时候,当分成若干个 sharding 表后,如何能够快速拿到一个唯一序列号,是经常遇到的问题。实现思路如下:
【1】数据库自增长序列或字段:全数据库唯一。
优点简单,代码方便,性能可以接受。数字ID天然排序,对分页后者需要排序的结果很有帮组。适合小应用,无需分表,么有高并发性能要求。
【缺点不同数据库实现不同,在水平分表时,使用自增ID时可能会出现ID冲突。同时在高并发的情况下需要使用事务。在性能达不到要求的情况下,比较难于扩展。如果多个系统需要合并或者设计到数据迁移会相当痛苦。
优化针对主库单点,如果有多个Master库,则每个Master库设置的起始数字不一样,步长一样,可以是Master的个数。比如:Master1 生成的是 1,4,7,10,Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。这样就可以有效生成集群中的唯一ID,也可以大大降低ID生成数据库操作的负载。
【2】UUID:常见的方式。可以利用数据库也可以利用程序生成32位的16进制格式的字符串,唯一性很高。
【优点简单,方便,生产ID性能非常好且全球基本唯一,在数据迁移和系统后期合并,或数据库变更等情况下都可应对。
缺点】没有排序,无法保证趋势递增。UUID使用字符串存储,查询效率低。存储空间较大,如果数据海量就绪考虑存储量问题,传输数据量大。
【3】Redis生成ID:当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用 Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用 Redis的原子操作 INCR和INCRBY来实现。可以使用Redis集群来获取更高的吞吐量。假如一个集群中有5台Redis。可以初始化每台 Redis的值分别是1,2,3,4,5,然后步长都是5。各个Redis生成的ID为:
A:1,6,11,16,21
B:2,7,12,17,22
C:3,8,13,18,23
D:4,9,14,19,24
E:5,10,15,20,25
这个,随便负载到哪个机器确定好,未来很难做修改。但是3-5台服务器基本能够满足器上,都可以获得不同的ID。但是步长和初始值一定需要事先需要了。使用 Redis集群也可以防止单点故障(系统中一点失效,就会让整个系统无法运作的部件)的问题。另外,比较适合使用 Redis来生成每天从0开始的流水号。比如订单号=日期+当日自增长号。可以每天在 Redis中生成一个 Key,使用 INCR进行累加。
【优点】:不依赖于数据库,灵活方便,且性能优于数据库。数字ID天然排序,对分页或者需要排序的结果很有帮助。
【缺点】:如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。需要编码和配置的工作量比较大。
【4】Twitter(推特) 的 snowflake 算法:twitter 在把存储系统从 MySQL 迁移到 Cassandra(一套开源分布式NoSQL数据库系统)的过程中由于 Cassandra 没有顺序 ID 生成机制,于是自己开发了一套全局唯一 ID 生成服务:Snowflake。
    ●  41位的时间序列(精确到毫秒,41位的长度可以使用69年)
    ●  10位的机器标识(10位的长度最多支持部署1024个节点)
    ●  12位的计数顺序号(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号) 最高位是符号位,始终为0
Snowflake 的结构如下(每部分用-分开):一共加起来刚好64位,为一个Long型。(转换成字符串后长度最多19)
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
snowflake 生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。经测试 snowflake每秒能够产生26万个ID。
【优点】:高性能,低延迟;独立的应用;按时间有序。
【缺点】:需要独立的开发和部署。在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,也许有时候也会出现不是全局递增的情况。
【5】MongoDB 的 ObjectId:MongoDB 的 ObjectId 和 snowflake 算法类似。它设计成轻量型的,不同的机器都能用全局唯一的同种方法方便地生成它。MongoDB 从一开始就设计用来作为分布式数据库,处理多个节点是一个核心要求。使其在分片环境中要容易生成得多。
Java面试——架构设计与分布式_第2张图片
前4 个字节是从标准纪元开始的时间戳,单位为秒。时间戳,与随后的5 个字节组合起来,提供了秒级别的唯一性。由于时间戳在前,这意味着ObjectId 大致会按照插入的顺序排列。这对于某些方面很有用,如将其作为索引提高效率。这4 个字节也隐含了文档创建的时间。绝大多数客户端类库都会公开一个方法从ObjectId 获取这个信息。
接下来的3 字节是所在主机的唯一标识符。通常是机器主机名的散列值。这样就可以确保不同主机生成不同的ObjectId,不产生冲突。
为了确保在同一台机器上并发的多个进程产生的ObjectId 是唯一的,接下来的两字节来自产生ObjectId 的进程标识符(PID)。
前9 字节保证了同一秒钟不同机器不同进程产生的ObjectId 是唯一的。后3 字节就是一个自动增加的计数器,确保相同进程同一秒产生的ObjectId 也是不一样的。同一秒钟最多允许每个进程拥有2563(16 777 216)个不同的ObjectId。
【6】其他一些方案:比如京东淘宝等电商的订单号生成。因为订单号和用户id 在业务上的区别,订单号尽可能要多些冗余的业务信息,比如:滴滴:时间+起点编号+车牌号 淘宝订单:时间戳+用户ID 其他电商:时间戳+下单渠道+用户ID,有的会加上订单第一个商品的ID。而用户ID,则要求含义简单明了,包含注册渠道即可,尽量短。

三、设计一个秒杀系统,30分钟没付款就自动关闭交易


秒杀架构设计理念】:限流: 鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。
削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。
异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。
内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。
可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了。像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。
设计思路】:将请求拦截在系统上游,降低下游压力:秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。
充分利用缓存:利用缓存可极大提高系统读写速度。
消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。
前端方案:页面静态化:将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。
禁止重复提交用户提交之后按钮置灰,禁止重复提交。
用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流。
后端方案】:服务端控制器层(网关层):限制uid(UserID)访问频率:我们上面拦截了浏览器访问的请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。
服务层】:上面只拦截了一部分访问请求,当秒杀的用户量很大时,即使每个用户只有一个请求,到服务层的请求数量还是很大。比如我们有100W用户同时抢100台手机,服务层并发请求压力至少为100W。
采用消息队列缓存请求:既然服务层知道库存只有100台手机,那完全没有必要把100W个请求都传递到数据库啊,那么可以先把这些请求都写到消息队列缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。
利用缓存应对读请求:对类似于12306等购票业务,是典型的读多写少业务,大部分请求是查询请求,所以可以利用缓存分担数据库压力。
利用缓存应对写请求:缓存也是可以应对写请求的,比如我们就可以把数据库中的库存数据转移到Redis缓存中,所有减库存操作都在Redis中进行,然后再通过后台进程把Redis中的用户秒杀请求同步到数据库中。
数据库层数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。
30分钟没付款就自动关闭交易:要看你取消订单后需不需要恢复库存了,不需要的话可以插入个结束时间来做标识,如果需要恢复库存的话可使用 swoole 里面的毫秒定时器 swoole_timer_after 来实现,如果使用的是 laravel 框架的话也可以使用延时队列来实现。我们公司在页面上会有倒计时刷新,其实也是通过页面定时器(setTiemout、setInterval)定时向后台发送请求。当超时后会进行订单状态的修改,达到自动关闭。

四、如何使用 Redis 和 Zookeeper 实现分布式锁?有什么区别优缺点,会有什么问题,分别适用什么场景。(延伸:如果知道redlock,讲讲他的算法实现,争议在哪里)


Redis实现分布式锁思路基于Redis实现分布式锁(setnx)setnx也可以存入key,如果存入 key成功返回1,如果存入的 key已经存在了,返回0。
Zookeeper实现分布式锁思路基于Zookeeper实现分布式锁 Zookeeper是一个分布式协调工具,在分布式解决方案中。多个客户端(jvm),同时在 zookeeper 上创建相同的一个临时节点,因为临时节点路径是保证唯一,只要谁能够创建节点成功,谁就能够获取到锁,没有创建成功节点,就会进行等待,当释放锁的时候,采用事件通知给客户端重新获取锁的资源。
Redis实现分布式锁与Zookeeper实现分布式锁区别:相同点:在集群环境下,保证只允许有一个 jvm进行执行。
不同点:Redis 是nosql数据,主要特点缓存; Zookeeper是分布式协调工具,主要用于分布式解决方案。
实现思路:主要通过获取锁、释放锁、死锁三方面进行说明:
【1】获取锁Zookeeper:多个客户端(jvm),会在 Zookeeper上创建同一个临时节点,因为 Zookeeper节点命名路径保证唯一,不允许出现重复,只要谁能够先创建成功,谁能够获取到锁。
Redis:多个客户端(jvm),会在Redis使用setnx命令创建相同的一个key,因为Redis的key保证唯一,不允许出现重复,只要谁能够先创建成功,谁能够获取到锁。
【2】释放锁Zookeeper:使用直接关闭临时节点 session 会话连接,因为临时节点生命周期与 session 会话绑定在一块,如果 session 会话连接关闭的话,该临时节点也会被删除。这时候客户端使用事件监听,如果该临时节点被删除的话,重新进入盗获取锁的步骤。
Redis:在释放锁的时候,为了确保是锁的一致性问题,在删除的 redis 的 key 时候,需要判断同一个锁的 id,才可以删除。
【3】共同特征如何解决死锁现象问题:Zookeeper:使用会话有效期方式解决死锁现象。Redis:是对 key 设置有效期解决死锁现象。
【4】性能角度考虑因为 Redis 是 NoSQL 数据库,相对比来说 Redis 比 Zookeeper 性能要好。
【5】可靠性从可靠性角度分析,Zookeeper可靠性比Redis更好。因为Redis有效期不是很好控制,可能会产生有效期延迟;Zookeeper 就不一样,因为 Zookeeper 临时节点先天性可控的有效期,所以相对来说 Zookeeper 比 Redis 更好。

五、如果有人恶意创建非法连接,怎么解决

通过Filter进行拦截处理。


六、分布式事务的原理,优缺点,如何使用分布式事务,2PC 3PC 的区别,解决了哪些问题,还有哪些问题没解决,如何解决,你自己项目里涉及到分布式事务是怎么处理的


分布式事物的原理:从广义上来看,分布式事务其实也是事务,只是由于业务上的定义以及微服务架构设计的问题,所以需要在多个服务之间保证业务的事务性,也就是 ACID 四个特性;从单机的数据库事务变成分布式事务时,原有单机中相对可靠的方法调用以及进程间通信方式已经没有办法使用,同时由于网络通信经常是不稳定的,所以服务之间信息的传递会出现障碍。
Java面试——架构设计与分布式_第3张图片
模块(或服务)之间通信方式的改变是造成分布式事务复杂的最主要原因,在同一个事务之间的执行多段代码会因为网络的不稳定造成各种奇怪的问题,当我们通过网络请求其他服务的接口时,往往会得到三种结果:正确、失败和超时,无论是成功还是失败,我们都能得到唯一确定的结果,超时代表请求的发起者不能确定接受者是否成功处理了请求,这也是造成诸多问题的诱因。
Java面试——架构设计与分布式_第4张图片
系统之间的通信可靠性从单一系统中的可靠变成了微服务架构之间的不可靠,分布式事务其实就是在不可靠的通信下实现事务的特性。无论是事务还是分布式事务实现原子性都无法避免对持久存储的依赖,事务使用磁盘上的日志记录执行的过程以及上文,这样无论是需要回滚还是补偿都可以通过日志追溯,而分布式事务也会依赖数据库、Zookeeper 或者 ETCD 等服务追踪事务的执行过程,总而言之,各种形式的日志是保证事务几大特性的重要手段。
2PC与3PC:两阶段提交是一种使分布式系统中所有节点在进行事务提交时保持一致性而设计的一种协议;在一个分布式系统中,所有的节点虽然都可以知道自己执行操作后的状态,但是无法知道其他节点执行操作的状态,在一个事务跨越多个系统时,就需要引入一个作为协调者的组件来统一掌控全部的节点并指示这些节点是否把操作结果进行真正的提交,想要在分布式系统中实现一致性的其他协议都是在两阶段提交的基础上做的改进。
Java面试——架构设计与分布式_第5张图片
两阶段提交的执行过程就跟它的名字一样分为两个阶段,投票阶段 提交阶段,在投票阶段中,协调者(Coordinator)会向事务的参与者(Cohort)询问是否可以执行操作的请求,并等待其他参与者的响应,参与者会执行相对应的事务操作并记录重做和回滚日志,所有执行成功的参与者会向协调者发送 AGREEMENT 或者 ABORT 表示执行操作的结果。
Java面试——架构设计与分布式_第6张图片
当所有的参与者都返回了确定的结果(同意或者终止)时,两阶段提交就进入了提交阶段,协调者会根据投票阶段的返回情况向所有的参与者发送提交或者回滚的指令。
Java面试——架构设计与分布式_第7张图片

当事务的所有参与者都决定提交事务时,协调者会向参与者发送 COMMIT 请求,参与者在完成操作并释放资源之后向协调者返回完成消息,协调者在收到所有参与者的完成消息时会结束整个事务;与之相反,当有参与者决定 ABORT 当前事务时,协调者会向事务的参与者发送回滚请求,参与者会根据之前执行操作时的回滚日志对操作进行回滚并向协调者发送完成的消息,在提交阶段,无论当前事务被提交还是回滚,所有的资源都会被释放并且事务也一定会结束。

两阶段提交协议是一个阻塞协议,也就是说在两阶段提交的执行过程中,除此之外,如果事务的执行过程中协调者永久宕机,事务的一部分参与者将永远无法完成事务,它们会等待协调者发送 COMMIT 或者 ROLLBACK 消息,甚至会出现多个参与者状态不一致的问题。
Java面试——架构设计与分布式_第8张图片

3PC 为了解决两阶段提交在协议的一些问题,三阶段提交引入了 超时机制 准备阶段,如果协调者或者参与者在规定的时间内没有接受到来自其他节点的响应,就会根据当前的状态选择提交或者终止整个事务,准备阶段的引入其实让事务的参与者有了除回滚之外的其他选择。
Java面试——架构设计与分布式_第9张图片
当参与者向协调者发送 ACK 后,如果长时间没有得到协调者的响应,在默认情况下,参与者会自动将超时的事务进行提交,不会像两阶段提交中被阻塞住;上述的图片非常清楚地说明了在不同阶段,协调者或者参与者的超时会造成什么样的行为。

七、什么是一致性 hash


一致性Hash算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性Hash算法是对2^32取模,什么意思呢?简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下:
Java面试——架构设计与分布式_第10张图片

整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1, 0和2^32-1在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环。

下一步将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置,这里假设将上文中四台服务器使用IP地址哈希后在环空间的位置如下:
Java面试——架构设计与分布式_第11张图片

接下来使用如下算法定位数据访问到相应服务器:将数据key使用相同的函数 Hash 计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器!

例如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:
Java面试——架构设计与分布式_第12张图片
根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

八、什么是 Restful,讲讲你理解的 Restful


九、如何设计一个良好的API


十、如何设计建立和保持100w的长连接


十一、解释什么是MESI协议(缓存一致性)


十二、说说你知道的几种HASH算法,简单的也可以


十三、什么是paxos算法, 什么是zab协议


十四、一个在线文档系统,文档可以被编辑,如何防止多人同时对同一份文档进行编辑更新


十五、线上系统突然变得异常缓慢,你如何查找问题


十六、说说你平时用到的设计模式


十七、Dubbo的原理,有看过源码么,数据怎么流转的,怎么实现集群,负载均衡,服务注册和发现,重试转发,快速失败的策略是怎样的


十八、一次RPC请求的流程是什么


十九、自己实现过rpc么,原理可以简单讲讲。Rpc要解决什么问题


二十、异步模式的用途和意义


二十一、编程中自己都怎么考虑一些设计原则的,比如开闭原则,以及在工作中的应用


二十二、设计一个社交网站中的“私信”功能,要求高并发、可扩展等等。 画一下架构图


二十三、MVC模式,即常见的MVC框架


二十四、聊下曾经参与设计的服务器架构并画图,谈谈遇到的问题,怎么解决的


二十五、应用服务器怎么监控性能,各种方式的区别


二十六、如何设计一套高并发支付方案,架构如何设计


二十七、如何实现负载均衡,有哪些算法可以实现


二十八、Zookeeper的用途,选举的原理是什么


二十九、Zookeeper watch机制原理


三十、Mybatis的底层实现原理


三十一、请思考一个方案,实现分布式环境下的countDownLatch


三十二、后台系统怎么防止请求重复提交


三十三、描述一个服务从发布到被消费的详细过程


三十四、讲讲你理解的服务治理


三十五、如何做到接口的幂等性


三十六、如何做限流策略,令牌桶和漏斗算法的使用场景


三十七、什么叫数据一致性,你怎么理解数据一致性


三十八、分布式服务调用方,不依赖服务提供方的话,怎么处理服务方挂掉后,大量无效资源请求的浪费,如果只是服务提供方吞吐不高的时候该怎么做,如果服务挂了,那么一会重启,该怎么做到最小的资源浪费,流量半开的实现机制是什么


三十九、dubbo的泛化调用怎么实现的,如果是你,你会怎么做


四十、远程调用会有超时现象,如果做到优雅的控制,JDK自带的超时机制有哪些,怎么实现的



----关注公众号,获取更多内容----

你可能感兴趣的:(面试)