“学会吊打面试官系列”8.12~8.24面试难点记录

一共面了三家小公司,以下为个人记录的比较重要的10道题目

redis大key是什么问题?如何避免?

“大 Key”是指那些占用大量内存的键值对。大 Key 会导致各种性能问题,比如:内存消耗增大,性能影响增大,导致redis操作延迟,若在分布式环境下,会导致大量数据通过网络传输,增加网络压力。
持久化时,大key会导致操作耗时增加,甚至导致持久化失败。
避免大key:避免将大量数据存储在单个key中,可以考虑将数据拆分成多个小key。可以定期检测key的大小,清理和拆分大key;可以使用数据压缩,将数据压缩后再存入到redis中,节省空间。

redis中数据结构bitmap的使用场景?优缺点?

Redis 中的 bitmap 是一种非常高效的数据结构,用于存储和操作位(bit)级数据。它可以用来处理大规模的、稀疏的布尔值数据集合。
使用场景

  1. 用户行为分析:
    ○ 签到系统:记录用户每日签到的情况,每一天用一个 bit 表示是否签到。
    ○ 活跃用户统计:跟踪每天的用户活跃状态,例如每个 bit 表示用户是否在某一天访问过系统。
  2. 权限控制:
    ● 访问权限:用来控制用户是否拥有某项权限,每个权限用一个 bit 表示用户是否拥有该权限。
    在线状态:
    ● 在线用户:记录系统中用户的在线状态,例如每个 bit 表示用户是否在线。
    推送消息:
    ● 消息发送:标记是否已向某个用户发送了推送消息,避免重复发送。
    去重:
    ● 唯一用户标识:用来跟踪大范围的唯一用户标识,如记录某用户是否在一天内访问过网站,每个用户用一个 bit 来表示。
    优点
  3. 内存高效:
    ○ 低空间消耗:每个位仅占用 1 bit,存储大量布尔值数据时非常节省内存。例如,存储 1,000,000 个布尔值仅需约 125 KB 的内存。
  4. 快速操作:
    ○ 常数时间操作:位操作(如设置、获取和清除)通常在常数时间内完成。
  5. 适合稀疏数据:
    ○ 适用范围广:适合存储稀疏数据集合,如某个特定范围内的布尔值信息。
  6. 支持丰富的操作:
    ○ 多种操作:Redis 的 BITOP 命令允许对多个 bitmap 进行位操作,如 AND、OR、XOR 等。
    缺点
  7. 操作复杂性:
    ○ 位操作复杂:对于不熟悉位操作的开发者来说,位操作的逻辑可能较复杂。
  8. 没有内建的复杂数据结构:
    ○ 简单存储:Bitmap 只支持基本的位操作,没有复杂的查询和分析能力。
  9. 长度限制:
    ○ 最大长度:Bitmap 的长度受限于 Redis 的最大 key 长度,如果需要更大的 bit 集合,需要考虑分片或其他存储方式。
  10. 可读性差:
    ○ 调试困难:位操作可能使调试和数据可视化变得困难,因为数据存储在单个位中,不容易直接查看。
mysql可以用字符串做主键索引吗?varchar可以做主键索引吗?innodb对单个索引的最大长度限制为多少?

在 MySQL 中,字符串(如 VARCHAR 类型)可以用作主键索引。实际上,VARCHAR 类型作为主键非常常见,尤其是在需要用文本字段唯一标识记录的情况下。例如,使用电子邮件地址、用户名或其他自然键作为主键。较长的字符串作为主键可能导致索引变得较大,从而影响查询性能和存储效率。
MySQL 8.0:默认情况下,MySQL 8.0 使用 DYNAMIC 或 COMPRESSED 行格式,因此索引前缀长度的限制可以达到 3072 字节(对于 utf8mb4 编码为 767 字符)。

微服务之间的通信为什么使用gprc而不是rest?优点在什么地方?

