Q:进程与线程
A:区别&联系:线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信
号等),某进程内的线程在其他进程不可见;调度和切换:线程上下文切换比进程上下文切换要快得多;通信方式差异::进程间通信:管道通信;信号量;消息队列;信号;共享内存;套接字;线程间通信:锁机制:包括互斥锁、条件变量、读写锁;信号量机制;信号机制;
Q:Redis为什么快?为什么单线程?
A:快----数据库的工作模式按存储方式可分为:硬盘数据库和内存数据库。Redis 将数据储存在内存里面,读写数据的时候都不会受到硬盘 I/O 速度的限制,所以速度极快;1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;4、使用多路I/O复用模型,非阻塞IO;5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;单线程-----官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!);Redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。
Q:缓存穿透、缓存击穿、缓存雪崩和解决方案
A:缓存穿透:缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据,导致数据库压力过大
解决方案:接口层增加校验;key-value对写为key-null,缓存有效时间可以设置短点,如30秒
缓存击穿:缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:设置热点数据永远不过期;加互斥锁,100ms休眠
缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,给后端系统(比如DB)带来很大压力
解决方案:设置热点数据永远不过期;缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生;分布式下均匀分布;DB加锁排队
Q:JVM分代回收方式以及各种回收算法
A:很完整的一篇文章: JVM分代回收机制和垃圾回收算法_羽毛的博客-CSDN博客_jvm分代回收
Q:NoSql和关系型数据库的区别,优势
A:见下文:关系型数据库与非关系型数据库Nosql区别汇总_渴望飞的鱼的博客-CSDN博客_nosql和关系型数据库的区别
Q:事务ACID,隔离级别
A:原子性(atomicity):事务包含的所有操作要么全部成功,要么全部失败回滚--->undolog(回滚日志,当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子)
一致性(consistency):事务必须使数据库从一个一致性状态----> 另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
隔离性(isolation):隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离----->(锁机制、MVCC),隐藏列:InnoDB中每行数据都有隐藏列,隐藏列中包含了本行数据的事务id、指向undo log的指针;基于undo log的版本链;ReadView快照
持久性(durability):事务一旦提交,它对数据库的改变就应该是永久性的,接下来的其他操作或故障不应该对其有任何影响;Mysql中,为了解决CPU和磁盘速度不一致问题,Mysql是将磁盘上的数据加载到内存,对内存进行操作,然后再回写磁盘,如果中间出现断电,那么久有可能没有将数据写入---->redo log(redo log被引入解决buffer pool丢失问题:当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作;当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求)
隔离级别相关问题:
脏读:A读取B事务尚未提交的事务,并修改了B的数据,然后B对事务执行回滚,那么A读取到的数据为脏读
不可重复读:事务A读取数据,然后事务B对事务A的数据进行了修改,此后,事务A再次读取数据,这时为不可重复读,最后A提交事务。所以在A的一次事务中,两次读取到的数据不一致
幻读:事务A查询数据,查询一切符合查询条件的行,这时B新增加一个行数据,A事务再次查询时,发现与第一次查询相比,新增加了一行
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read-uncommitted | √ | √ | √ |
读已提交(read-committed) | × | √ | √ |
可重复读(repeatable-read) | × | × | √ |
串行化(serializable) | × | × | × |
深入学习MySQL事务:ACID特性的实现原理 - 编程迷思 - 博客园
Q:SQL优化方案
A:SQL语言 - SQL语句优化 | Java 全栈知识体系
- 负向查询不能使用索引
- 前导模糊查询不能使用索引
- 数据区分不明显的不建议创建索引
- 字段的默认值不要为 null
- 在字段上进行计算不能命中索引
- 最左前缀问题
- 如果明确知道只有一条记录返回
- 不要让数据库帮我们做强制类型转换
- 如果需要进行 join 的字段两表的字段类型要相同
MySQL Explain详解 - 杰克思勒(Jacksile) - 博客园
Q:分布式锁
A:基于数据库组合唯一约束的排他锁;基于Redis,setIfAbsent(k,v),最后再删除,可能会出现宕机,无法释放锁的情况;见文章:三种实现分布式锁的方式_vincent-CSDN博客_分布式锁
Q:消息中间件的应用场景
A:应用解耦:如,一个服务调用多个服务的业务场景,只需要推送,而不关心结果,不关心其他服务的处理情况,使用消息中间件,由其他服务主动订阅处理,降低服务之间的耦合性;流量削峰:大量请求进行同一接口调用,导致超过后端承载能力上限,可以将请求丢入消息中间件,在后端最大处理能力内限制消费中间件消息;日志处理:ELK+Kafka-----aop日志--->kafka topic--->logstash--->elasticsearch存储--->kibana连接索引访问;分布式事务:聊聊分布式事务,再说说解决方案 - Savorboard - 博客园
Q:内存溢出和内存泄漏;内存泄漏、内存溢出的多种场景
A:内存溢出:程序申请内存时,没有足够的内存供申请者使用,场景:内存中加载的数据量过于庞大,如一次从数据库取出过多数据;集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;代码中存在死循环或循环产生过多重复的对象实体;使用的第三方软件中的BUG;启动参数设定的过小。。。。。内存泄漏:程序在申请内存后,无法释放已申请的内存空间,场景:大量使用static变量;资源未关闭导致内存泄漏;hashcode数据结构产生的内存泄漏;