记录一次面试经历

第一轮:

类加载
  • 子父类加载顺序
    Fu 静态代码块 static{}
    Zi 静态代码块
    FU 构造代码块 {}
    Fu 构造器…
    zi 构造代码块…
    Zi 构造器…

    静态代码块实现单例模式:

    public class StaticInnerSingleton {
        private StaticInnerSingleton() {
            if (SingletonHolder.instance != null) {
                throw new IllegalStateException();
            }
        }
        private static class SingletonHolder {
            private static StaticInnerSingleton instance = new StaticInnerSingleton();
        }
        public static StaticInnerSingleton getInstance() {
            return SingletonHolder.instance;
        }
    }
    

    优势:

  • 兼顾了懒汉模式的内存优化(使用时才初始化)以及饿汉模式的安全性(不会被反射入侵)。

多线程:
  • 启动一个线种的几种方式:

    • 继承Thread 重写run()
    • 声明实现Runnable接口的类 重写run()
    • 实现Callable接口,重写call()方法有执行完返回值
  • synchronized修饰静态方法时,它表示锁定class对象;修饰普通方法时,表示锁定当前对象(this)。

    • 释放该锁只有两种情况
    • 一是,获取锁的线程执行完了该代码块,然后线程释放对锁的占有。
    • 二是,线程执行发生异常,此时JVM会让线程自动释放锁。
  • Lock接口和和synchronized的区别:

    • Lock不是java语言内置的,synchronized关键字是java语言内置特性,通过Lock类可以实现同步访问
    • Lock需要代码手动释放锁,而synchronized会在代码块执行完之后,自动释放锁。
  • ReentrantLock是Lock的实现类 ReentrantLock的意思是可重入锁 ReentrantLock默认是一种公平锁

    • lock() 拿到锁
    • unlock() 释放锁
    • tryLock() 试着拿锁 true拿到了,false 未拿到
    • interruptibly() 可中断的锁(如果是在等待拿锁的过程中,可以被其他线程终止拿锁)Thread的interup()方法,对锁进行中断。
  • ReadWriteLock 接口下的类ReetrantReadWriteLock

    • writeLock().lock() 写锁
    • readLock().lock() 读锁
  • 悲观锁与乐观锁:

    • synchronized就是悲观锁,是一种独占锁
    • 偏向锁,轻量锁,自旋锁,锁消除,锁粗化
  • 死锁:

    • synchronized死锁

      public SyncThread(Object o1, Object o2){
              this.obj1=o1;
              this.obj2=o2;
          }
          @Override
          public void run() throws Exception{  //两个线程同时调此方法,t1(o1,02) t2(o2,o1)
              synchronized (obj1) {
                  Thread.sleep(1000);
                  synchronized (obj2) {
                      Thread.sleep(1000);
                  }
            }
          }
      
  • wait 和sleep 方法的区别:

    ​ wait()方法是Object提供,需要在synchronized同步代码块中才能使用,调用wait ()后线程将会释放锁,而等待其他线程调用 notify()方法随机唤醒,唤醒后,等待拿锁。

    ​ sleep()方法是线程对象Thread的静态方法,调用后,并不会释放锁资源 。等待时间自动解锁。

  • 线程池:Executors

    • 阿里开发手册:【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,
      这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

    • 创建几种线程池的方式

    • SpringBoot 整合线程池:

       @Configuration
          @EnableAsync
          public class TaskPoolConfig {
              @Bean("taskExecutor")
              public Executor taskExecutror(){
                  ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
                  taskExecutor.setCorePoolSize(50);
                  taskExecutor.setMaxPoolSize(100);
                  taskExecutor.setQueueCapacity(10000);
                  taskExecutor.setKeepAliveSeconds(60);
                  taskExecutor.setThreadNamePrefix("basicIaskExecutor--");
                  taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
                  taskExecutor.setAwaitTerminationSeconds(60);
                  return taskExecutor;
              }
          }
      
  • CompletableFuture 实现异步编排。

    创建异步任务:

     // 无返回值
     public static CompletableFuture runAsync(Runnable runnable);         
     public static CompletableFuture runAsync(Runnable runnable, Executor executor);
     //有返回值
     public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
     public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
    

    计算完成时对结果的处理

     //成功的回调:执行完的结果作为参数。 是否异步,是否使用线程池
        //结果为T  Throwable 为异常
        public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
        public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action);
        public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
    
    //异常的回调 T为有异常的返回值
    public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn);
    
    //执行完之后(无论成功失败)后续处理
    public <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn);
    public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn);
    public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor);
    
    //串行化
    //对前一个线程的返回值进行处理
    public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
    public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn);
    public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor);
    
    //需要前一个线程的返回值
    public CompletableStage<void> thenAccept(Consumer<? super T> action);
    public CompletableStage<void> thenAcceptAsync(Consumer<? super T> action);
    public CompletableStage<void> thenAcceptAsync(Consumer<? super T> action,Executor executor);
    
    //不需要前一个线程的返回值
    public CompletableFuture<void> thenRun(Runnable action);
    public CompletableFuture<void> thenRunAsync(Runnable action);
    public CompletableFuture<void> thenRunAsync(Runnable action,Executor executor);
    

     //编排
      thenCombine(...)  组合两个future,获取两个future的返回值,执行第当前future然后返回
      thenAcceptBoth(... ) 组合两个future,获取两个future的返回值,执行第当前future
      runAfterBoth(... )  组合两个future,并执行当前future无返回值
    

     //全部执行完,或者某一个执行完
      public static completableFuture<void> allOf(CompletableFuture<void> ... csf);
      public static completableFuture<void> anyOf(CompletableFuture<void> ... csf);
    
  • 消息队列

    • BlockingQueue接口也是java.util.concurrent下的主要用来控制线程同步的工具

    • boolean add() 加入队列 能容纳 true,不能,抛异常

    • boolean offer() 加入队列 能容纳 true,不能容纳 false

    • put() 加入队列能存则存,不能存等有空间了再存

    • pull(time)取走里排在首位的对象,若不能立即取出则等time指定的时间,取不到返回null

    • take()阻塞方法,有则取出 ,无则等

    • int remainingCapacity()返回队列剩余容量

    • boolean remove()从队列中移除某个元素

    • 实现类:ArrayBlockingQueue:一个由数组支持的有界阻塞队列

    • 实现类:LinkedBlockingQueue:大小不一定的BlockingQueue可以指定也可以不指定大小