在微服务之间的通信中,gRPC 相比于 REST 有几个明显的优点,这也是为什么越来越多的公司选择 gRPC 而不是 REST。首先,gRPC 基于 HTTP/2 协议,它本身就比传统的 HTTP/1.1 更加高效,支持双向流式通信、多路复用,也就是说同一个连接上可以处理多个请求,这大大降低了延迟和带宽的使用。
其次,gRPC 使用的是 Protocol Buffers 作为序列化格式。相比 JSON 或 XML,Protobuf 更加紧凑和高效,传输的数据量更小,这在高并发和低带宽环境下特别有优势。因为序列化和反序列化的速度也很快,所以整体性能比 REST 高很多。
另一个重要的优势是,gRPC 支持多种语言。gRPC 服务的定义是通过 .proto 文件来描述的,客户端和服务端代码可以通过这些定义自动生成,这极大简化了跨语言开发的复杂性。而且这些代码生成的接口都是强类型的,编译时就能检查出错误,避免了很多因为接口变更导致的运行时错误。
最后,gRPC 还天然支持双向流和长连接,这在需要实时通信或者推送消息的场景下非常有用,而 REST 通常需要配合其他技术来实现类似功能,比如 WebSocket。

讲解一下es,es的底层逻辑,了解lucene么?简单说一下es是在基础上加了什么措施才实现了高性能,高扩展和高可用?

ES)是一个分布式搜索引擎,底层是基于 Apache Lucene 的。Lucene 本身是一个强大的搜索库,它提供了全文搜索、索引等功能,性能也非常好,但 Lucene 的复杂度比较高,直接使用不太友好。Elasticsearch 可以看作是对 Lucene 的封装,提供了一个更高层的接口,让我们能更轻松地进行分布式搜索和数据分析。
从底层逻辑上来看,Elasticsearch 通过分片(Sharding)和副本(Replication)来实现高性能和高可用。分片就是把数据分成多个块,每个块可以独立地进行存储和搜索,这样一来,查询和写入操作可以并行处理,极大地提高了性能。副本则是在多台机器上保存同样的数据,确保即使某个节点故障,数据也不会丢失,从而保证了高可用性。
另外,ES 在 Lucene 的基础上还增加了一些集群管理的功能,比如自动发现和自动分片重分配。这意味着,当你增加或删除节点时,Elasticsearch 能够自动地将数据重新分配到新的节点上,无需手动干预,这使得它的扩展性非常强。

为什么mongodb查询文档就比mysql快?

数据存储格式
● MongoDB:MongoDB 是一个面向文档的 NoSQL 数据库,使用 BSON(Binary JSON)格式存储数据。BSON 是一种高效的二进制序列化格式,支持复杂的嵌套结构。这使得 MongoDB 可以高效地存储和查询嵌套的数据结构,如数组和嵌套文档。
● MySQL:MySQL 是一个关系型数据库,使用表格结构存储数据。虽然 MySQL 的表格结构灵活,但对于复杂的数据结构或嵌套关系,表连接操作可能会变得复杂且低效。
索引机制
● MongoDB:MongoDB 对于查询性能的优化依赖于高效的索引机制。它支持多种索引类型,如单字段索引、复合索引、地理空间索引等。MongoDB 还允许在嵌套文档字段上创建索引,从而提高对复杂查询的支持。
● MySQL:MySQL 也支持多种索引类型,包括 B-Tree 索引、哈希索引等。但对于一些复杂的查询或涉及多个表的联接操作,索引的效率可能会受到限制。
数据模型和查询方式
● MongoDB:MongoDB 支持灵活的数据模型,可以存储嵌套的文档和数组。查询可以直接访问嵌套的数据,避免了关系型数据库中常见的联接操作,从而提高查询效率。MongoDB 的查询语言也提供了丰富的功能,可以高效地处理复杂的文档结构。
● MySQL:MySQL 使用关系模型,通常需要进行联接操作来处理多个表的数据。这些联接操作可能会增加查询的复杂性和时间,特别是当涉及大数据集和复杂联接时。
数据的分片和分布
● MongoDB:MongoDB 原生支持分片(sharding),可以将数据分布在多个节点上,从而实现横向扩展。查询时可以通过分片键高效地路由到正确的分片,从而提高查询性能。
● MySQL:虽然 MySQL 也支持分区和分表,但分布式数据库的功能和灵活性通常不如 MongoDB 的分片机制强大。实现复杂的分布式查询可能需要额外的配置和管理工作。
内存使用和缓存:MongoDB 对于热点数据有良好的内存缓存策略。MongoDB 的 WiredTiger 存储引擎在内存中缓存数据页,从而加快查询速度。它可以充分利用内存,减少磁盘 I/O。

