前言
这篇来讲解java各种各样组件,例如数据库mysql、缓存redis、分布式搜索等等的题目
一、redis篇
1、redis和ehcache区别
答:1.ehcache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。2.redis可缓存共享、分布式部署,可持久化
2、redis应用场景
答:1.热点数据。2.计数器。3.排行榜。4.分布式锁。5.队列。6.点赞。7.token令牌。8.延时操作
3、为啥效率那么高
答::1.完全基于内存,持久化。
2.单线程。
3.redis使用多路复用技术。
4.基于跳跃表数据增删改,效率高
4、redis线程安全吗?为啥效率那么高?
答:采用NIO多路复用,一个线程处理多个请求,线程安全类似无锁机制
5、redis分为多少个库,为啥有这么多个
答:16个库,没个库不准许出现相同key,不同业务连接同一个redis,所以区分
6、redis五种类型:
答:1.String(常规key-value缓存应用,最大512M。常规计数: 微博数, 粉丝数。)
2.List(双向链表,字符串列表。最新消息排行,消息队列)
3.Hash(键值(key => value)对集合。场景:存储部分变更数据,如用户信息、存储、读取、修改用户属性等。)
4.set(string类型的无序集合。场景:共同好友、交集)
5.zset(sorted set:有序集合。场景:1.排行榜 2.带权重的消息队列)
7、redis如何存放数据
答:1.基于json序列化。2.基于String二进制存放对象
8、mysql和redis保证数据唯一性
答:1.手动清除缓存。2.订阅mysql的binlog日志通过MQ推送
9、全量和增量区别
答:1.全量:每天定时对所有数据数据同步。2.增量:发生操作同步数据,效率低,低延迟
10、内存满了如何处理?
答:1.扩展内存,治标不治本。2.采用redis淘汰机制。3.设置过期key
11、redis宕机会丢失?
答:不会,因为会持久化
12、redis持久化有哪些方案?
答:RDB增量同步。存放文件格式,恢复速度快。AOF增量同步,日志存放
13、redis支持回滚吗?
答:没有回滚。mysql开启事务,其他线程不能做写操作,回滚相当于对该行锁释放。redis开启对key的事务,其他线程还是可以对key做操作
14、redis主从复制
答:单台redis情况下,如果redis宕机会导致数据丢失,故使用复制备份数据
多台分为主从关系,请求会转发主节点。在同步到每子字节点负责读,哨兵会重启节点,单机要手动
15、redis主从实现
答:1.数据备份。2.集群。3.读写分离
16、redis分布式锁思路
答:采用setn。2.redis框架
17、redis的set和setnx区别
setnx可以返回key是否存在。存在返回0,不能修改,不存在返回1
18、分布式锁超时如何处理
答:1.续时。2.回滚当前事务,同时释放锁
19、redis缓存穿透,缓存穿击、缓存雪崩原因及解决方案
答:缓存穿透
缓存穿击
缓存雪崩
二、Mysql
2.1、Mysql数据库优化层面
- 1、需求优化(需求无用功能,不合理。论坛实时更新)
- 2、系统架构(二进制多媒体功能、流水、活跃缓存数据)
- 3、SQL以及索引
- 4、数据库表结构(表规范、分表分库)
- 5、系统配置优化(Tcp连接、打开文件限制、安全性优化)
- 6、硬件(IO、CPU、网络)
2.2、SQL查询慢如何优化
- 1、慢查询日志是否打开
set global slow_query_log=on;
- 2、检查慢日志路径
show variables like '%slow_query_log%';
- 3、慢日志判断标准(默认大于10秒)
show variables like 'slong_query_time';
2.3、Explain执行计划
id | select_type | table | partitions | type | possible_keys | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|
越大越先执行 | 表示查询的类型,什么语句 | 查询的表 | 匹配的分区 | 表的连接类型 | 可能使用索引 | 实际使用索引 | 索引长度 | 列与索引比较 | 估算的行数 | 条件过滤的百分比 |
2.4、慢查询优化思路
- 优化更需要优化的SQL
- 了解性能瓶颈
- 明确优化目标
- explan执行计划
- 小结果集驱动大结果集
- 尽可能在索引中完成排序
- *禁用所有列查询,使用需要的列
- 只使用最有效的过滤条件
- *尽可能避免使用复杂的join和子查询
- 尽可能使用三张以内表
- 小心使用order by、group by、distinct函数
- **合理使用索引
2.5、索引种类
- B-tree索引(mysql中最频繁的索引类型)
- B树:三个节点,三次IO,键值、指针、数据组合
- B+树:1、数据全部在第三节点。2、第三节点双向
- Hash索引(检索效率高于B-tree索引,可以一次定位)
- Fulltext索引(目前仅支持char、varchar、text)
- R-tree索引(少见,主要用于空间数据检索)
2.6、什么时候需要创建索引
- 字段查询比较频繁
- 字段更改不是很频繁
- where里面的字段才可以创建索引
2.7、索引失效与优化
- 复合索引尽量写全
- 最佳前缀法则(中间索引不能断)
- 不要在索引上做任何操作(计算、函数等)
- mysql存储引擎不能继续使用索引中范围条件(bettween、in等)右边列
- 尽量使用覆盖索引(只查询索引的列)
- is null 或者 is not nul也会失效
- !=或 > <判断时,也会失效
- like通配符也会失效
- 索引字段是字符串,查询时候不加单引号也会失效
- or也会导致失效
2.8、优化终极奥义
- 针对百万数据,放弃join操作。推荐分别根据索引单表取数据,然后在java代码里面join、merge操作
- 解决IO问题,读IO尽量使用nosql来防控热点数据。写IO使用消息中间件来抗压
- 解决读IO、热点数据存放redis读IO,从而减轻数据库物理压力
- 解决写IO、使用消息队列慢慢依次对mysql进行写操作
- 拓展:多级缓存、redis集群、mq、tomcat、mysql集群
一个单节点(1服务器、1数据库)不可能使系统达到百万级别
mysql最多曾在3500-4500QPS
2.9、其他优化
- 不能在数据库做运算,运算务必移到业务层
- 数据库命名简洁明了(长度不能超过30字符)
- 控制列数量(字段少而精、字段数控制20个以内)
- 平衡范式与冗余(效率优先,往往牺牲范式)
- 拒接3B(拒接大sql语句、大事物、大批量)
- 合理数值类型(合适的字段节省空间)
- 字符转化数字(例如类型、节省空间、性能)
- 避免NULL字段(NULL难查询优化、NULL字段索引需要额外空间、复合索引失效)
- 少用text类型(尽量varchar)
- 合理使用索引(改善查询、减慢更新)
- 字符字段建立前缀索引
- innodb主键推荐自增列(字符串不应该做主键、不用外键)
- sql尽量简单(一条sql只能在一个cpu运算,大语句拆小语句,减少锁时间,一条大sql可以堵死整个数据库)
- 简单事物(最好不要有事物)
- 避免trig/func(不用触发器、函数、客户端程序代替取而代之)
2.10、常见面试题
- 1、mylSAM和InnoDb区别
1、InnoDb支持事物
2、InnoDb支持外键
3、InnoDb是聚集索引,使用B+Tree作为索引结构。MyISAM是非聚集索引
4、MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,所以查询速度很快
5、InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
6、InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键)
7、Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI
- Innodb:frm是表定义文件,ibd是数据文件
- Myisam:frm是表定义文件,myd是数据文件,myi是索引文件
- 2、为啥InnoDb引擎表必须有主键、并且推荐整数自增方式
如果不是自增id,例如uuid。此时你将不能够范围查询
- 3、云数据库如何定位慢查询
- 4、执行计划EXPLAIN如何使用
- 5、EXPLAIN Type需要达到什么级别
- rang
ALL:全表扫描
index:全表扫描索引数、接近ALL
range:检索范围查询
ref:表示上述表的连接匹配条件、就是那些列、常量用于查询索引列上的值
eq_ref:主键或者唯一索引关联查询、最多只返回一条符合条件记录。
const:对查询某部分进行优化,并转换为一个常量
NULL
- 6、mysql索引为什么遵循最佳左前缀法则
查询条件尽量用 联合索引前面的列,这样就可以走索引树
- 7、mysql索引为什么需要避免回表查询
因为索引树上找不到需要的内容,需要借用主键ID再回表查询第二次(利用复合索引)
- 8、超过多少张表需要禁止join
- 9、为啥阿里巴巴需要禁止存储过程
- 10、一张表达到多少级别需要分库分表
三、rabbitMq篇
3.1、项目那些场景运用到MQ
执行比较耗时的代码操作,交给mq异步实现接口
- 异步发送优惠券
- 异步发送短信
- 异步扣除库存
3.2、为什么使用MQ
- 异步处理(多线程和MQ)【耗时程序移步异步处理】
- 实现解耦
- 流量削峰(抗高并发)
3.3、MQ与多线程实现异步区别
- 多线程实现异步请求可能会消耗cpu资源,频繁上下文切换,从而影响业务线程会发生cpu竞争问题
- MQ异步是解耦,适合大型互联网项目
- 小项目可以使用多线程实现异步,大项目建议MQ实现
3.4、MQ如何避免消息堆积问题
- 背景
- 生产者投递速率与消费者速率完全不匹配
- 注意
- rabbitmq消息被消费立即删除。kafka和rocketMq不会
立即删除
- rabbitmq消息被消费立即删除。kafka和rocketMq不会
- 解决办法
- 提高消费者速率,例如消费者集群
- 消费者批量获取消息、减少网络传输次数
- 同一个组中,消息不会重复消费
3.5、如何保证消息不丢失
- MQ服务器端【消息持久化到硬盘】
- 生产者【ACK响应状态投递 确保我们消息投递到MQ】
- 消费者【消费者确认消息消费成功,rabbitmq会删除信息】
3.6、生产投递服务器宕机如何处理
使用一个redis或者mysql保存msg记录,如果发生失败,使用定时器根据日志补偿投递。
3.7、如何保证MQ顺序一致性
- 背景:
MQ集群或者MQ分区存放消息,每个分区对应一个消费者 - 解决:
同一类消息投递到同一个MQ、同一分区、被同一消费者消费 - 实现:
根据消息key%分区模型总数投递到同一分区
3.8、如何保证MQ消息幂等性问题
- 背景:
消费失败、重复消费 - 解决:
- 间隔重复执行消费
- 业务方面保证幂等性,不被重复执行
- 设置全局id,消费前先查询是否已经执行
- 数据库层:设置唯一约束、乐观锁
3.9、MQ与Redis如何保证一致性
- 解决:
- 删除redis缓存,可能会出现延迟双删。适合小项目
- 基于MQ异步处理。update数据–〉MQ发送消息–〉消费–〉redis
- 订阅binlog。update数据–〉cannal订阅binlog–〉cannal客户端解析成json–〉发送到kafka–〉消费消息–〉redis