写点什么

阿里一面都会考什么?

作者:王中阳Go
  • 2025-02-23
    湖南
  • 本文字数:3013 字

    阅读完需:约 10 分钟

阿里一面都会考什么?

新的一年,希望观看本文的各位朋友 offer 拿到手软,薪资翻倍


今天分享的是训练营的朋友在阿里一面的面试题,内容涉及 Redis 的核心知识点和 LRU 算法的实现


这些内容非常实用,尤其是对正在准备面试或工作中需要用到 Redis 的同学。一起来看看吧!



Redis 数据消失的原因

Redis 中的数据如果既没有设置过期时间也没有被显式删除但仍然消失了,可能是因为以下原因之一:


  1. 配置了持久化策略如果 Redis 配置了 RDB 快照或 AOF 日志持久化策略,在重启后可能会因为数据加载失败而导致数据丢失。

  2. 执行了清空命令如果不小心执行了 FLUSHDBFLUSHALL 命令,会导致当前数据库或所有数据库的数据被清空。

  3. 内存驱逐策略当 Redis 达到配置的最大内存限制时,会根据驱逐策略(如 allkeys-lruvolatile-lru)自动移除部分键值对以释放内存空间。

  4. 主从复制故障切换在主从复制场景中,如果发生故障切换且主节点的数据未完全同步到从节点,可能会导致部分数据丢失。



Redis 的数据结构

Redis 支持五种核心数据结构:


  • 字符串(String):适用于存储单值类型的数据,如用户密码、计数器等。

  • 哈希表(Hash):适用于存储键值对类型的复杂对象,如用户信息。

  • 列表(List):适用于需要按顺序存储和操作数据的场景,如消息队列。

  • 集合(Set):适用于需要去重和快速查找的场景,如关注列表。

  • 有序集合(Sorted Set):结合了集合和排序的功能,适用于需要按分数排序的场景,如排行榜。



Redis GeoHash 的使用和实现

Redis 的 GeoHash 功能可以将经纬度坐标编码成一个字符串,从而简化位置数据的管理和检索。在内部,Redis 使用有序集合(ZSet)来保存每个地点的位置信息,其中元素的分数代表了该地点的 GeoHash 编码值。


应用场景


  • 周边商家推荐

  • 地理位置签到


实现原理


  1. 将经纬度坐标转换为 GeoHash 字符串。

  2. 将 GeoHash 字符串作为 ZSet 的成员,并将其对应的分数设置为该字符串的哈希值。

  3. 通过 ZSet 的范围查询功能,快速找到指定区域内的所有地点。



ZSet 的存储方式

ZSet 是 Redis 中一种特殊的集合类型,允许为每个成员关联一个浮点数分值,并按此分值升序排列。为了保证高效的插入、删除和查找操作,Redis 在内部采用了跳跃表(Skiplist)与哈希表相结合的方式组织数据:


  • 跳跃表:确保了快速的顺序访问(O(log n) 时间复杂度)。

  • 哈希表:提供了 O(1) 复杂度的随机访问能力。


应用场景


  • 排行榜(如游戏积分排行)

  • 分布式锁



RocketMQ 如何保障高性能

RocketMQ 是一款高性能的消息队列系统,其核心性能优势来源于以下设计:


  1. 异步刷盘 RocketMQ 将消息写入内存后立即返回给生产者,随后异步将消息刷盘,减少了 I/O 阻塞。

  2. 批量发送生产者可以将多个消息批量发送到 Broker,减少了网络开销。

  3. 零拷贝技术通过 mmap 文件映射和 PageCache 机制,减少了文件读写的开销。

  4. 多线程模型 RocketMQ 采用生产者线程池和消费者线程池的设计,充分利用 CPU 资源。

  5. 文件索引管理 RocketMQ 对消息文件进行了预分配和索引优化,提升了消息的读取效率。



批量提交的好处

批量提交指的是将多个独立的操作合并成一次请求发送给服务器。这种方式有以下好处:


  1. 减少交互次数批量提交可以显著减少客户端与服务端之间的交互次数,降低通信成本和整体延迟。

  2. 提高资源利用率减少了每次请求的上下文切换和资源分配过程,系统能够更加高效地利用计算资源。

  3. 促进资源共享多个任务可以在单次调用中得到统一处理,减少了并发控制带来的额外负担。



