Java面试 (六) | 技术组件专题

Scroll Down

前言
这篇来讲解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不会
      立即删除

image.png

  • 解决办法
    • 提高消费者速率,例如消费者集群
    • 消费者批量获取消息、减少网络传输次数
  • 同一个组中,消息不会重复消费

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