坐标上海,20~40K 的面试强度

继续分享最新的面经,面试的岗位是上海某公司的 Golang 开发岗,给的薪资范围是 20~40K,对mongodb
要求熟练掌握,所以面试过程中对于mongodb
也问的比较多。
下面是我整理好的面经(去除了项目相关的问题):

自我介绍?
2. mongodb 查询优化讲一下?
可以从以下几个方面展开:
索引的使用:
索引是查询优化的核心。MongoDB 支持多种索引类型(如单字段索引、复合索引、全文索引等)。合理创建索引可以显著提高查询性能。
使用
explain()
方法分析查询计划,查看是否使用了索引以及索引的效率。查询语句优化:
避免全表扫描:确保查询条件能够命中索引。
尽量减少返回的数据量,使用
projection
只返回需要的字段。对于复杂的查询,可以通过拆分查询或使用聚合管道来优化。
分片与副本集:
分片可以将数据分布在多个节点上,从而提高查询性能。
副本集主要用于高可用性,但读操作可以分担到从节点以减轻主节点的压力。
硬件和配置优化:
调整 MongoDB 的内存分配和缓存策略,充分利用服务器资源。
定期监控数据库性能,使用工具如 MongoDB Atlas 或第三方监控工具定位瓶颈。
写操作优化:
批量写入比单条写入更高效。
在高并发场景下,考虑调整写关注级别(Write Concern)以平衡性能和一致性。
3. mongodb 和 mysql 的索引特性上有什么区别?
索引类型:
MongoDB 支持多种索引类型,包括单字段索引、复合索引、地理空间索引、全文索引和哈希索引。
MySQL 主要支持 B+树索引(InnoDB 和 MyISAM 引擎),此外还有全文索引、哈希索引(Memory 引擎)等。
索引存储结构:
MongoDB 默认使用 B 树作为索引结构,适合范围查询和排序。
MySQL 的 InnoDB 引擎使用 B+树,更适合范围查询和顺序访问。
索引覆盖:
MongoDB 支持索引覆盖查询(Index-Only Query),即如果查询的所有字段都在索引中,则无需访问文档本身。
MySQL 同样支持索引覆盖,但需要确保查询字段完全包含在索引中。
唯一性约束:
MongoDB 允许在集合中创建唯一索引,但分布式环境下的唯一性约束需要额外注意。
MySQL 的唯一索引在单机和分布式环境下都更容易实现。
性能影响:
MongoDB 的写操作会在写入文档的同时更新索引,可能会对性能产生一定影响。
MySQL 的索引维护成本较高,尤其是在大规模更新或插入时。
4. mongodb 设计索引上跟 mysql 有什么区别?
数据模型差异:
MongoDB 是文档型数据库,数据以嵌套的 JSON 格式存储,因此可以在嵌套字段上创建索引。
MySQL 是关系型数据库,数据以表格形式存储,索引设计通常基于列。
复合索引的设计:
MongoDB 的复合索引顺序非常重要,查询条件必须按照索引定义的顺序匹配才能生效。
MySQL 的复合索引也有顺序要求,但其查询优化器会尝试重排条件以匹配索引。
动态模式的支持:
MongoDB 支持动态模式,索引设计需要考虑文档结构的多样性。
MySQL 的表结构是固定的,索引设计相对简单。
分布式环境:
MongoDB 的分片集群需要为分片键创建索引,且分片键的选择对性能有重大影响。
MySQL 在分布式环境中通常通过中间件(如 ShardingSphere)实现分片,索引设计不受分片键限制。
索引大小的考虑:
MongoDB 的索引存储在内存中,过大的索引可能导致性能下降。
MySQL 的索引也占用内存,但其 B+树结构更节省空间。
5. mongodb 在创建索引和使用上有什么注意事项吗?
选择合适的字段:
根据查询频率和数据分布选择索引字段,避免为低频查询创建索引。
复合索引的字段顺序应根据查询条件的重要性排列。
索引的维护成本:
创建索引会增加写操作的开销,因为每次写入都需要更新索引。
删除不必要的索引以减少维护成本。
索引的覆盖能力:
尽量设计索引以支持覆盖查询,减少文档访问次数。
内存限制:
索引需要加载到内存中才能高效工作,因此索引大小不能超过可用内存。
后台创建:
在生产环境中创建索引时,建议使用后台模式(
background: true
),以避免阻塞其他操作。分片集群的特殊要求:
分片集群需要为分片键创建索引,并确保分片键的选择均衡分布数据。
6. mongodb 和 mysql 主键的区别?主键会带来什么影响?
主键的生成方式:
MongoDB 默认为主键字段
_id
生成一个唯一的 ObjectId 值,也可以自定义主键。MySQL 的主键通常由用户指定,或者由自增列(AUTO_INCREMENT)生成。
主键的作用:
MongoDB 的主键用于唯一标识文档,同时也是集合的默认索引。
MySQL 的主键用于唯一标识行,同时是表的聚集索引(InnoDB 引擎)。
性能影响:
MongoDB 的主键索引会影响查询和写入性能,尤其是当主键是随机生成的 ObjectId 时,可能导致频繁的页分裂。
MySQL 的主键直接影响数据存储的物理顺序,连续递增的主键有助于提高插入性能。
分布式环境:
MongoDB 的主键在分片集群中需要结合分片键使用。
MySQL 的主键在分布式环境中可能需要额外的协调机制。
7. kafka 怎么保障 kafka 消息可靠性?
持久化:
Kafka 将消息持久化到磁盘,确保即使发生故障也能恢复数据。
通过配置
acks
参数,可以控制消息的确认级别(如acks=1
、acks=all
)。副本机制:
Kafka 使用分区副本(Partition Replication)来保证数据的冗余。
ISR(In-Sync Replica)机制确保只有同步完成的副本才能参与选举。
消息确认:
生产者可以通过
acks
参数设置消息的确认级别,确保消息被成功写入。消费者确认:
消费者通过手动提交偏移量(Offset)确保消息被正确处理。
事务支持:
Kafka 支持事务性消息,确保跨分区的消息一致性。
8. kafka 怎么保证消息幂等?
生产者幂等性:
Kafka 引入了幂等性生产者(Idempotent Producer),通过为每个生产者分配唯一的 PID(Producer ID)和序列号(Sequence Number)来确保每条消息只被写入一次。
事务支持:
Kafka 支持事务性消息,允许跨分区和主题的消息原子性提交。
消费者端处理:
消费者可以通过去重逻辑(如基于消息 ID)避免重复处理。
9. 怎么限制 goroutine 的上限?
使用信号量(Semaphore):
使用
sync.WaitGroup
或chan struct{}
实现信号量,限制并发 goroutine 的数量。使用 Worker Pool 模式:
创建固定数量的 worker goroutine,任务通过队列分发给这些 worker。
使用第三方库:
使用类似
ants
这样的协程池库,直接设置最大 goroutine 数量。
10. sync.map 的实现介绍一下?
sync.Map
是 Go 标准库中提供的一个并发安全的 map 实现,旨在优化高并发环境下的读写性能。它特别适合于读多写少的场景,并通过内部机制减少锁竞争来提高效率。
核心数据结构
read
:这是一个只读缓存,包含一部分或全部的数据副本。它是无锁访问的,因此读操作非常快。dirty
:这是一个可写的缓存,包含了所有键值对(包括那些在read
中没有但新添加的)。由于需要支持写入,访问dirty
时会涉及到加锁操作。entry
:这是存储实际键值对的结构体。它支持原子操作,允许高效地更新或删除值而无需锁。
工作机制
读操作
当进行读取时,优先从
read
中查找数据。因为read
是无锁的,所以读取速度很快。如果
read
中找不到且有未迁移至read
的数据,则检查dirty
。这时需要加锁,但这种情况相对较少。写操作
写入已存在的键值对时,尝试直接更新
read
中对应的条目。这通常可以通过原子操作完成,避免了加锁。对于新增的键值对,则会添加到
dirty
缓存中。如果dirty
尚未初始化,会先将read
中的数据复制到dirty
。数据迁移
随着时间推移,
dirty
可能积累大量未迁移到read
的数据。当达到一定条件时,sync.Map
会触发一次数据迁移,将dirty
提升为新的read
并清空旧的dirty
。删除操作
删除操作不是立即从
read
或dirty
中移除数据,而是标记相应的entry
为已删除。这样可以延迟清理工作,减少内存分配和回收的开销。
适用场景
读多写少:在这种情况下,
sync.Map
的设计能够最大化利用其无锁读的优势。动态数据集:适用于键值对集合经常变化的应用场景。
高并发环境:提供了一种高效的并发控制方式,减少了锁争用。
注意事项
虽然
sync.Map
在读多写少的情况下表现优异,但在写密集型应用中可能不如使用传统同步方法(如手动加锁)那样有效。应谨慎评估你的应用场景是否适合使用
sync.Map
,特别是当你预计会有大量的新键值对插入时。
欢迎关注 ❤
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:面试群。
版权声明: 本文为 InfoQ 作者【王中阳Go】的原创文章。
原文链接:【http://xie.infoq.cn/article/1f69a2a45f20310e763e3bfee】。文章转载请联系作者。
评论