JVM的回收机制

https://www.cnblogs.com/laoqing/p/8 583583.html

  • 按代的垃圾回收机制
    新生代(Young generation):绝大多数最新被创建的对象都会被分配到这里,由于大部分在创建后很快变得不可达,很多对象被创建在新生代,然后“消失”。对象从这个区域“消失”的过程我们称之为:Minor GC 。
    老年代(Old generation):对象没有变得不可达,并且从新生代周期中存活了下来,会被拷贝到这里。其区域分配的空间要比新生代多。也正由于其相对大的空间,发生在老年代的GC次数要比新生代少得多。对象从老年代中消失的过程,称之为:Major GC 或者 Full GC。
    持久代(Permanent generation)也称之为 方法区(Method area):用于保存类常量以及字符串常量。注意,这个区域不是用于存储那些从老年代存活下来的对象,这个区域也可能发生GC。发生在这个区域的GC事件也被算为 Major GC 。
  • 默认的新生代(Young generation)、老年代(Old generation)所占空间比例为 1 : 2 。
  • 新生代空间的构成与逻辑
    为了更好的理解GC,我们来学习新生代的构成,它用来保存那些第一次被创建的对象,它被分成三个空间:
    一个伊甸园空间(Eden)
    两个幸存者空间(Fron Survivor、To Survivor)
    默认新生代空间的分配:Eden : Fron : To = 8 : 1 : 1
    每个空间的执行顺序如下:
    1、绝大多数刚刚被创建的对象会存放在伊甸园空间(Eden)。
    2、在伊甸园空间执行第一次GC(Minor GC)之后,存活的对象被移动到其中一个幸存者空间(Survivor)。
    3、此后,每次伊甸园空间执行GC后,存活的对象会被堆积在同一个幸存者空间。
    4、当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。然后会清空已经饱和的哪个幸存者空间。
    5、在以上步骤中重复N次(N = MaxTenuringThreshold(年龄阀值设定,默认15))依然存活的对象,就会被移动到老年代。
    从上面的步骤可以发现,两个幸存者空间,必须有一个是保持空的。如果两个两个幸存者空间都有数据,或两个空间都是空的,那一定是你的系统出现了某种错误。
    我们需要重点记住的是,对象在刚刚被创建之后,是保存在伊甸园空间的(Eden)。那些长期存活的对象会经由幸存者空间(Survivor)转存到老年代空间(Old generation)。
    也有例外出现,对于一些比较大的对象(需要分配一块比较大的连续内存空间)则直接进入到老年代。一般在Survivor 空间不足的情况下发生。
  • 老年代空间的构成与逻辑
    老年代空间的构成其实很简单,它不像新生代空间那样划分为几个区域,它只有一个区域,里面存储的对象并不像新生代空间绝大部分都是朝闻道,夕死矣。这里的对象几乎都是从Survivor 空间中熬过来的,它们绝不会轻易的狗带。因此,Full GC(Major GC)发生的次数不会有Minor GC 那么频繁,并且做一次Major GC 的时间比Minor GC 要更长(约10倍)。