b树和b+树区别,b+树作为mysql索引的优点

B+ 树的主要优势在于它把所有的数据都存在叶子节点,这样可以让范围查询和顺序扫描变得非常高效,因为这些节点是按顺序排列并通过链表连接的。而且 B+ 树的内部节点只存储键值,这让树的高度保持较低,减少了内存占用和磁盘 I/O 操作。因此,B+ 树在处理大规模数据和执行复杂查询时性能更稳定,这也是它作为 MySQL 索引的主要原因。

当用户登录在线时怎么保证用户登录状态和redis中存储的用户状态一致?

首先,用户每次登录时,系统会在 Redis 中更新他们的在线状态,比如存储一个带有 user_id 的键,值是一些相关信息,比如登录时间、客户端类型、和一个唯一的会话 token。这个 token 用来标识用户的当前会话,有效地防止了重复登录或并发登录时的状态混乱。
然后,在用户进行任何操作时,比如发送消息或接收推送,系统都会先检查 Redis 中的这个状态信息,确保用户确实在线。如果 Redis 中的状态过期或失效,系统会要求用户重新登录,确保状态的同步性。
当用户退出时,无论是主动登出还是因为网络原因断开连接,我们都要及时清除 Redis 中的状态信息。对于那些没有正常退出的情况,比如网络掉线或者异常关闭客户端,我们可以依赖心跳检测或者超时机制。在 IM 系统中,通常会有一个定时任务或者心跳机制来检查用户的在线状态,如果长时间没有收到心跳,就会认为用户已经离线,并更新 Redis 中的状态。

对一个函数中传入一个int参数,如何去判断该参数是零值?还是传的其他值?还是未传递?

● 使用指针类型:我们可以将 int 参数改为 *int,也就是指针类型。这样,调用方如果传递了 nil,就表示参数未传递,反之如果传递了一个非 nil 的值,就可以检查指针指向的具体值是 0 还是其他数值。这种方式很直观,但需要调用方创建指针,使用起来可能稍微麻烦一些。
● 使用额外的布尔值标记:另一种方式是在函数签名中增加一个 bool 参数,用来明确表示 int 参数是否被传递。这种方式相对简单,也常用于需要传递多个可选参数的场景。

常用数据类型,值类型和引用类型,存在堆还是栈中?

值类型包括基本数据类型,比如 int、float、bool,还有结构体 struct 等。这些类型的变量在被赋值时会直接复制其内容。值类型通常存储在栈(stack)中,因为栈适合处理这些生命周期短的、大小固定的数据。栈上的内存管理比较简单,变量在函数调用结束时自动释放,减少了手动内存管理的复杂性。
引用类型包括切片 slice、映射 map、通道 channel 和接口 interface。这些类型的变量并不直接存储数据,而是存储对数据的引用。实际的数据会存储在堆(heap)上。堆适合处理生命周期较长、大小不固定的数据。引用类型变量在函数调用时会存储在栈上,但它们指向的数据则存储在堆上。堆的内存管理由 Go 的垃圾回收器负责,可以自动处理内存的分配和回收。
总结一下:值类型通常存储在栈中,因为它们的数据在传递和操作时是直接复制的;而引用类型的实际数据存储在堆中,栈上存储的是指向这些数据的引用。这样设计可以有效地管理内存,平衡性能和灵活性。在开发中理解这些差异,可以帮助我们编写更高效的代码和做出更好的内存管理决策。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值