悲观锁:多线程同时修改共享资源的概率比较高,于是容易出现冲突,所以访问共享资源前,先要上锁
乐观锁:先修改完共享资源,再验证这段时间内有没有发生冲突,如果没有其他线程在修改资源,那么操作完成,如果发现有其他线程已经修改过这个资源,就放弃本次操作
虚拟内存解决的问题
第一个程序在一个位置写入一个新的值,将会擦掉第二个程序存放在相同位置上的所有内容,同时运行两个程序根本行不通
虚拟内存 将不同的虚拟地址和不同的物理地址映射起来
内存分段:段基地址+段内偏移量=物理内存地址
内存分页:把整个虚拟和物理内存空间切成一段段固定尺寸的大小,一个连续且固定的内存空间,叫页
进程间通信
管道传输数据是单向的,如果相互通信,我们需要创建两个管道才行
管道就是内核里面的一串缓存,从管道里的一段写入的数据,实际上是缓存在内核中的,另一端读取,从内核中读取这段数据,管道传输的数据是无格式的流且大小受限
消息队列:是保存在内核中的消息链表,不适合比较大数据的传输,消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销
共享内存:拿出一块虚拟地址空间,映射到相同的物理内存中
信号量:信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,通过P操作会使得信号量减去1 V操作会使信号量加1
先更新数据库,再删除缓存
更新数据库成功后,会产生一条变更日志,记录在binlog里,订阅这个binlog日志,拿到具体要操作的数据,再执行缓存删除。
canal模拟mysql主从复制的交互协议,把自己伪装成一个mysql的从节点,向mysql主节点发送dump请求,mysql收到请求后,就会开始推送binlog给canal,canal解析binlog字节流之后,转换为读取的结构化数据,供下游程序订阅使用
Minor GC:只针对年轻代进行回收,包括Eden区和两个Survivor区,发生非常频繁,年轻代对象的生命周期较短,回收效率高,暂停时间较短
Major GC:主要针对老年代进行回收,但不一定只是回收老年代,当老年代空间不足时,或者系统监测到年轻代对象晋升到老年代的速度过快,可能会触发major gc
Full GC:对整个堆内存进行回收
BIO NIO AIO区别
BIO:同步阻塞
NIO:同步非阻塞 读写动作完成之前,线程会一直阻塞在那里
AIO:异步非阻塞 基于事件和回调机制实现的,应用操作会直接返回,不会堵塞再那里,当后台处理完成后,操作系统会通知相应的线程进行后续的操作
NIO是一种同步非阻塞的IO模型,Channel(通道) Buffer(缓冲区) Selector(选择器)
Selector 选择区 用于监听多个通道的事件,单个线程可以监听多个数据通道
Redis分布式锁的缺点
set lock value nx ex 10
超时时间不好设置,锁的超时时间设置过长,会影响性能,如果设置的超时时间过短会保护不到共享资源
redission解决:加锁后,通过watch dog看门狗,每隔releaseTime/3的时间做一次续期
跳表
查找一个跳表节点的过程时,跳表就会从头结点的最高层开始,逐一遍历每一层,在遍历某一层的跳表节点时,会用跳表节点中的SDS类型的元素和元素的权重来进行判断
如果当前节点的权重小于要查找的权重,跳表就会访问该层上的下一个节点
如果当前节点的权重等于要查找的权重时,并且当前节点的SDS类型数据小于要查找的数据时,跳表就会访问该层上的下一个节点
get和post区别
get的语义是从服务器获取指定的资源,这个资源可以是静态的文本,页面等
post语义是根据请求负荷对指定的资源做出处理
get方法是安全且幂等的,因为他是只读操作,无论操作多少次,服务器上的数据都是安全的,且每次的结果都是相同的
post方法是新增/提交数据的操作,会修改服务器的资源,所以是不安全的,且多次提交数据就会创建多个资源,所以不是幂等的。
MQTT协议
是一种基于发布/订阅模式的轻量级通讯协议,通过订阅相应的主题来获取消息,是互联网中的一个标准传输协议
Qos等级
Qos 0(最多一次):消息发送后不进行确认,也不重试,是最低的服务质量等级,这种方式可能会导致消息丢失,但传输效率最高
Qos 1(至少一次):确保消息至少被送达一次,如果发送方没有收到确认,他可能重试发送消息
这可能导致消息重复
Qos 2(恰好一次):保证消息准确无误地送达一次,不丢失也不重复,是最高的服务质量等级
布隆过滤器原理
布隆过滤器由初始值都为0的位图数组和N个哈希函数两部分组成,当我们在写入数据库数据时,在布隆过滤器做个标记,这样下次查询数据是否在数据库时,只需要查询布隆过滤器,如果查询到数据没有被标记,说明不在数据库中
索引下推
能够减少二级索引在查询时的回表操作,提高查询的效率,因为他将server层部分负责的事情交给存储引擎层去处理了
工厂模式 通用代码
//抽象的产品
public abstract class Product{
public abstract void method();
}
//定义一个具体的产品
class ProductA extends Product{
@Override
public void method(){}//具体的执行逻辑
}
//抽象的工厂
abstract class Factory<T>{
abstract Product createProduct(Class<T>c);
}
//具体的工厂可以生产出相应的产品
class FactoryA extends Factory{
@Override
Product createProduct(Class c){
Product product=(Product) Class.forName(c.getName()).newInstance();
return product;
}
}
SQL深分页
通过普通二级索引树idx_update_time 过滤update_time条件,找到满足条件的记录ID
通过ID,回到主键索引数,找到满足记录的行,然后取出展示的列
扫描满足条件的100010行,然后扔掉前100000行,返回
sql
//优化前
select id,name,balance from account where update_time>'2024-12-30' limit 10000,10;
//优化后
select id,name,balance FROM account where id >= (select a.id from account a where a.update_time >= '2024-12-30' limit 100000, 1) LIMIT 10;
Redis内存淘汰策略
1.不进行数据淘汰的策略
2.随机淘汰了设置过期时间的任意键值
3.优先淘汰更早过期的键值
4.淘汰所有设置了过期时间的键值中,最久未使用的键值
5.淘汰所有设置了过期时间的键值中,最少使用的键值
如何保证Redis和Mysql数据缓存一致性问题
对于读数据,我会选旁路缓存策略,如果cache不命中,会从db加载数据到cache。对于写数据,我们会选择更新db后,再删除缓存。
两阶段提交的过程
在MySql的InnoDB存储引擎中,开启binlog的情况下,MySQL会同时维护binlog日志与InnoDB的redo log,为了保证这两个日志的一致性。
事务的提交过程有两个阶段,将redo log的写入拆成prepare和commit,中间再穿插写入binlog
prepare阶段:将XID(内部XA事务的ID)写入到redo log,同时将redo log对应的事务状态设置为prepare,然后将redo log持久化到磁盘
commit阶段:把binlog持久化到磁盘上,接着调用引擎的提交事务接口,将redo log状态设置为commit