固态硬盘(SSD)和机械硬盘(HDD)的区别

SSD 和 HDD 的主要区别如下:




随机读和顺序读

  • 随机读:按照不连续的地址序列访问数据块。对于 HDD 来说,随机读会导致频繁的磁头定位操作,延迟较高。对于 SSD 来说,随机读和顺序读的性能差异较小。

  • 顺序读:沿着预先确定的路径连续读取一系列数据块。这种方式对于 HDD 来说更为有利,因为不需要频繁调整磁头位置。



MQ 消息如何保障不丢失

消息队列系统通常通过以下机制保障消息不丢失:


  1. 持久化存储消息被写入磁盘后才会确认提交,即使发生故障也能恢复。

  2. 确认机制消费者成功处理完消息后向 MQ 发送确认信号。如果消费者未确认或处理失败,消息会重新投递。

  3. 高可用部署通过集群化配置和负载均衡技术,避免单点故障造成的服务中断。



注册中心挂了怎么办

如果注册中心发生故障,可以采取以下措施:


  1. 本地缓存应用程序可以缓存服务实例信息,在注册中心不可用时依赖本地缓存继续运行。

  2. 健康检查与重试应用程序可以定期检查注册中心的状态,并在注册中心恢复后重新连接。

  3. 高可用部署注册中心本身应采用分布式部署策略(如负载均衡或多活数据中心),提高系统的稳定性和可靠性。



编程题:LRU 算法实现

实现思路

LRU(Least Recently Used)是一种常见的缓存淘汰算法。它的核心思想是:当缓存满时,移除最近最少使用的项。为了高效实现 LRU 算法,我们可以结合双向链表(用于维护元素的使用顺序)和哈希表(用于快速查找元素)。

Go 语言实现代码

go复制package main  import (  "container/list"  "fmt") // LRUCache 定义了一个基于 LRU 策略的缓存结构。type LRUCache struct {  capacity int                      // 缓存容量   cache    map[int]*list.Element    // 哈希表,用于存储键及其对应的链表节点   lru      *list.List               // 双向链表,用于维护元素的使用顺序 } // Entry 表示缓存中的一个条目。type Entry struct {  key   int // 键   value int // 值 } // Constructor 初始化一个新的 LRUCache 实例。func Constructor(capacity int) LRUCache {  return LRUCache{    capacity: capacity,    cache:    make(map[int]*list.Element),    lru:      list.New(),  }} // Get 根据键获取对应的值。如果键不存在,则返回 -1。func (cache *LRUCache) Get(key int) int {  if elem, ok := cache.cache[key];  ok {    cache.lru.MoveToFront(elem)  // 将最近使用的元素移动到链表头部     return elem.Value.(*Entry).value   }  return -1 // 如果键不存在,返回 -1 } // Put 插入或更新键值对。如果缓存已满,则移除最近最少使用的元素。func (cache *LRUCache) Put(key int, value int) {  if elem, ok := cache.cache[key];  ok {    cache.lru.MoveToFront(elem)  // 更新现有条目,并将其移动到链表头部     elem.Value.(*Entry).value = value   } else {    if cache.lru.Len()  >= cache.capacity  {      // 移除链表尾部的元素(最近最少使用的)      old := cache.lru.Back()       if old != nil {        cache.lru.Remove(old)         delete(cache.cache,  old.Value.(*Entry).key)      }    }    // 将新条目添加到链表头部     elem := cache.lru.PushFront(&Entry{key,  value})    cache.cache[key]  = elem   }} func main() {  cache := Constructor(2 /* 容量 */)  cache.Put(1, 1)  cache.Put(2, 2)  fmt.Println(cache.Get(1)) // 输出:1   cache.Put(3, 3)           // 移除键 2   fmt.Println(cache.Get(2)) // 输出:-1   cache.Put(4, 4)           // 移除键 1   fmt.Println(cache.Get(1)) // 输出:-1   fmt.Println(cache.Get(3)) // 输出:3   fmt.Println(cache.Get(4)) // 输出:4 }
复制代码



欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:面试群。

发布于: 刚刚阅读数: 5
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
阿里一面都会考什么?_Go_王中阳Go_InfoQ写作社区