设计模式面试

设计模式面试

数据存储

  • 反模式设计:指在对经常面对的问题经常使用低效,不良,或者有待优化的设计模式/方法。甚至,反模式也可以是一种错误的开发思想/理念
  • 分库与分表设计:水平/垂直分库分表
  • 分库与分表带来的分布式困境与应对之策:数据迁移与扩容问题(随机分表和连续分表)、表关联问题(避免联合查询,可以通过程序中进行拼装,或者通过反范式化设计进行规避)、分页与排序问题、分布式事务问题、分布式全局唯一ID( UUID、GUID等)
  • MySQL 遇到的死锁问题:产生死锁的四个必要条件(互斥,请求与保持,不剥夺,循环等待),只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁
    • 按同一顺序访问对象。
    • 避免事务中的用户交互。
    • 保持事务简短并在一个批处理中。
    • 使用低隔离级别。
    • 使用绑定连接。
  • 数据库索引的原理:数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用 BTree 及其变种 B+Tree。
  • 为什么要用 B-Tree:一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘 I/O 消耗,相对于内存存取,I/O 存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘 I/O 操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘 I/O 的存取次数。
  • 聚集索引与非聚集索引的区别
    • 聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
    • 聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续
    • 聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序
    • 非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序.
    • 索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。
  • limit 20000 加载很慢怎么解决
    • 前端加缓存,或者其他方式,减少落到库的查询操作,例如某些系统中数据在搜索引擎中有备份的,可以用 es 等进行搜索
    • 使用延迟关联,即先通用 limit 得到需要数据的索引字段,然后再通过原表和索引字段关联获得需要数据select a.* from a,(select id from table_1 where is_deleted=‘N’ limit 100000,20) b where a.id = b.id
    • 从业务上实现,不分页如此多,例如只能分页前 100 页,后面的不允许再查了
    • 不使用 limit N,M, 而是使用 limit N,即将 offset 转化为 where 条件。
  • 选择合适的分布式主键方案
    • 数据库自增长序列或字段
    • UUID
    • 使用 UUID to Int64 的方法
    • Redis 生成 ID
    • Twitter 的 snowflake 算法
    • 利用 zookeeper 生成唯一 ID
    • MongoDB 的 ObjectId
  • 选择合适的数据存储方案
    • 关系型数据库 MySQL:因为,需要关系型数据库进行管理,此外,业务存在许多事务性的操作,需要保证事务的强一致性。同时,可能还存在一些复杂的 SQL 的查询。值得注意的是,前期尽量减少表的联合查询,便于后期数据量增大的情况下,做数据库的分库分表。
    • 内存数据库 Redis:可以极大的提高查询性能,对产品在架构上很好的补充。为了提高服务端接口的访问速度,尽可能将读频率高的热点数据存放在 Redis 中。这个是非常典型的以空间换时间的策略,使用更多的内存换取 CPU 资源,通过增加系统的内存消耗,来加快程序的运行速度。在某些场景下,可以充分的利用 Redis 的特性,大大提高效率。这些场景包括缓存,会话缓存,时效性,访问频率,计数器,社交列表,记录用户判定信息,交集、并集和差集,热门列表与排行榜,最新动态等。使用 Redis 做缓存的时候,需要考虑数据不一致与脏读、缓存更新机制、缓存可用性、缓存服务降级、缓存穿透、缓存预热等缓存使用问题。
    • 文档数据库 MongoDB:MongoDB 是对传统关系型数据库的补充,它非常适合高伸缩性的场景,它是可扩展性的表结构。基于这点,可以将预期范围内,表结构可能会不断扩展的 MySQL 表结构,通过 MongoDB 来存储,这就可以保证表结构的扩展性。此外,日志系统数据量特别大,如果用 MongoDB 数据库存储这些数据,利用分片集群支持海量数据,同时使用聚集分析和 MapReduce 的能力,是个很好的选择。MongoDB 还适合存储大尺寸的数据。
    • 列族数据库 HBase:HBase 适合海量数据的存储与高性能实时查询,它是运行于 HDFS 文件系统之上,并且作为 MapReduce 分布式处理的目标数据库,以支撑离线分析型应用
    • 全文搜索引擎 ElasticSearch:ElasticSearch 作为一个建立在全文搜索引擎 Apache Lucene 基础上的实时的分布式搜索和分析引擎,适用于处理实时搜索应用场景。此外,使用 ElasticSearch 全文搜索引擎,还可以支持多词条查询、匹配度与权重、自动联想、拼写纠错等高级功能。因此,可以使用 ElasticSearch 作为关系型数据库全文搜索的功能补充,将要进行全文搜索的数据缓存一份到 ElasticSearch 上,达到处理复杂的业务与提高查询速度的目的。ElasticSearch 不仅仅适用于搜索场景,还非常适合日志处理与分析的场景。著名的 ELK 日志处理方案,由 ElasticSearch、LogStash 和 KibAna 三个组件组成,包括了日志收集、聚合、多维度查询、可视化显示等。
  • ObjectId 规则
  • ObjectId
    • 前四位是时间戳,可以提供秒级别的唯一性。
    • 接下来三位是所在主机的唯一标识符,通常是机器主机名的散列值。
    • 接下来两位是产生 ObjectId 的 PID,确保同一台机器上并发产生的 ObjectId 是唯一的。
    • 前九位保证了同一秒钟不同机器的不同进程产生的 ObjectId 时唯一的。
    • 最后三位是自增计数器,确保相同进程同一秒钟产生的 ObjectId 是唯一的。
  • MongoDB 使用场景:高伸缩性的场景、日志系统的场景、分布式文件存储
  • ElasticSearch 使用场景:
    • 全文搜索,这个是用的最多的。加上分词插件、拼音插件什么的可以做成强大的全文搜索引擎。
    • 数据库,挺奇葩的用法,因为 ES 存数相同数据,更费空间,不过确实不错,因为他的强大统计分析汇总能力,再加上分布式 P2P 扩展能力,现在硬件又那么便宜,所以就有人拿来当数据库了。
    • 在线统计分析引擎,日志系统,LogStash; 可以实时动态分析数据。