简述堆栈
  • 都是java在内存中存放数据的地方,程序员不能直接地设置堆或者栈
堆栈的不同点
速度
生存周期与数据大小动态分配确定
存放内容包装类型: Integer, String, Double基本数据类型,部分String
是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量.所有基本类型和引用类型的引用都在栈中存储.栈中数据的生存空间一般在当前scopes内(就是由{…}括起来的区域).
设计模式:动态代理
算法:快速排序 的实现
集合
两种区别HashMapConcurrentHashMap
底层Entry数组+链表Segment数组+链表
默认大小16(16)*2
加载因子0.750.75
扩容方式Entry数组数组扩容Segment内部扩容(数组默认16,只能初始化定义不支持扩展)
线程安全Segment本身是线程安全的继承 ReentrantLock
读写数度
Spring ioc 、事务
  • 什么是DI机制:依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者
  • IOC容器:就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。。在Spring中BeanFactory是IOC容器的实际代表者。
  • 给IOC容器中注册组件:
    • 1, 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[适合自己写的类]
    • 2,@Configuration@Bean[导入第三方包里的组件]
    • 3,@Configuration@Import[快速给窗口中注册一个组件]
      • @Import[快速给窗口中导入一个组件]
      • ImportSelector:返回需要导入的组件的全类名数组
      • ImportBeanDefinitionRegistrar
    • 使用Spring 提供的FactoryBean(工厂Bean)
  • 注入方式:构造器,set方法
  • AOP原理:
    • 面向切面编程(aop)是对面向对象编程(oop)的补充, 面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程中的步骤进行抽象,,从而获得步骤之间的逻辑划分。
  • AOP 面向切面编程
    • 将业务逻辑组件和切面类都加入到容器中,告诉Spring 哪个是切面 类(@Aspect)
    • 在切面 类上的每一个通知方法上标注通知注解,告诉Spring何时 何地运行(切入点表达式)。
    • 配置文件开启aop模式,或者配置类@EnableAspectJAutoProxy
  • 声明式事物:
    • @Configuration类 @EableTransactionManagerment
    • 注册事务管理器在容器中 (引用数据源)
SpringMVC
  • (1)客户端通过url发送请求
    (2-3)核心控制器Dispatcher Servlet接收到请求,通过系统或自定义的映射器配置找到对应的handler,并将url映射的控制器controller返回给核心控制器。
     (4)通过核心控制器找到系统或默认的适配器
     (5-7)由找到的适配器,调用实现对应接口的处理器,并将结果返回给适配器,结果中包含数据模型和视图对象,再由适配器返回给核心控制器

    (8-9)核心控制器将获取的数据和视图结合的对象传递给视图解析器,获取解析得到的结果,并由视图解析器响应给核心控制器

    (10)核心控制器将结果返回给客户端

Dubbo 原理
SpingBoot
  • 1、首先 SpringBoot可以快速一键快速搭建Spring框架,简化初始配置 ,可与主流框架集成
    2、内置Servlet容器,无需在打War包
    3、使用了Starter(启动器)管理依赖并版本控制
    4、大量的自动配置,简化开发,方便集成第三方
    5、提供准生产环境运行时的监控,如指标,健康,外部配置等
    6、无需配置,推荐使用yml.
