Java开发面试题分享
求时,表示客户端不会再向服务端发送数据了,但是客户端可能还有数据没接收完,服务端还需要继续向客户端发送剩余的数据,当服务端也没数据发送给客户端时,服务端在发送断开请求,客户端进行确认即可,所以是4 次握⼿手。
3. 说说你知道的几种 HTTP 响应码,比如 200, 302, 404。
答:2**一般指请求成功, 例如 200 成功。
3**指重定向, 301 永久移动, 302 临时移动。
4**指请求错误, 404 未找到, 403 禁止。
5**指服务器异常, 500 服务器内部错误, 503 服务不可⽤。
七:架构设计与分布式
1. 分布式集群下如何做到唯一序列号。
答:uuid -> segment 获取号段方案 -> segment+双 *** -> snowflake。详细的说明可以查看美团技术公众号对应文章
2. 如何使用 redis 和 zookeeper 实现分布式锁?有什么区别优缺点,会有什么问题,分别适用什么场景。
答:简单的 redis 分布式锁可以通过 setnx 命名,对同一个 key 去 setnx 1,因为只有一个会成功,所以就达到了加锁的目的,但是这会有个问题,就是因为 value 都是 1,所有就有可能锁会被其他客户端释放,所以一般采取的措施就是 value 是随机数或者时间戳。但这个仅是和单机的 redis,如果 redis 是集群,主的数据还没来得及同步到从,主挂了,那么锁就失效了,其他客户端就能再次获取锁了。
所以 redis 作者提出了 redlock,客户端向多个节点申请锁,每个节点设置远小于锁过期时间的等待时间,当成功的节点个数⼤于一半,则获取成功。但这和上面单节点一样会有问题,有节点发生崩溃或者有节点阻塞导致过期等都同样会有问题
3. REST 和 RPC 异同?
答:(1) ⾯向的对象不同:REST 是⾯向资源的,而 RPC 是⾯向服务,⾯向方法的
(2) 所属类别不不同:REST 主要是用在 http 中,而 RPC 主要是远程调⽤
4. Zk 怎么保证多客户端同时创建节点,只有一个创建成功。
答:通过查看 zk 的源代码可以发现, createNode 的实现会先根据节点的 path 获取上级路径的父节点,并用⽗节点对后续的创建节点操作进行加锁。当父节点 getchildren 包含当前节点时,直接失败。
八:数据库知识
1. Mysql MyIsam 和 InnoDB 引擎索引结构有什什么区别。
2. 数据库隔离级别有哪些,各自的含义是什么, MYSQL 默认的隔离级别是什么。
答:隔离级别有 4 种
未提交读:最低级别,只保证不读取物理损坏的数据
提交读:可以避免脏读
可重复读:默认级别,能够避免脏读和不可重复读
可序列化:最⾼级别,可以避免脏读,不可重复读和幻读。
3. 什么是幻读。
答:一个事务按照相同条件读取以前读取过的数据,发现其他事务插入了满足条件的数据。避免幻读一般采取的措施是采用间隙锁。 不可重复读关注的是数据被其他事务修改,而幻读关注的是其他事务插入了新的符合条件的数据。
4. Mysql 的索引原理,索引的类型有哪些,如何创建合理的索引,索引如何优化。
答:索引使用 B+树对数据进行快速的检索。
B+树索引, hash 索引,前缀索引,全文索引等等。
创建合理理的索引:(1)首先你得清楚你业务中的使用场景,哪些字段会被经常用做检索条件,然后考虑字段的离散程度
(2) 根据需要适当的建立索引,不要过度,索引不是越多越好
(3) ⻓字段可以考虑前缀索引,多字段可以考虑建立联合索引
(4) InnoDB 还可以充分利用聚集索引
索引的优化我认为主要是优化有索引但没用上的情况:
or 的每个条件都必须有索引,不然不会⽤索引;
是否是复合索引的前列;
Like 模糊查询模糊匹配%放在最前面;
字符串没加引号导致的隐式类型转换
九:消息队列
1. 消息队列的使用场景。
答:消息队列一般用于系统间的解耦, 例如订单组发生订单相关的各类 mq 消息,关心订单操作的系统自行申请相关的 mq 即可。
异步处理, 相比较于 rpc 的同步调⽤,需要等待结果返回, mq 是异步处理的,例如库存的扣减主流程仅仅依赖 redis,而扣减 DB 可以通过 mq 实现最终一致性。
瞬时流量的平滑削峰处理,对于瞬时的大流量,可以将其放⼊ mq 中,消费端不断拉取任务进⾏处理,做到平滑削峰。
2. 消息的重发,补充策略。
答:消费端消费成功后都会给予消息中间件确认消息,中间件即可将相关的消息删除。但是由于网络的不可靠或者其他因素,消息中间件为了保证消息的一定送达,一般会采取各种重发措施,一般常见的措施有超时重传,消息确认机制等。
3. MQ 系统的数据如何保证不丢失。
答:各大消息中间件采取的措施其实⼤同小异,互相借鉴,以 Kafka 为例。
发送端一般是通过 ACK 应答机制,当 kafka 接收到消息后,就会发生应答消息,可以配置是不需要应答,还是 leader 应答, 还是所有的 follower 都完成再应答。
消息队列一般是通过持久化到文件系统,节点的主从机制,已经主节点的***等机制。消费端则一般是通过应答机制,以及超时重传来保证消息的可靠性的。 Kafka 通过位点来控制数据的不丢失
十:缓存
1. 如何防止缓存击穿和雪崩。
答:(1)缓存穿透:指的是当缓存查不到的时候,去查数据库。当有人⽤大量量的不存在的key 去恶意查你的缓存时候,就会有⼤量的请求打到数据库,对数据库造成压力。一般可以采取的措施是,查询缓存前在增加一层过滤,例如通过 bitmap。
(2)缓存击穿:指个别被高频访问的热点 sku,当这些热点 sku 过期了,大量的请求就会打到数据库。可以考虑采取加锁,或者设置更⻓的过期时间,甚⾄不过期。
(3)缓存雪崩:指大⾯积的 key 同时过期,请求全部请求到了 DB。采取的办法可以 key 的过期时间增加一个随机数。
其他还可以采取的措施,可以单机通过 Guava 做防刷。其实前面问题的关键都是对数据库造成压力,所以可以在数据库端做好限流或者分布式锁。
2. Redis 的数据结构都有哪些,各自都适合什么样的场景。
答:String, list, hash, set, zset
String 应用最广泛,适合各种 key-value 数据的存储,List 底层是双向链表,适合用作列表,队列等
Hash 适合对象的存储
Set 适合去充场景下集合的存储, set 还提供交并差集⽀支持
Zset 是有序的 set,可以⽤来实现 PriorityQueue
3. Redis 的使用要注意什么
答:(1)冷热数据分开存储,不同业务数据分开存储
(2)规范 key 的命名,根据不同业务设置合适的命名空间
(3)注意垃圾回收, key 设置合适的过期时间
(4)⼤文本数据可以先进行压缩
(5)hash, set 的 key 的 field 不应太多,可以根据业务多用几个 hash 和 set
(6)设计 sharding 机制
4. redis 和 mem***d 的区别。
答:redis 和 mem***d 都能很好的适用缓存,它们使用内存进⾏行数据的存储。主要有如下⼏个区别:
(1)⽀持的数据类型:mem***d 仅支持简单的 key-value,而 redis ⽀持更丰富
(2)线程模型:redis 是单线程的, mem ⽀持多线程,数据量大时, mem 具有一定的优势
(3)持久化:mem 纯内存的, 断电,啥都没了了。redis ⽀支持 rdb 或者 aof 两种⽅式的持久化
(4)内存管理理:mem 将内存划分成一块块固定⼤小的 chunk 内存块,尺⼨寸相同的块组成slab class,当存储数据时,找一个最合适的 chunk 进行存储,可能会产⽣生碎⽚片,内存利⽤率不高。 ⽽ redis 通过对 C 语⾔言的 malloc/free 进行包装,将申请的内存块的⼤小放置在内存块的头部区域,做到精准的内存申请和释放。同时,当内存不不够的时候, mem 采⽤用LRU 进⾏删除,而 redis 除了 LRU 还可以使⽤虚拟内存将部分 value 转移到磁盘中, key依然保存在内存中。
(5)分布式:mem 本身不支持分布式,得⾃己在客户端实现。而 3.0 版本开始, redis 原⽣⽀持集群
咱们下期见!