设计模式

工厂模式

将对象的创建逻辑封装在一个工厂类中,而不是直接实例化,使得创建对象的过程与使用对象的过程分离
使用场景:

  1. 日志记录:选择记录位置 本地、网络存储
  2. 数据库访问:切换数据库
  3. 协议选择

单例模式

一个类只有一个实例,并且提供访问这个对象的方式

  1. 生成唯一ID
  2. 计数器

代理模式

通过引入一个代理对象来控制对原对象的访问,代理对象在客户端和目标对象之间充当中介,负责将客户端的请求转发给目标对象,同时在转发请求前后进行额外的处理。

  1. AOP
  2. 火车票代售

与适配器模式区别:适配器改变接口,代理不改变
与装饰器模式区别:装饰器用于增强功能,代理用于控制访问

适配器模式

充当两个不兼容接口之间的桥梁,通过适配器将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作

  1. 跨平台运行
  2. xml转json

装饰器模式

向一个现有的对象添加新功能,同时不改变其结构

模板模式

抽象类定义方法模板,子类按需重写方法实现,调用方式按抽象类定义执行


场景题

设计秒杀

静态资源放cdn
F5

nginx

open feign
↓ sentinel和mq 限流
服务
预热:把商品放入redis
库存:lua脚本操作
放重:setnx token或IP同一时间一个有效
分布式锁:请求原子性

数据库读写分离

订单超时自动取消

JDK自带延迟队列 DelayQueue 简单 不适合分布式
MQ延时消费 MQ接到消息会在指定时间通知消费端去处理 支持分布式 24小时内
redis过期监听 不可靠
定时任务分布式批处理 批量捞取

防重复下单

网页按钮置灰
redis setnx 过期3-5s 用户token+商品URL+key(下单)

防刷单

用风控
提高门槛:实名认证,消费门槛
限制用户参与、中奖次数
根据用户历史行为,提供不同的优惠
限流,自动扩容伸缩
黑名单
大数据用户画像

扫码登录

  1. 生成QR:生成二维码ID,保存二维码ID状态到redis,设置过期时间,用轮询或长连接查询二维码状态
  2. 扫码:APP扫码,校验用户token,变更二维码状态,绑定二维码ID和临时token
  3. 确认登录:检验临时token,执行登录,生成PC token

redis 记录连续登录几天

redis bitmap
key:日期 位:用户ID
key:用户 位:日期

一亿个redis key 统计共同好友

SINTERSTORE 取交集
Neo4j
Hbase+Hadoop

拆微服务

  1. 微服务之间不要有业务交叉
  2. 微服务之间用接口访问
  3. 高内聚 低耦合
    DDD 面对软件复杂之道

MQ保证消息不丢失

生产者发送:发送+回调 事务消息 手动事务
主从同步:1.同步-收到消息立即同步到从节点 2.异步-收到消息先响应生产者,后同步从节点
写入磁盘:同步、异步刷盘
消费者消费:事务完成后,提交offset

设计一个高效的会议室预订方案,快速返回一间空的会议室

数据结构

使用HashMap<Integer, List>记录每个会议室的预定情况

判断一个会议室是否空闲

  • 新请求的开始时间 >= 已有时间段的结束时间
  • 新请求的结束时间 <= 已有时间段的开始时间

对每个会议室的预定时间进行排序,利用 二分查找 提高查询效率

如何保证redis和mysql的一致性

延迟双删策略

  1. 先删除缓存
  2. 更新数据库
  3. 等待一段时间,再次删除缓存(确保脏数据不会回写)

基于MySQL binlog订阅

  1. MySQL主库更新数据后,binlog记录变更日志
  2. Redis监听binlog,并同步更新缓存

事务+消息队列(MQ)保证最终一致性

  1. 数据库更新和消息队列发送放入同一个事务,保证数据库变更后一定会有一个同步消息。
  2. 消息队列消费后,再更新Redis,保证最终一致性。

小内存如何排序大数据

分组查询数据,每一组单独排序后存入文件,同时读取各组文件,将每组文件的数据按顺序放入败者树中,每一个叶子节点对应一个文件,若该节点的数据胜出,则读取下一个数据,胜出的数据放入一个新文件,直到各组文件读取完毕。
败者树