架构设计与分布式

1 常见的缓存策略有哪些,你们项目中用到了什么缓存系统,如何设计的。 redis缓存,ehcache缓存2 分布式集群下如何做到唯一序列号。 Redis生成,

1.常见的缓存策略有哪些,你们项目中用到了什么缓存系统,如何设计的。

redis缓存,ehcache缓存


2.分布式集群下如何做到唯一序列号。

Redis生成,zk生成,只要保证原子性即可。


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

秒杀系统设计理念

限流:只有少部分消费者能真正传达到后台服务
削峰:使用队列让流量均匀地进入系统,降低对系统的冲击
异步处理:异步返回结果
可用性:尽最大程度地保证高可用。
用户体验:消费者点击抢购按钮后,无论是否能抢到商品,期望是能得到及时的反馈。

自动关闭交易使用Redis的发布订阅机制,在失效后进行后续操作。


4.如何使用 redis 和 zookeeper 实现分布式锁?有什么区别优缺点,分别适用什么场景。

redis 适合性能要求高的场景,缺点是存放于内存,宕机后锁丢失。

zk 可以有效的解决锁无法释放的问题,创建锁时,客户端会在 zk 创建一个临时节点,一旦客户端挂掉了,那这个临时节点就会自动删除,其他客户端可以再次获得锁。

zk 可以默认实现 阻塞锁非阻塞锁 ,但 Redis 默认能实现 非阻塞锁 ,需要 阻塞锁 需要自己改造


5.如果有人恶意创建非法连接,怎么解决。

使用过滤器处理


6.分布式事务的原理,优缺点,如何使用分布式事务。

分布式事务通常分为两种:

  • TCC

    两阶段补偿型 (TCC)

    1. 主业务活动请求 ( try ) 各个从业务服务预留资源。 try 过程的本地事务,是保证资源预留的业务逻辑的正确性。

    2. 如果在第一阶段所有业务资源都预留成功,那么 confirm 各个从业务服务,否则取消( cancel )所有从业务服务的资源预留请求。

  • 2PC/3PC

    三阶段提交 (3PC)

    1. 协调者:接收事务请求并把 canCommit 发送给参与者

      参与者:向协调者发送Yes消息并切换到 prepared 状态

    2. 协调者:接收所有参与者的Yes消息,向所有参与者发送 preCommit 消息并切换到 prepared 状态

      参与者:收到 preCommit 消息,它将发送 ACK 消息并等待最后的提交或中止。

    3. 协调者:在收到来自大多数参与者的确认的情况下,协调者切换到 commit 状态。并向所有参与者发送 doCommit 请求。

      参与者:参与者接收到 doCommit 请求之后,执行正式的事务提交,并发送 ack 给协调者

参考文章:https://www.cnblogs.com/dennyzhangdd/p/10580446.html


7.什么是一致性 hash。


8.如何设计建立和保持 100w 的长连接。

服务器内核调优(tcp,文件数),客户端调优,框架选择(netty)


9.什么是 paxos 算法。


10.什么是 zab 协议。

ZAB 是 Zookeeper 原子广播协议的简称,Zookeeper 是通过 Zab 协议来保证分布式事务的最终一致性。

  1. Zab协议原理
  • 发现 Discovery
  • 同步 Synchronization
  • 广播 Broadcast
  1. 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.说说你平时用到的设计模式。

  1. 策略模式

    public class StrategyUse {
        public static void main(String[] args) {
            Strategy strategy = new Strategy(new WeiXinPay());
            PayInfo payinfo = strategy.payForSometh();
            System.out.println(payinfo.getPayType());
            //微信
        }
    }
    
  2. 单例模式

    1. 饿汉式
    private final static Singleton INSTANCE = new Singleton();
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        return INSTANCE;
    }
    
    1. 普通的懒汉式 (线程不安全,不可用)
    private static Singleton instance = null;
    
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    
    1. 同步方法的懒汉式 (可用)
    private static Singleton instance = null;
    
    private Singleton() {
    }
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    
    1. 双重检查懒汉式 (可用,推荐)
    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;
    }
    
  3. 代理模式

    //代理类
    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();
        }
    }
    
  4. 模板模式

    //抽象做菜父类
    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 的原理

  1. 初始化过程细节 把服务装载到容器中,然后注册服务,类似Spring启动过程一样。
  2. 服务的提供方会向注册中心注册自己提供的服务。
  3. 消费者在启动时,就会向注册中心订阅自己所需要的服务。
  4. 如果服务提供方有数据变更等,注册中心将基于长连接的形式推送变更数据给消费者。

数据怎么流转的


怎么实现集群

使用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 请求的流程是什么。

  1. 服务消费方调用服务
  2. 消费方接收到调用后把方法和参数组装成网路传输消息体
  3. 通过注册中心找到服务地址,并把消息发送到服务端
  4. 服务提供方收到消息后进行解码
  5. 服务提供方根据解码结果调用本地方法
  6. 本地方法把结果返回给服务提供方,并打包发送回消费方
  7. 消费方收到消息进行解码

14.聊了下曾经参与设计的服务器架构。


15.应用服务器怎么监控性能,各种方式的区别。

Prometheus监控,使用exporter做数据指标的采集,grafana展示,后面会单独做一个部署的教程。


16.如何设计一套高并发支付方案,架构如何设计。

  1. 防止重复提交、支付
  2. 防止用户同一商品购买两次
  3. 支付过程中防止订单交易状态过期
  4. 预热购物信息
  5. 把支付过程改为异步,加入请求队列,降低服务器压力


17.如何实现负载均衡,有哪些算法可以实现。

SpringCloud的Ribbon,还有dubbo的。
Ribbon:https://www.cnblogs.com/nicori/p/11672030.html
dubbo:问题12有解答。


18.Zookeeper 的用途,选举的原理是什么。

zk本质上是分布式的小文件存储系统,是一个分层的文件系统目录树结构,每个节点可以存储少量数据(1M左右),每个节点叫ZNode,通过路径作为唯一标识。

  1. 分布式锁服务
  2. 配置管理

19.Mybatis 的底层实现原理。

https://www.cnblogs.com/nicori/p/13533576.html


20.请思考一个方案,实现分布式环境下的 countDownLatch。

基于Redisson的分布式锁 RCountDownLatch 可以实现类似 countDownLatch 的效果


21.后台系统怎么防止请求重复提交。

https://my.oschina.net/huangweiindex/blog/1843927


22.讲讲你理解的服务治理。


23.如何做到接口的幂等性。