写点什么

面试官:Redis 中大 Key 怎么删除?

作者:王中阳Go
  • 2024-11-06
    北京
  • 本文字数:3541 字

    阅读完需:约 12 分钟

面试官:Redis中大Key怎么删除?

首先来看一下该岗位的职责和要求:

岗位职责

  1. 负责公司旗下产品的全新需求开发

  2. 负责公司中台系统管理系统开发

  3. 开发临时性工具和数据处理工作

  4. 设计开发可复用模块,提高开发效率节省维护成本

  5. 保质保量的完成上级领导安排的技术相关工作

任职要求

  1. 本科以上学历,计算机相关专业优先,3 年左右 Golang 开发经验,有 PHP 转 Go 项目经验者优先

  2. 熟练掌握 Golang/PHP 语言,熟悉至少一种 Golang 框架

  3. 熟练掌握关系型数据库 Mysql 及部分 Nosql

  4. 熟练掌握 Redis 缓存技术及 Rabbitmq 等常用消息队列

  5. 熟悉 Svn/Git,熟悉 Shell,Python 等至少一种脚本语言

  6. 基础扎实,对数据结构有较为深刻的理解

  7. 具备良好的分析解决问题能力,能独立承担任务和有系统进度把控能力,注重结果导向

  8. 良好的代码书写、注释习惯,能写出高质量的代码,对自己开发的代码负责

面试问题

  • 自我介绍

  • 项目介绍

  • 八股

1. Redis 大 key 删除

问题背景:在 Redis 中,删除大 key(如大型哈希表、列表、集合或有序集合)时,直接使用DEL命令会导致 Redis 阻塞,影响性能。


解决方案


  • 使用UNLINK命令

  • UNLINK命令从 Redis 4.0 开始引入,它的工作原理是异步删除 key。UNLINK命令会立即将 key 从数据库中删除,但实际的内存释放工作会在后台线程中进行,不会阻塞主线程。

  • 示例:


    UNLINK my_large_key
复制代码


  • 分批删除

  • 使用SCANHSCANSSCANZSCAN等命令分批删除大 key 中的元素,减少每次操作的负载。

  • 示例:


    SCAN 0 MATCH my_large_hash:* COUNT 100
复制代码


这个命令会返回100个匹配的key,然后你可以逐个删除这些key。
复制代码


  • 选择在业务低峰期执行删除操作

  • 在业务低峰期执行删除操作,可以减少对正常业务的影响。

  • 例如,可以选择在夜间或周末进行大 key 的删除操作。

  • 使用RENAME命令

  • 先将大 key 重命名,使其不再被业务访问,然后再逐步删除。

  • 示例:


    RENAME my_large_key my_large_key_to_delete    DEL my_large_key_to_delete
复制代码

2. MySQL 什么时候会回表

问题背景:在 MySQL 中,回表是指在查询过程中,如果索引不能完全覆盖查询所需的所有列,MySQL 需要通过主键索引回表获取完整的行数据。


具体场景


  • 非覆盖索引:当查询条件命中了索引,但查询结果需要的列不在索引中时,MySQL 需要回表获取这些列的数据。

  • 示例:


    SELECT name, age FROM users WHERE id = 1;
复制代码


如果`id`上有索引,但`name`和`age`不在索引中,MySQL需要回表获取`name`和`age`。
复制代码


  • 非唯一索引:即使查询条件能够唯一确定一行,但如果使用的是非唯一索引,MySQL 也需要回表确认这一行是否满足查询条件。

  • 示例:


    SELECT * FROM users WHERE email = 'example@example.com';
复制代码


如果`email`上有非唯一索引,MySQL需要回表确认是否有多个用户具有相同的`email`。
复制代码


  • 多表联接:在多表联接查询中,如果使用了非覆盖索引,MySQL 可能需要回表获取额外的数据。

  • 示例:


    SELECT u.name, o.order_id FROM users u JOIN orders o ON u.id = o.user_id WHERE u.id = 1;
复制代码


如果`users`表的`id`上有索引,但`name`不在索引中,MySQL需要回表获取`name`。
复制代码

3. MySQL explain type 类型 ref 和 index 的区别

问题背景EXPLAIN命令用于显示 MySQL 如何执行查询计划,其中type列显示了访问类型。


具体区别


  • ref

  • 表示使用了非唯一索引或唯一索引的一部分。

  • 对于每个索引值,MySQL 需要进行一次查询,以找到符合条件的行。

  • 适用于等值查询(如=IN<=>)。

  • 示例:


    EXPLAIN SELECT * FROM users WHERE email = 'example@example.com';
复制代码


如果`email`上有索引,`type`列会显示为`ref`。
复制代码


  • index

  • 表示全索引扫描,即 MySQL 会遍历整个索引来查找匹配的行。

  • 这通常用于索引覆盖查询,即查询的所有列都包含在索引中,无需回表。

  • 适用于范围查询(如><BETWEENLIKE)。

  • 示例:


    EXPLAIN SELECT email FROM users ORDER BY email;
复制代码


如果`email`上有索引,`type`列会显示为`index`。
复制代码

4. 对已经关闭的 chan 进行读写会怎么样?

问题背景:在 Go 语言中,channel 是一种同步机制,用于在 goroutine 之间传递数据。


具体行为


  • 读取已关闭的 channel

  • 从已关闭的 channel 读取数据时,会立即返回零值,并且关闭标志位会被设置,表明 channel 已经关闭。

  • 向已关闭的 channel 写入数据

  • 向已关闭的 channel 写入数据会触发 panic,因为不允许向已关闭的 channel 写入数据。