SpringCloud:
  • Eureka 服务发现与注册
  • Ribbon 客户端负载均衡
  • Hystrix 断路器 熔断器
  • Zuul 服务网关
  • Config 分布式配置文件管理
索引:

​ 索引的数据结构:

  1. 使用 B+tree 、Hash 的数据结构 。

  2. 其它数据结构的特点:

    • 二叉树:如果是有序新增,会有单边增长的风险。

    • 红黑树:有节点太长的风险。

    • HASH:hash索引 无法满足范围查找和LIKE查询。

    • Btree:

      • B-TREE 每个节点都是一个二元数组: [key, data],所有节点都可以存储数据。key为索引key,data为除key之外的数据。
      • 检索原理:首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或未找到节点返回null指针。
      • 缺点:1.插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质。造成IO操作频繁。2.区间查找可能需要返回上层节点重复遍历,IO操作繁琐。
    • B+Tree: B-Tree的变种

      • 与B-Tree相比,B+Tree有以下不同点:非叶子节点不存储data,只存储索引key;只有叶子节点才存储data
      • Mysql中B+Tree:在经典B+Tree的基础上进行了优化,增加了顺序访问指针。在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。这样就提高了区间访问性能
  3. Btree 存储的索引失效问题。

    • 全值匹配
    • 最佳左前缀法则
    • 不在索引列上做任何操作
    • 存储引擎不能使用索引中范围右边的列
    • 尽量使用覆盖索引
    • mysql在使用不等于 != 、<>的时候无法匹配索引
    • is null、is not null也无法使用索引
    • like通配符开关%abc索引会失效
    • 字符串不加单引号
    • 少用or
MYSQL 主从复制 分表分库
  • 分区:

    1. rang 分区根据某个字段的范围来分区
    2. list 分区基于列值匹配一个离散值集合中的某个值来进行选择。
  • 分库分表:

    1. 按照业务拆分,把不同的业务放在不同的数据库
    2. 主从复制
    3. 分表,按照业务ID进行分表,垂直拆分与水平拆分
      • 垂直拆分,表字段过长,分为多个表
      • 数量量太大,按照业务分为多个表,理论上单表数据到500W
  • 主从复制:

    1. 原理:slave会从master读取binlog日志来进行数据同步
    2. 配置:my.cnf 配置文件 /etc/my.cnf,开启二进制日志,设置server-id=1
    3. 创建用户并授权:CREATE USER ‘repl’@‘123.57.44.85’ IDENTIFIED BY ‘slavepass’
    4. GRANT REPLICATION SLAVE ON . TO ‘repl’@‘123.57.44.85’;#分配权限
    5. flush privileges; #刷新权限
    6. 查看master状态 SHOW MASTER STATUS;记住file和position的值
    7. 从机:配置my.cnf 修改server-id=2 重启
    8. 从机:
      mysql> CHANGE MASTER TO
      -> MASTER_HOST=‘182.92.172.80’,
      -> MASTER_USER=‘rep1’,
      -> MASTER_PASSWORD=‘slavepass’,
      -> MASTER_LOG_FILE=‘mysql-bin.000003’,
      -> MASTER_LOG_POS=73;
    9. 查看从机状态:show slave status\G; 当Slave_IO_Running和Slave_SQL_Running都为YES的时候就表示主从同步设置成功了。
    10. 停止服务复制功能:stop slave;
MYSQL的引擎

数据库引擎及功能 ISAM MYISAM InnoDB Memory(HEAP)
读速度 快快 较快 相对较慢 最快
外键 是 是 是
支持索引 否 否 是
支持事务 否 否 是
支持容错 否 否 是
锁 表锁 行锁

一般来说,MyISAM适合:

(1)做很多count 的计算;

(2)插入不频繁,查询非常频繁;

(3)没有事务。

InnoDB适合:

(1)可靠性要求比较高,或者要求事务;

(2)支持聚集索引:索引中的数据物理存放地址和索引的顺序是一致的

