【Java面经】一次颇为进阶的面试记录

工作之余又参加了一次面试,对我来说比之前的面试难度都提了一个度,面试官从公司场景引申聊到高并发和Redis的很多问题。 可惜我太菜了回答不上来,只能回答基础的问题。面完就是凉凉的味道。。

Redis相关

Redis的String是怎么实现的?和其他String有什么优势?
Redis是用C语言写的,但它的字符串不是简单的char[]数组,而是简单动态字符串 Simple Dynamic Strings(SDS) ,它是一个二进制安全的字符串。

struct sdshdr{
 unsigned int len ; //buf的长度 
 unsigned int free ; //标记buf中没使用的元素个数 
 char buf[] ;  // 存放元素的数组 
}

优势:

  1. 解决普通char数组的二进制安全问题: C语言的字符串是以\0终止的,二进制数据如果也存在\0字符, 会导致这个字符被截断。而SDS是以len来表示长度的,也就避免了这个问题。
  2. 缓存区溢出问题
  3. 方便进行字符串追加,预分配内存

(详细可以直接看下面连接的文章)

Redis String的扩容过程?
简单来讲也是空间预分配的策略,避免了每次字符串追加都要重新分配内存。

这个写的好详细了:https://juejin.cn/post/6894539895084154887#heading-2

Redis作为缓存的优势有哪些?
对比本地缓存HashMap,SpringCache:本地缓存的功能太单一,没有过期时间,淘汰机制,命中率设计等等。 并且 本地缓存不能实现多个服务数据共享。无法支持高并发。

对比其他分布式缓存如memcached:
Redis的数据结构更加丰富,支持list,set,hash等。并且操作具有原子性
Redis支持数据持久化,可以实现灾难恢复。
Redis支持cluster模式,可以分布式部署。

拓展:为啥Redis不采用多线程?
普通的kv操作瓶颈其实不在cpu,而在内存和I/O
Redis中有多种数据类型的操作,包括事务,采用多线程会因为上下切换,加锁解锁等增加复杂度。
Redis 6.0引入的多线程也主要处理网络I/O方面,对网络事件进行监听

Redis Cluster模式
Redis Cluster是服务器Sharding(分片)的技术
使用的场景:
Redis的主从模式和哨兵模式已经保障了数据高可用,实现读写分离的能力。 但是每台Redis服务器存储的都是相同的数据,对于海量数据存储压力还是很大,并且浪费内存,Redis Cluster实现了对数据分片,将不同的数据存储到不同的master节点上,从而解决了海量数据的问题。

Redis集群采用了去中心化的思想,没有中心节点的说法,对于客户端来说,整个集群可以看成一个整体,可以连接任意一个节点。
在这里插入图片描述
Redis的分布算法:哈希槽算法
对于这样的集群,一个重点问题就是如何将数据分配到不同的Redis服务器上。常见的算法有hash算法,一致性hash算法等等。但是Redis是引入了哈希槽的概念,并且设计了一套新的算法。

Redis-cluster中有16384个哈希槽,集群中的每个redis节点,分配到一部分槽,每个Key使用公式CRC16校验后,对16384取模来决定放置那个槽。通过查询集群的配置,就可以知道key对应的槽属于那个节点,然后再将请求打到该节点。

哈希槽分配到不同节点,可以很容易地向集群添加或者删除节点:

  • 新节点加入到集群中,只需要将旧节点的槽移动到新节点
  • 移除一个旧节点,只需要将该节点的槽移动到其他节点
    槽在节点之间移动不会造成节点阻塞,所以无论是删除还是添加,redis集群都能保证槽的平滑移动,不会造成集群下线。

拓展:一致性哈希算法
一致性hash算法是一种特殊的哈希算法,它本质上也是一种取模算法,但不是按照服务器数量取模,而是对固定值2^32取模

步骤如下:
①、将整个哈希空间按照顺时针方向组织成一个虚拟的圆环,称为Hash环
②、将各个服务器使用Hash函数进行哈希,可以选择服务器IP或者主机名作为关键字进行哈希,来决定服务器在哈希环的位置(这也是为什么对2^32取模的理由,用ip地址进行哈希)
③、用算法定位数据访问到相应的服务器,将数据key使用相同的函数计算出hash值,沿着顺时针找到的第一台机器就是定位到的机器。

一致性Hash的优点是,当服务器数量变化时,只需要重定位一部分的数据,不至于发生缓存雪崩,具有较好的容错性和拓展性。
在这里插入图片描述

网络

一次Http请求包含哪些过程?

  1. 浏览器查找域名的IP地址 (查找过程: 浏览器缓存,本机缓存,发起DNS系统调用)
  2. 浏览器发起一个TCP连接请求 (IP协议,OPSF协议,ARP协议)
  3. 建立完TCP连接后,发起HTTP请求
  4. 服务器返回一个HTTP响应
  5. 浏览器解析HTML响应,并且展示HTML

HTTP的报文是怎么样的?
HTTP的请求报文和相应报文相似,包括请求行,请求头,请求体
在这里插入图片描述

HTTP的请求头有几种?
HTTP头字段是指在超文本传输协议HTTP的请求和响应消息的头部分

常见的请求字段有:

  1. Accept:表示浏览器能够接受的内容类型
  2. Accept-Language 浏览器申明自己接收的语言。
  3. Connection : Connection: keep-alive/close
  4. Host
  5. Cache-Control
  6. Cookie

HTTP3:了解吗?
HTTP3 不再使用TCP协议,而是使用基于UDP的QUIC传输协议。贴张图把:
在这里插入图片描述

Netty有什么优势?
易用性: 使用Jdk的NIO变成需要了解很多复杂的概念,比如channel,selectors,socket等等,Netty在NIO的基础上进行更高地封装,提供了统一的API
更低的资源消耗:

  1. 对象池复用技术,避免频繁创建和销毁对JVM GC带来的压力
  2. 零拷贝技术:除了操作系统级别的零拷贝技术外,Netty 提供了更多面向用户态的零拷贝技术,例如 Netty 在 I/O 读写时直接使用 DirectBuffer,从而避免了数据在堆内存和堆外内存之间的拷贝

其他杂七杂八

Zookeeper中有什么经典的算法?

Zookeeper的应用:
Zookeeper为分布式应用提供分布式锁,发布订阅和配置管理等服务,也提供类似于文件系统的树方式数据存储,但它主要解决分布式集群中的一致性问题,通过维护和监控存储数据的状态变化,达到基于数据的集群管理。

Zab协议:Zab协议是为了解决分布式一致性设计的协议,

Linux内核态和用户态的区别?
先要知道CPU指令是分权限的,不同CPU指令的权限不同,一些操作硬件的指令权限就很高,不是一般进程能使用的。
内核态和用户态其实就是CPU指令权限的区别。做出区别的目的是为了安全性,保护整个系统。

要从用户态切换到内核态,需要经过三种方式之一:系统调用、中断、异常

用户态切换到内核态再切换到用户态这个过程怎么优化?

重点应该放在减少切换操作,比如说IO操作都会需要系统调用让内核线程执行,这个时候mmap就很有用了。
mmap是一种内存映射文件的方法,将一个文件或者其他对象映射到内存,实现文件磁盘地址和进程虚拟地址空间的对应,这样进程就可以使用指针方法操作这一段内存,不必再调用read,write等系统调用函数了。并且操作系统会自动将页面写回到磁盘上。

(底层菜鸡,只能说点边角料的,如果有知道的大佬请在评论区指点一下我)

Spring的注解原理?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值