每天一套面试题Day10-腾讯高频
1.HashMap底层原理和扩容机制
数组+链表 数组+链表/红黑树(JDK8以及之后,在 ?时会变成红黑树 当元素数目大于因子(0.75)×?的时候,会发生扩容,扩容为原来的两倍,在jdk7之前要重新计算来确定位置,由于要么位置在原位置,要么在原位置+原数组长度,所以用哈希值与上原数组长度,如果为真,那么就在原位置+原数组长度,不然的话就不动。确定好在哈希桶的位置后,再尾插进对应的位置。
默认初始容量16,负载因子0.75,当元素数量超过(容量×负载因子)发生扩容。链表长度>=8且数组长度≥64时会转为红黑树,提升查询效率。
2.ArrayList和LinkedList的区别
ArrayList底层基于动态数组,LinkedList底层基于双向链表。 因此ArrayList随机访问快,直接基址+元素大小×索引即可得到位置,LinkedList增删中间快,因为只需要遍历,而ArrayList需要移动。
3.JVM的垃圾回收算法
标记-整理(老年代,无内存碎片),标记-清除(老年代,有内存碎片),标记-复制(新生代,无内存碎片)
4.详细的说说Redis的数据类型
5.Redis的持久化策略
默认RDB。快照。有丢失数据的风险,但恢复快 AOF,以命令的形式追加。数据完整性高,文件更大,恢复比较慢。 RDB + AOF 兼具两者优势。
6.Redis如何与数据库保持双写一致性
双写一致性 指的是,当我们同时使用了数据库(持久化存储)和 Redis(缓存)时,如何保证对一个数据进行更新后,两者存储的数据是相同的。
6.1.并发问题
-
更新缓存和数据库,如果并发两个写,会因为并发导致数据库和缓存数据不一致。
-
这里可以用旁路缓存策略,也就是说先更新数据库中的数据,再删除缓存中的数据。这个顺序为什么是这样的呢,因为存在一个读写并发,如果先删除缓存,这时候另一个线程来读的话,发现缓存没有,它去数据库读到旧数据,这时候就把旧数据缓存到缓存中,这时候去更新数据库。最终就会发现redis中的数据还是旧的数据,但是数据库更新了,不一致了。 那我们怎么改善这种问题,可以用延迟双删,我们等另一个线程读完旧的数据库的数据,并且写完缓存再删除一次不就解决了吗
-
延迟双删,顾名思义,先删除缓存中的数据,再更新数据库中的数据,然后延迟(睡眠一会),再删除一次。→解决了先删除缓存后更新数据库的问题。
-
当然其实先更新数据库中的数据,再删除缓存中的数据。也存在读写并发,如果我们在缓存中没有读到,就去数据库获取一个旧数据,这时候另一个线程来写数据库,然后删除缓存,我们再把原来从数据库获取到的旧数据缓存在redis中,但是这样有一个问题,就是必须等另一个线程来写数据库,然后删除缓存,都做完之后,再去写缓存,本来写redis就比写sql要快很多,所以这种概率并不高。
-
但是删了缓存的话,命中率变低,如果要求很高,那我们可以更新缓存+数据库(更新缓存+数据库或者更新数据库+缓存,都存在写写并发问题),但是要解决数据库和缓存数据不一致,我们可以采取
-
分布式锁,避免并发问题,写操作时加锁,确保同一数据串行更新。也就是请求执行"更新数据库 → 更新缓存"(先更新数据库再更新缓存,先保证数据权威的来源(数据库),失败处理也合理(缓存失败了,也能后面会过期))的完整操作序列。
-
给缓存加上较短的过期时间,接受出现短暂的缓存不一致,但是缓存的数据反正会很快过期。
6.2.操作失败问题
Redis和数据库是两个独立系统,可能一个成功一个失败。 更新数据库中的数据,再删除缓存中的数据,但是删除缓存中的数据失败了,其他请求打过来不还是不一致吗。
- 消息队列重试机制。要删除的缓存中的数据加入消息队列,消费者来操作,如果失败,会从消息队列重新读取。
- 订阅 MySQL binlog,再操作缓存。更新数据库成功会产生一条日志,记录在 binlog 里。订阅这个日志,并且通过ACK机制确认处理这条更新log(也是通过消息队列,但是代码侵入性没有那么强)
7.HTTP/1.0、HTTP/1.1、HTTP/2.0、HTTP/3.0 的区别?
现在浏览的大部分网站,可能还在使用 HTTP/1.1,但正在快速向 HTTP/2 迁移。 HTTP/2 是当前现代网站的标配和主流,能显著提升网页加载速度。 HTTP/3 是未来。
| 维度 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输协议 | TCP | TCP | QUIC (over UDP) |
| 连接模型 | 持久连接 + 多连接并发 | 单连接多路复用 | 单连接多路复用 |
| 数据格式 | 文本 | 二进制分帧 | 二进制分帧 |
| 队头阻塞 | 应用层存在 | 应用层解决,传输层存在 | 应用层和传输层均解决 |
| 头部压缩 | 无 | HPACK | QPACK |
| 0-RTT建连 | 不支持 | 不支持 | 支持 |
从HTTP/1.1到HTTP/2,核心是改变了数据的传输格式,通过二进制分帧和多路复用解决了应用层效率问题。而从HTTP/2到HTTP/3,核心是更换了底层的传输协议,通过QUIC解决了传输层的根本性瓶颈,提供更低延迟、更可靠的Web体验。
8.从「敲下一个 URL」到「页面出现在屏幕」整条链路全景
- DNS 主机到本地域名服务器递归查询,本地域名服务器,为了完成对客户端的递归查询承诺,向根、顶级、权限域名服务器发起查询,并接收来自它们的迭代查询响应,最终拿到域名对应的IP。
- ARP协议,由目的IP得到目的MAC(路由器的MAC)
- TCP三次握手建立连接
- 应用层:生成 HTTP 请求 传输层:TCP 分段,添加端口号 网络层:IP 封装,添加 IP 地址 数据链路层:添加 MAC 地址,形成帧 物理层:转换为比特流传输
- 由IP协议指路到达服务器
- 服务器再一层层拆开,拆到应用层,解析,响应经过HTTP应用层,TCP传输层,IP网络层,网络接口层等封装,返回客户端
- 浏览器解析渲染
- TCP四次挥手断开连接 (连接管理:根据 HTTP 版本和头信息决定是否保持连接或关闭,现代HTTP/1.1默认长连接,可能不会立即断开)
9.HTTP vs. HTTPS 有什么区别?
小林
10.HTTPS 的「秘钥交换 + 证书校验」全流程
HTTPS 的 TLS 握手流程,其核心目标就是两个:第一,通过证书校验来验证服务器的身份,防止中间人攻击;第二,通过密钥交换算法,安全地协商出一个只有双方知道的对称会话密钥,用于后续的高效加密通信
第一步:建立连接与协商基础
-
- TCP 连接建立: 首先,客户端(比如浏览器)会和服务器通过 TCP 三次握手,建立一个可靠的网络连接。这是所有通信的基础。”
-
- ClientHello & ServerHello: “接着,客户端会发送一个 ClientHello 消息,里面主要包括:一个客户端生成的随机数(Client Random)、以及客户端支持的密码套件列表(比如 RSA 或 ECDHE)。 服务器回应一个 ServerHello 消息,从中选出双方都支持的最强密码套件,并也生成一个服务器随机数(Server Random)发给客户端。”
(至此,双方有了两个随机数,并确定了加密算法组合。)
第二步:核心环节一 —— 证书校验
“接下来就是身份验证的关键环节。服务器会将自己的 数字证书 发送给客户端。 客户端收到后,会进行严格的证书校验:
- 验证证书链:我会检查证书是否由可信的颁发机构签发。浏览器和操作系统里预置了受信任的根CA证书。会用根CA的公钥去验证中间CA的签名,再用中间CA的公钥去验证服务器证书的签名,只要有一环验证失败,就认为身份不可信。
- 验证内容:还会检查证书的有效期是否过期,以及证书上绑定的域名是否与正在访问的网站一致。 只有所有这些校验都通过,才会信任这个服务器,并使用证书里携带的服务器公钥进行后续操作。 如果失败,浏览器就会给用户显示警告。”
第三步:核心环节二 —— 密钥交换
“身份确认后,双方就要安全地协商出后续通信用的对称密钥了。以两种常见的密钥交换方式为例:
-
如果是 RSA 算法: “客户端会生成第三个随机数,叫做 预备主密钥。然后,用刚才证书里拿到的服务器公钥加密这个预备主密钥,通过 ClientKeyExchange 消息发送给服务器。只有拥有对应私钥的服务器才能解密它。这样,双方就都拥有了客户端随机数、服务器随机数和预备主密钥。”
-
如果是现在更推荐的 ECDHE 算法: “服务器会在证书发送后,发送一个 ServerKeyExchange 消息,包含它的椭圆曲线参数和公钥。客户端也生成自己的参数和公钥,通过 ClientKeyExchange 发送回去。然后,双方利用迪菲-赫尔曼密钥交换协议的原理,各自在本地计算,最终得到一个相同的共享密钥,这个共享密钥就作为预备主密钥。这种方式的好处是提供了前向保密,即使服务器私钥未来泄露,过去的通信也无法被解密。”
“无论哪种方式,现在客户端和服务器都拥有了三个共同的随机要素:Client Random, Server Random, 和 Premaster Secret。它们会通过一个伪随机函数,共同计算出最终的 主密钥 和 会话对称密钥。”
第四步:收尾与安全通道建立
为了确认握手过程没有被篡改,并且密钥已经协商成功: 客户端和服务器会互相发送一个 Finished 消息。这个消息是用刚刚生成的会话密钥加密的,并且包含了之前所有握手消息的摘要。 对方收到后,会尝试解密并验证摘要。如果验证成功,就说明整个握手过程是安全且一致的。在这之前,双方会先发送 ChangeCipherSpec 消息,通知对方:‘从现在起,我们之后所有的通信都要用刚才商量好的密钥来加密了’。
至此,TLS 握手全部完成。一个安全的加密通道就建立起来了,之后所有的 HTTP 请求和响应都会在这个加密通道里进行。
**证书体系解决了‘你是谁’的身份问题,非对称加密的密钥交换解决了‘如何安全地传小纸条’的问题,最后再由高效的对称加密来负责‘之后的大量秘密通信’。
#面试真题#记录刷过的面试真题
查看11道真题和解析