5. 如何保证多个 goroutine 的全部执行

问题背景:在 Go 语言中,goroutine 是轻量级的线程,用于并发执行任务。确保多个 goroutine 全部执行完毕是常见的需求。


具体方法


  • 使用sync.WaitGroup

  • 在启动 goroutine 前增加 WaitGroup 的计数,goroutine 完成后调用 Done()方法减少计数,最后在主 goroutine 中调用 Wait()等待所有 goroutine 完成。

  • 使用通道

  • 可以创建一个通道,每个 goroutine 完成任务后向通道发送一个信号,主 goroutine 接收这些信号直到所有 goroutine 完成。

  • 使用上下文

  • 通过 context 管理 goroutine 的生命周期,可以取消或超时等待。

6. string 转 bytes 是否会重新分配内存

问题背景:在 Go 语言中,字符串是不可变的,而字节切片是可变的。


具体行为


  • 转换过程

  • []byte(s)将字符串转换为字节切片时,通常不会重新分配内存,而是共享字符串的底层内存。

  • 例如:


    s := "hello"    b := []byte(s)
复制代码


在这个例子中,`b`和`s`共享同一块内存。
复制代码


  • 修改字节切片

  • 如果对字节切片进行了修改,会触发内存拷贝,因为字符串是不可变的。

  • 例如:


    s := "hello"    b := []byte(s)    b[0] = 'H' // 这会触发内存拷贝
复制代码

7. goframe 和 gozero 的区别

问题背景:goframe 和 gozero 都是 Go 语言的开发框架,但它们有不同的设计理念和应用场景。


具体区别


  • goframe

  • 特点:企业级开发框架,提供了一整套的 Web 开发、数据库操作、缓存、日志等组件。

  • 适用场景:适合快速构建企业级应用,特别是需要复杂功能和高性能的应用。

  • 优势

  • 完善的文档和社区支持。

  • 提供丰富的中间件和插件。

  • 支持多种数据库和缓存系统。

  • gozero

  • 特点:轻量级的微服务框架,专注于微服务架构,提供了 API 生成器、服务注册与发现、配置中心等功能。

  • 适用场景:适合构建微服务应用,特别是需要高可扩展性和高可用性的应用。

  • 优势

  • 轻量级,启动速度快。

  • 内置了服务发现和配置管理功能。

  • 支持自动代码生成,提高开发效率。

8. 逃逸分析有哪些场景

问题背景:逃逸分析是编译器的一种优化技术,用于确定变量的作用域和生命周期,以决定变量是否可以在栈上分配,从而减少堆上的内存分配,提高程序性能。


具体场景


  • 全局变量

  • 作用域超出函数范围的变量。

  • 函数返回值

  • 如果函数返回了局部变量的引用或指针,该变量需要逃逸到堆上。

  • 闭包

  • 如果一个函数返回了一个闭包,而闭包引用了外部函数的局部变量,那么这些变量需要逃逸到堆上。

  • 例如:


    func createClosure() func() int {        x := 10        return func() int {            return x // x 逃逸到堆上        }    }
复制代码


  • 循环中的变量

  • 在循环中创建的变量,如果在循环外被引用,也会逃逸到堆上。

9. Kafka 如何实现有序

问题背景:Kafka 是一个分布式流处理平台,用于构建实时数据管道和流应用。


具体实现


  • 分区

  • 每个主题可以被划分为多个分区,每个分区内的消息是有序的。

  • 生产者可以指定消息的分区键,确保相同键的消息被发送到同一个分区。

  • 单一消费者

  • 对于每个分区,如果有多个消费者订阅了同一个消费者组,那么每个分区的消息只会被一个消费者消费,确保了消息的顺序。

  • 事务

  • Kafka 支持事务,可以确保消息的生产者发送的消息按照发送顺序被提交。

10. 项目中常用的设计模式

问题背景:设计模式是解决常见问题的模板,可以帮助开发者编写更高效、更可维护的代码。


  • 单例模式

  • 描述:确保一个类只有一个实例,并提供一个全局访问点。

  • 优点:节省资源,避免重复创建对象。

  • 缺点:单例对象通常是全局可访问的,容易引起耦合。

  • 工厂模式

  • 描述:提供一个创建对象的接口,但由子类决定实例化哪一个类。

  • 优点:将对象的创建和使用分离,提高代码的灵活性。

  • 缺点:增加了代码的复杂性。

  • 观察者模式

  • 描述:定义了对象之间的一对多依赖关系,当一个对象的状态改变时,所有依赖于它的对象都会得到通知。

  • 优点:实现了对象之间的松耦合。

  • 缺点:如果观察者数量过多,通知过程可能会变得复杂。

  • 策略模式

  • 描述:定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。

  • 优点:算法的变化独立于使用算法的客户。

  • 缺点:增加了代码的复杂性。

  • 装饰者模式

  • 描述:动态地给一个对象添加一些额外的职责,而不必修改对象结构。

  • 优点:增加了代码的灵活性和可扩展性。

  • 缺点:增加了代码的复杂性。

  • 代理模式

  • 描述:为其他对象提供一种代理以控制对这个对象的访问。

  • 优点:增加了安全性和灵活性。

  • 缺点:增加了代码的复杂性。

欢迎关注 ❤

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


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


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

用户头像

王中阳Go

关注

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

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

评论

发布
暂无评论
面试官:Redis中大Key怎么删除?_php_王中阳Go_InfoQ写作社区