架构设计与分布式
1.常见的缓存策略有哪些,你们项目中用到了什么缓存系统,如何设计的。
redis缓存,ehcache缓存
2.分布式集群下如何做到唯一序列号。
Redis生成,zk生成,只要保证原子性即可。
3.设计一个秒杀系统,30 分钟没付款就自动关闭交易。
秒杀系统设计理念
限流:只有少部分消费者能真正传达到后台服务
削峰:使用队列让流量均匀地进入系统,降低对系统的冲击
异步处理:异步返回结果
可用性:尽最大程度地保证高可用。
用户体验:消费者点击抢购按钮后,无论是否能抢到商品,期望是能得到及时的反馈。
自动关闭交易使用Redis的发布订阅机制,在失效后进行后续操作。
4.如何使用 redis 和 zookeeper 实现分布式锁?有什么区别优缺点,分别适用什么场景。
redis 适合性能要求高的场景,缺点是存放于内存,宕机后锁丢失。
zk 可以有效的解决锁无法释放的问题,创建锁时,客户端会在 zk 创建一个临时节点,一旦客户端挂掉了,那这个临时节点就会自动删除,其他客户端可以再次获得锁。
zk 可以默认实现 阻塞锁
和 非阻塞锁
,但 Redis 默认能实现 非阻塞锁
,需要 阻塞锁
需要自己改造
5.如果有人恶意创建非法连接,怎么解决。
使用过滤器处理
6.分布式事务的原理,优缺点,如何使用分布式事务。
分布式事务通常分为两种:
-
TCC
两阶段补偿型 (TCC)
-
主业务活动请求 (
try
) 各个从业务服务预留资源。try
过程的本地事务,是保证资源预留的业务逻辑的正确性。 -
如果在第一阶段所有业务资源都预留成功,那么
confirm
各个从业务服务,否则取消(cancel
)所有从业务服务的资源预留请求。
-
-
2PC/3PC
三阶段提交 (3PC)
-
协调者:接收事务请求并把
canCommit
发送给参与者参与者:向协调者发送Yes消息并切换到
prepared
状态 -
协调者:接收所有参与者的Yes消息,向所有参与者发送
preCommit
消息并切换到prepared
状态参与者:收到
preCommit
消息,它将发送ACK
消息并等待最后的提交或中止。 -
协调者:在收到来自大多数参与者的确认的情况下,协调者切换到
commit
状态。并向所有参与者发送doCommit
请求。参与者:参与者接收到
doCommit
请求之后,执行正式的事务提交,并发送ack
给协调者
-
参考文章:https://www.cnblogs.com/dennyzhangdd/p/10580446.html#_label11_2
7.什么是一致性 hash。
8.如何设计建立和保持 100w 的长连接。
服务器内核调优(tcp,文件数),客户端调优,框架选择(netty)
9.什么是 paxos 算法。
10.什么是 zab 协议。
ZAB 是 Zookeeper 原子广播协议的简称,Zookeeper 是通过 Zab 协议来保证分布式事务的最终一致性。
- Zab协议原理
- 发现
Discovery
- 同步
Synchronization
- 广播
Broadcast
-
Zab协议内容
Zab 协议包括两种基本的模式:崩溃恢复 和 消息广播
协议过程
当整个集群启动过程中,或者当 Leader 服务器出现网络中弄断、崩溃退出或重启等异常时,Zab协议就会 进入崩溃恢复模式,选举产生新的Leader。
当选举产生了新的 Leader,同时集群中有过半的机器与该 Leader 服务器完成了状态同步(即数据同步)之后,Zab协议就会退出崩溃恢复模式,进入消息广播模式。
这时,如果有一台遵守Zab协议的服务器加入集群,因为此时集群中已经存在一个Leader服务器在广播消息,那么该新加入的服务器自动进入恢复模式:找到Leader服务器,并且完成数据同步。同步完成后,作为新的Follower一起参与到消息广播流程中。
协议状态切换
当Leader出现崩溃退出或者机器重启,亦或是集群中不存在超过半数的服务器与Leader保存正常通信,Zab就会再一次进入崩溃恢复,发起新一轮Leader选举并实现数据同步。同步完成后又会进入消息广播模式,接收事务请求。
保证消息有序
在整个消息广播中,Leader会将每一个事务请求转换成对应的 proposal 来进行广播,并且在广播 事务Proposal 之前,Leader服务器会首先为这个事务Proposal分配一个全局单递增的唯一ID,称之为事务ID(即zxid),由于Zab协议需要保证每一个消息的严格的顺序关系,因此必须将每一个proposal按照其zxid的先后顺序进行排序和处理。
参考文章:https://www.jianshu.com/p/2bceacd60b8a
11.说说你平时用到的设计模式。
-
策略模式
public class StrategyUse { public static void main(String[] args) { Strategy strategy = new Strategy(new WeiXinPay()); PayInfo payinfo = strategy.payForSometh(); System.out.println(payinfo.getPayType()); //微信 } }
-
单例模式
- 饿汉式
private final static Singleton INSTANCE = new Singleton(); private Singleton(){} public static Singleton getInstance(){ return INSTANCE; }
- 普通的懒汉式 (线程不安全,不可用)
private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }
- 同步方法的懒汉式 (可用)
private static Singleton instance = null; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }
- 双重检查懒汉式 (可用,推荐)
private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }
-
代理模式
//代理类 public class BuyHouseProxy implements BuyHouse { private BuyHouse buyHouse; public BuyHouseProxy(final BuyHouse buyHouse) { this.buyHouse = buyHouse; } @Override public void buyHosue() { System.out.println("买房前准备"); buyHouse.buyHosue(); System.out.println("买房后装修"); } } //测试类 public class ProxyTest { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); buyHouse.buyHosue(); BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse); buyHouseProxy.buyHosue(); } }
-
模板模式
//抽象做菜父类 public abstract class DodishTemplate { /** * 具体的整个过程 */ protected void dodish(){ this.preparation(); this.doing(); this.carriedDishes(); } /** * 备料 */ public abstract void preparation(); /** * 做菜 */ public abstract void doing(); /** * 上菜 */ public abstract void carriedDishes (); } //西红柿炒蛋 public class EggsWithTomato extends DodishTemplate{ @Override public void preparation() { System.out.println("洗并切西红柿,打鸡蛋。"); } @Override public void doing() { System.out.println("鸡蛋倒入锅里,然后倒入西红柿一起炒。"); } @Override public void carriedDishes() { System.out.println("将炒好的西红寺鸡蛋装入碟子里,端给客人吃。"); } } //测试类 public class App { public static void main(String[] args) { DodishTemplate eggsWithTomato = new EggsWithTomato(); eggsWithTomato.dodish(); } }
12.Dubbo 的原理,数据怎么流转的,怎么实现集群,负载均衡,服务注册和发现。重试转发,快速失败的策略是怎样的。
Dubbo 的原理
- 初始化过程细节 把服务装载到容器中,然后注册服务,类似Spring启动过程一样。
- 服务的提供方会向注册中心注册自己提供的服务。
- 消费者在启动时,就会向注册中心订阅自己所需要的服务。
- 如果服务提供方有数据变更等,注册中心将基于长连接的形式推送变更数据给消费者。
数据怎么流转的
怎么实现集群
使用Cluster 实现集群
dubbo根据注册中心获取服务信息,在通过集群负载均衡策略后获取服务信息。服务集群需要注意application name需要一致。
负载均衡
Random LoadBalance:随机,按权重比率设置随机概率。
RoundRobin LoadBalance:轮循,按公约后的权重比率设置轮循比率。
LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance:一致性Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
重试转发,快速失败的策略
容错机制分为6种
传播属性 | 描述 |
---|---|
Failover Cluster(默认) | 失败自动切换,当出现失败,重试其它服务器 |
Failfast Cluster | 快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。 |
Failsafe Cluster | 失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。 |
Failback Cluster | 失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。 |
Forking Cluster | 并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。 |
Broadcast Cluster | 广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。 |
在提供者中,reties的值设置在@Service中
在消费者中,reties的值设置在@Reference中
其中可以设置timeout进行超时重试
13.一次 RPC 请求的流程是什么。
- 服务消费方调用服务
- 消费方接收到调用后把方法和参数组装成网路传输消息体
- 通过注册中心找到服务地址,并把消息发送到服务端
- 服务提供方收到消息后进行解码
- 服务提供方根据解码结果调用本地方法
- 本地方法把结果返回给服务提供方,并打包发送回消费方
- 消费方收到消息进行解码
14.聊了下曾经参与设计的服务器架构。
15.应用服务器怎么监控性能,各种方式的区别。
Prometheus监控,使用exporter做数据指标的采集,grafana展示,后面会单独做一个部署的教程。
16.如何设计一套高并发支付方案,架构如何设计。
- 防止重复提交、支付
- 防止用户同一商品购买两次
- 支付过程中防止订单交易状态过期
- 预热购物信息
- 把支付过程改为异步,加入请求队列,降低服务器压力
17.如何实现负载均衡,有哪些算法可以实现。
SpringCloud的Ribbon,还有dubbo的。
Ribbon:https://www.cnblogs.com/nicori/p/11672030.html
dubbo:问题12有解答。
18.Zookeeper 的用途,选举的原理是什么。
zk本质上是分布式的小文件存储系统,是一个分层的文件系统目录树结构,每个节点可以存储少量数据(1M左右),每个节点叫ZNode,通过路径作为唯一标识。
- 分布式锁服务
- 配置管理
19.Mybatis 的底层实现原理。
https://www.cnblogs.com/nicori/p/13533576.html
20.请思考一个方案,实现分布式环境下的 countDownLatch。
基于Redisson的分布式锁 RCountDownLatch
可以实现类似 countDownLatch
的效果
21.后台系统怎么防止请求重复提交。
https://my.oschina.net/huangweiindex/blog/1843927