(3)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况指定数据引擎的创建,让所有的灵活性成为可能的开关是提供给ANSI SQL的MySQL扩展——TYPE参数。MySQL能够让你在表格这一层指定数据库引擎,所以它们有时候也指的是table formats。下面的示例代码表明了如何创建分别使用MyISAM、ISAM和HEAP引擎的表格。要注意,创建每个表格的代码是相同的,除了最后的 TYPE参数,这一参数用来指定数据引擎。

  • 表锁与行锁
    1. 表锁:MYISAM引擎支持:查看
      • show status like ‘table%’:
      • table_locks_immediate 产生表锁的次数
      • table_locks_waited 出现表级锁定争用发生等待的次数
    2. 行锁:InnoDB :读已之所写。索引失效可能导致表锁
      • show status like ‘innodb_row_lock%’ :
      • innodb_row_lock_avg 平均等待时长
      • innodb_row_lock_waits 等待发生的次数
      • innodb_row_lock_time 等待总时长
  • InnoDB行锁升级表锁:1,类型转换 where id = ‘123’ 2,索引失效
事物的特性,与隔离级别
  • spring对事务的控制有:传播行为、隔离级别、是否只读、有回滚机制、事务超时

  • 事物的特性:ACID

    • 原子性:Atomicity 一件事做完,要不做,要么做完
    • 一致性:Consistency 事务的运行不改变数据库原本的一致性
    • 隔离性:Isolation 事务未提交,数据不会改变
    • 持久性:Durability 事务一旦提交后,即使宕机,也不会丢
  • 读数据的概念:

    1. 脏读(Dirty Reads):脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
    2. 不可重复读(Non-Repeatable Reads):不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
    3. 幻读(Phantom Reads):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
  • 隔离级别:

    • 隔离级别 一致性 脏读 不可重复读 幻读
      读未提交 最低级别不读取物理上损坏数据 是 是 是
      读已提交 语句级 否 是 是
      可重复读 事物级 否 否 是
      串行化 最高级别、事务级 否 否 否
    • 读未提交(Read Uncommitted):SELECT语句以非锁定方式被执行,所以有可能读到脏数据,隔离级别最低。
    • 读已提交(Read Committed):只能读取到已经提交的数据。即解决了脏读,但未解决不可重复读。
    • 可重复读(Repeated Read):在同一个事务内的查询都是事务开始时刻一致的,InnoDB的默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻读。
    • 串行话(Serializable):完全的串行化读,所有SELECT语句都被隐式的转换成SELECT … LOCK IN SHARE MODE,即读取使用表级共享锁,读写相互都会阻塞。隔离级别最高。
    • Mysql 四种都支持 默认可重复读
  • 传播行为:

    • PROPAGATION_REQUIRED 默认的,假如当前正要执行的事务不在另外一个事务里,那么就起一个新的事务
    • PROPAGATION_SUPPORTS 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
    • PROPAGATION_REQUIRES_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
Redis
  • Redis的优点:

    性能极高 – Redis能支持超过 100K+ 每秒的读写频率。

    丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

    原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

    丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

  • 持久化:

    RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

    AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

REDIS持久化的区别RDBAOF
对性能的影响
一致性
恢复速度

redis宕机以及开发建议:https://blog.fundebug.com/2018/09/21/redis_incident/

redis主从复制

  • 功能 命令
    查看主从状态 info replication
    认定一个主机,自己做从机 slaveof 192.168.152.128 6379 临时生效
    反客为主 slaveof no one
  • 原理以及步骤:
    1. 保存主节点信息
    2. 主从建立socket连接
    3. 发送ping命令
    4. 权限验证
    5. 同步数据集
    6. 命令持续复制
  • 主从复制方式:
    1. 一主二从:一台主机两台从机
    2. 薪火相传:一台主机下一台从机,从机下面又有一台从机
    3. 反客为主:当主机宕机时,从机使用slaveof no one 命令,自己当作主机
  • 哨兵模式:
    1. 自定义:/myredis目录下 sentinel.conf文件
    2. sentinel auth-pass mymaster 12345678 //sentinel连主节点的密码
    3. 启动哨兵:redis-sentinel /myredis/sentinel .conf 看日志