缓存使用

  • Redis 有哪些类型:String:字符串;Hash:字典;List:列表;Set:集合;Sorted Set:有序集合
  • Redis 内部结构
    • Redis 内部使用一个 redisObject 对象来表示所有的 key 和 value。
    • type :代表一个 value 对象具体是何种数据类型。
    • encoding :是不同数据类型在 redis 内部的存储方式,比如:type=string 代表 value 存储的是一个普通字符串,那么对应的 encoding 可以是 raw 或者是 int,如果是 int 则代表实际 redis 内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:“123” "456"这样的字符串。
    • vm 字段:只有打开了 Redis 的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的。 Redis 使用 redisObject 来表示所有的 key/value 数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给 Redis 不同数据类型提供一个统一的管理接口,实际作者也提供了多种方法帮助我们尽量节省内存使用。
  • Redis 内存淘汰机制
  • Redis 使用场景:缓存、会话缓存、时效性、访问频率、计数器、社交列表、记录用户判定信息、交集、并集和差集、热门列表与排行榜、最新动态、消息队列
  • Redis 持久化机制
    • RDB 持久化方式会在一个特定的间隔保存那个时间点的一个数据快照
    • AOF 持久化方式则会记录每一个服务器收到的写操作。在服务启动时,这些记录的操作会逐条执行从而重建出原来的数据。写操作命令记录的格式跟 Redis 协议一致,以追加的方式进行保存
    • Redis 的持久化是可以禁用的,就是说你可以让数据的生命周期只存在于服务器的运行时间里。两种方式的持久化是可以同时存在的,但是当 Redis 重启时,AOF 文件会被优先用于重建数据。
  • Redis 集群方案与实现:客户端分片、基于代理的分片、路由查询、客户端分片、由客户端决定 key 写入或者读取的节点包括 Jedis 在内的一些客户端,实现了客户端分片机制、开源方案Sentinel
  • Redis 为什么是单线程的:因为 CPU 不是 Redis 的瓶颈。Redis 的瓶颈最有可能是机器内存或者网络带宽。(以上主要来自官方 FAQ)既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。
  • 缓存崩溃:解决方案是加锁排队,加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间 key 是锁着的,这时过来 1000 个请求 999 个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法。
  • 缓存降级
    • 页面降级:在大促或者某些特殊情况下,某些页面占用了一些稀缺服务资源,在紧急情况下可以对其整个降级,以达到丢卒保帅;
    • 页面片段降级:比如商品详情页中的商家部分因为数据错误了,此时需要对其进行降级;
    • 页面异步请求降级:比如商品详情页上有推荐信息/配送至等异步加载的请求,如果这些信息响应慢或者后端服务有问题,可以进行降级;
    • 服务功能降级:比如渲染商品详情页时需要调用一些不太重要的服务:相关分类、热销榜等,而这些服务在异常情况下直接不获取,即降级即可;
    • 读降级:比如多级缓存模式,如果后端服务有问题,可以降级为只读缓存,这种方式适用于对读一致性要求不高的场景;
    • 写降级:比如秒杀抢购,我们可以只进行Cache的更新,然后异步同步扣减库存到DB,保证最终一致性即可,此时可以将DB降级为Cache。
    • 爬虫降级:在大促活动时,可以将爬虫流量导向静态页或者返回空数据,从而保护后端稀缺资源。
    • 自动开关降级:自动降级是根据系统负载、资源使用情况、SLA等指标进行降级。
    • 超时降级:当访问的数据库/http服务/远程调用响应慢或者长时间响应慢,且该服务不是核心服务的话可以在超时后自动降级;比如商品详情页上有推荐内容/评价,但是推荐内容/评价暂时不展示对用户购物流程不会产生很大的影响;对于这种服务是可以超时降级的。如果是调用别人的远程服务,和对方定义一个服务响应最大时间,如果超时了则自动降级。
  • 使用缓存的合理性问题:热点数据,缓存才有价值、频繁修改的数据,看情况考虑使用缓存、数据不一致性、缓存更新机制、缓存可用性、缓存服务降级、缓存预热、缓存穿透
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值