说一下,项目中那些场景使用了redis
缓存穿透,击穿,雪崩
缓存击穿
添加一个分布式锁,只能有一个线程拿到锁
和钱相关必须强一致选互斥锁
逻辑过期重要是高可用,不保证数据的一致性
双写一致
Mysql的数据如何与redis进行同步(双写一致)
两种方案要根据项目来选
第一种延时双删
先删除缓存,还没有更新数据库20这个时候有另外一个数据进来,查询缓存没有查到,就去数据库里查到之前的数据10
先操作数据,线程2还没有更新数据库20,这个时候线程1查询数据10,写入缓存10,线程2更新数据20,导致数据不一致出现脏数据
两种 情况都会导致脏数据
所以数据修改之后再删除一次缓存,为什么要延时,数据库可能是主从节点,需要延时一会让数据从主节点复制到从节点
延时双删的时间不好控制还是可能会导致脏数据
第二种方案 使用读写锁
读的时候使用共享锁可以读不能写
写的时候使用排他锁,会阻塞其他线程读和写的操作
相比分布式锁性能高一点
可以保证强一致,但是性能低
异步通知保证数据的最终一致性
redis的持久化
第一种方式 RDB
推荐使用子进程,这样不会影响其他命令
在linux中所有的主进程都无法直接操作物理内存,由操作系统给每个主进程分配一个虚拟内存,操作系统会维护一下虚拟内存和物理内存中间的映射关系表(页表),主进程通过页表对物理内存进行读操作
fork是克隆,fork子进程就是把主进程的页面复制过去,这样就和主进程有了相同的映射关系,这样就实现了主进程和子进程内存空间的共享这样就无需拷贝内存中的数据了,直接实现内存共享,这样子进程就可以写新的RDB文件。
怎么避免在写文件的时候有新的写操作导致数据不一致,fork采用copy-on-write技术,有写操作,就把数据拷贝,把数据写进去,读的数据对应的映射也会改变
第二种 AOF
会把无效的命令重写,最大的节省命令行数
reids的过期策略
reids数据淘汰策略
redis内存使用完之后会报错out of memory,中止服务,读操作可以,写操作不行
分布式锁
给锁续期:一开始给锁设置了过期时间然后再开另外一个线程来看业务到底执行了多久,如果执行时间长就增加持有锁的时长
这种就需要使用到redisson
使用redisson,watchdog会续期
抢不到锁的线程会尝试等待
加锁和设置过期时间等操作都是基于lua脚本的,lua脚本可以调用linux命令来保证多条命令执行的原子性
当设置了过期时间30之后watchdog就没有了,redisson认为你可以自己控制时间就不给你续期了
10是while循环的时间
redis实现的分布式锁不能重入
redisson实现的分布式锁可重入(同一个线程内,不同线程就是互斥了)
没有使用红锁的话,当一个服务挂了之后,同一个锁,可能就被不同的线程拿到了
Redis是单线程为什么还这么快
IO多路复用就是用来监听多个客户端的连接
Mysql
sql优化
Mysql中如何定位慢查询
表数据量大,可以添加索引,怎么看索引是否失效呢可以通过EXPLAIN
PRIMARY是主键
如果Extra 是using index condition 表示索引还有优化的空间
索引
1.写sql创建
sql范本:create index 索引名称 on 表名(字段名);
sql示例:create index index_user_name on PROMULGATE_CERT(user_name);
没有索引的时候,查找age是45的人,sql执行会从第一行一个一个找,找到最后一行
B+树特点,非叶子节点不存储数据只存储指针,这些指针是为了方便找到数据,只在叶子节点保存数据
主键索引是聚族索引
1 是主键索引也是聚族索引,可以从索引中一次查询出所有的数据
索引创建的原则
索引失效
name status address 是有顺序的查询要从最左边开始
key 和key_len 是null 索引已经失效了
最下面的这个key_len是303跟只查询name时候的key_len是一样都是303
表示只命中了name的索引,查询的时候后面的address是跳过status的,没有命中
Sql的优化经验
选择合适的数值可以减少存储的成本提高查询的效率
Mysql 事务
加钱和减钱的操作要么成功要么失败
并发事务带来的问题
串行话效率很低一般是不会用的
主库负责写数据,从库负责读数据,主库写数据之后要把数据同步到从库
Spring
spring 单例bean是线程安全的吗
AOP
事务就是使用的aop
项目中使用AOP,记录日志,
spring 中事务失效的场景
spring 的bean的生命周期
spring中的循环依赖
SpringMVC的执行流程
springboot自动配置原理
spring中常见的注解
mybatis执行流程
Mybatis的一级二级缓存
二级缓存默认是关的,开启之后,同一个线程内两个sqlSessionFactory查一个sql,只会连接数据库查询一次
Spring Cloud
服务降级针对的是某个接口,服务熔断针对的是整个服务
微服务是怎么监控的
一般shywalking来监控
项目中怎么做限流的
tomcat在单体项目中可以,微服务就不行了
公司压测之后业务的qps是1200
CAP和BASE
比如提交订单,提交多次也只能有一个订单
使用token和redids,在点击购买的时候去获取token,然后返回一个token,有了token之后请求业务接口提交订单的页面,验证token存在之后删除token,其他请求进来没有token就打不开提交订单的页面
使用分布式锁保证只有一个线程可以拿到锁进行业务的操作
项目中使用的分布式任务调度
消息中间件
生产者发生消息到交换机,交换机把消息路由到队列,然后消费者消费消息
消息未到达交换机怎么解决
消息未到达对列怎么解决
消费者未收到消息
RabbitMq消息重复消费的问题如何解决
当消费者消费完消息,这个时候消费挂了,确认的消息还没有回给生产者,因为有超时重试机制,消费者会再次消费消息,导致重复消费的问题。
每个消息设置一个唯一id,我们消费的时候去数据库看如果没有这个id就正常消费,如果有了就不再消费这个消息了
消息堆积怎么解决
集合
算法复杂度分析
来评估代码的执行耗时的
3n+3 前一个三是系数,第二个三是常量,这两个三都不能反映变化趋势所以可以省略
不管底数是2还是10复杂度都是logn
List相关
多线程
线程的基础
线程中并发安全
加锁之后使用monitorenter上锁
把这段代码锁住,等解锁之后其他代码才能执行这段代码,第二次解锁是怕出现异常之后也能解锁
JMM
AQS
RentrantLock
导致并发程序出现问题的根本原因
原子性保证一段代码要么全部执行完成,要么全部执行失败
内存可见性可以使用三种方案解决,但是volatile的方法效率高
线程池的核心参数
线程池的种类有哪些
异步线程:打印平台,请求进来保存json请求报文使用异步线程
常常用于限流
ThreadLocal
JVM
什么是程序计数器
JAVA堆
元空间就是方法区
程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;
Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息;
本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;
Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;
方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
Java1.8把方法区和永久代放到了本地内存的元空间,因为元空间中保存类信息和静态变量,随着代码加载这些类信息不可控,放在堆空间中容易内存溢出,为了避免OOM所以优化之后放在了本地内存
虚拟机栈
方法区
1.7以前是在堆中的永久代保存类的信息
1.8以后移到了本地内存中的方法区(元空间)
类加载器
bootstrap classloader 启动类加载器
string一直委派到启动类加载器,启动类加载器可以加载这个类,则由启动类加载器加载
stutdent类 委派到启动类加载器也没有被加载那么应用类加载器就会加载这个类
类装载的执行过程
垃圾回收
对象什么时候可以被垃圾回收器回收
demo指向一个对象,ref就是1,表面被引用了一次
如果 string demo = null; 那么ref就是0,表示可以被回收
垃圾回收算法有哪些
先标记存活的对象,然后清除其他的对象
jvm中的分代回收
当新生代和老年代内存严重不足的时候才会产生FullGC
JVM有哪些垃圾回收器
GC root是可达性算法标记哪些对象是存活的
软引用GC root先能找到softReference对象(软引用对象),user对象是一个软引用,进行垃圾回收之后如果内存不足再次触发垃圾回收就会回收user对象
JVM实践
JVM调优的参数在哪里设置参数
JVM调优的参数有哪些
JVM 调优工具
Java内存泄漏的排查思路
一些大的对象一直存活,垃圾回收器一直没有回收就会导致堆空间内存泄漏
CPU飙高排查方案和思路
设计模式
冒号后面是方法的返回值
这样实现耦合比较严重,更换对象的时候new的对象也都要更换
要实现开闭原则:扩展开放,对修改关闭
简单工厂模式
工厂方法模式
简单工厂又产生了新的耦合后期如果有新的产品还是要修改simplecoffefactory类
具体产品
抽象工厂
具体工厂
抽象工厂模式
策略模式
登录案例 工厂加策略模式
原来的登录方式不符合开闭原则
使用工厂和策略模式
让spring管理这些策略对象
在工厂类中
拿到配置文件中的值,放到map中
继承的applicationcontexAware接口,就会实现setApplicationContext方法,拿到applicationcontext对象,拿到配置文件
前面的account不能随便写,要和前端写的type对应,后面的accountGranter也不能随便写,要根据这个在spring中找到对应spring管理的类
责任链设计模式
setNext是设置下一条执行的顺序
在client中设置链条执行的顺序
这是责任链中的最后一个方法不用调用下一个执行的方法
复杂的流程审批会使用工作流来实现
常见的技术场景
单点登录
权限认证
上传数据的时候安全性怎么考虑?
项目中遇到的问题
一开始写的代码没有使用设计模式,后来需要经常更改代码,很不方便,后来我使用工厂模式和策略模式重构代码解决了这个问题
线上bug,线下测试不方便复现,项目上线一个月之后
日志的采集
怎么在linux中查看日志
QPS是每秒查询率