reids雪崩与击穿

  • redis雪崩:

    1. 数据同时过期:可以针对过期时间设定不同的值,固定值+随机值
    2. redis挂了:主从复制、本地缓存如:ehcache
  • redis缓存击穿:请求数据大量不命中

    1. 参数不合法,业务上过滤掉
    2. 第一次请求走数据库,然后再入缓存,第二次就可以走缓存了。
  • 双写不一致:

    1. 先更新数据库,再更新缓存
    2. 先删除缓存,再更新数据库
    3. 先更新数据库,再删除缓存 (推荐)
RabbitMQ

​ 概念:

  • Server:接收客户端的连接,实现AMQP实体服务。
  • Connection:连接,应用程序与Server的网络连接,TCP连接。
  • Channel:信道,消息读写等操作在信道中进行。客户端可以建立多个信道,每个信道代表一个会话任务。
  • Message:消息,应用程序和服务器之间传送的数据,消息可以非常简单,也可以很复杂。有Properties和Body组成。Properties为外包装,可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body就是消息体内容。
  • Virtual Host:虚拟主机,用于逻辑隔离。一个虚拟主机里面可以有若干个Exchange和Queue,同一个虚拟主机里面不能有相同名称的Exchange或Queue。
  • Exchange:交换器,接收消息,按照路由规则将消息路由到一个或者多个队列。如果路由不到,或者返回给生产者,或者直接丢弃。RabbitMQ常用的交换器常用类型有direct、topic、fanout、headers四种,后面详细介绍。
  • Binding:绑定,交换器和消息队列之间的虚拟连接,绑定中可以包含一个或者多个RoutingKey。
  • RoutingKey:路由键,生产者将消息发送给交换器的时候,会发送一个RoutingKey,用来指定路由规则,这样交换器就知道把消息发送到哪个队列。路由键通常为一个“.”分割的字符串,例如“com.rabbitmq”。
  • Queue:消息队列,用来保存消息,供消费者消费。

交换机类型:

  • Fanout Exchange

    扇出:会把所有发送到交换器的消息路由到所有绑定的队列中。优点是转发消息最快,性能最好。

  • Topic Exchange

    主题:该类型的交换器将所有发送到Topic Exchange的消息被转发到所有RoutingKey中指定的Topic的队列上面。

  • Direct Exchange

    Direct :该类型的交换器将所有发送到该交换器的消息被转发到RoutingKey指定的队列中,全值匹配。

  • Headers Exchange

    该类型的交换器不依赖路由规则来路由消息,而是根据消息内容中的headers属性进行匹配。headers类型交换器性能差,在实际中并不常用。

第二轮:

秒杀
  • 服务单一职责 、独立部署
    秒杀服务即使自己扛不住压力,也不影响其他功能正常运行。
  • 秒杀链接加密。
    防止恶意攻击,防止链接暴露,提前秒杀商品。
  • 库存预热、快速扣减。
    秒杀读多少写少,无需每次实时验证库存,我们库存预热放在redis中,信号量控制进来的请求。
  • 动静分离
    nginx做好动静分离,保证秒杀和商品详情页的动态请求才进入到后端的服务器的集群,使用CDN网络,分担本集群的压力。
  • 恶意请求拦截
    识别非法攻击请求,并进行拦截。
  • 流量错峰。
    使用各种手段,将流量分担到更大宽度的时间点,比如验证码、加入购物车等。
  • 限流 alibaba-sentinel、熔断、降级。
    前端限流加后端限流
    限制请求次数,限制总量,快速失败降级运行,熔断隔离防止雪崩。
  • 队列削峰
    一万个商品,每个1000件秒杀,双十一所有秒杀成功的请求,进入队列,慢慢创建订单,扣减库存。
  • 一句话总结 :缓存、异步、队排好
项目中有哪些比较难解决的问题,最后都是怎么解决的
分布式事务

​ SEATA:

  • ​ 概念:阿里巴巴开源的分布式事务框架。Seata目前的事务模式有AT,TCC,Saga三种模式,默认即是AT模式,AT本质上是2pc协议的一种实现,三种模式的不同后面文章再详细介绍。

  • TC:事务协调者

  • TM:事务管理者

  • RM:事务执行者

AT模式:2PC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值