0%

系统设计问题记录

记录遇到的系统设计问题,如内部支撑系统、2B的数据服务系统以及通用的系统设计问题

系统设计问题记录

常规敏捷开发流程

  1. 产品Story需求确认,制定Epic里程碑
  2. 产品交互原型设计
  3. 后端API接口设计确认/后端数据模型设计
  4. Story任务分解
  5. 前后端各自编码实现

迭代上述过程

衡量项目质量的指标

  1. 功能:功能目标是应用的基本要求,如果不能实现既定的功能逻辑,应用就失去了存在的意义,因此实现产品需求是应用的基本的目标。
  2. 性能:在基本的功能之上,会有一些性能的要求,但是很少有产品经理或者用户能提前提出这样的要求,因此架构师要有丰富的经验去发现和解决(或者为未来提升性能做准备)性能问题。
    性能的主要衡量有:单次请求的相应时间,单实例请求并发数,服务最大并发量等。
  3. 扩展性:目前互联网应用的开发模式:提出需求,快速响应,迭代开发,尽快上线

架构设计的主要过程

  1. 确定问题域:根据需求定位关键问题,需根据性能和扩展性定义问题域;如何平衡性能和扩展的关系,是架构师设计的关键。扩展把握关键问题,优先满足关键问题的性能,确定最小功能集;确定最小功能集的优势可以快速实现,快速验证需求的准确性,每次需求开发都完成最小和最关键的需求
  2. 数据建模:StarUML,ER
  3. 模块划分:单实例结构(应用>DB);集群结构;分布式结构(显示层>服务n>DB) ;混合结构;
  4. 关键流程描述:检查系统架构是否满足需求和指导开发的必要条件。使用流程图解决关键问题
  5. 技术选型
  6. 代码实现
  7. 验收测试

内部系统类

B2B的支付机制

  • 流程:记账->账单->扣款;
  • 记账:业务系统异步写入操作记录;
  • 账单:根据计费逻辑(折扣/套餐/阶梯)以存储过程生成账单;
  • 扣款:运营月结/日结+法务催收;

系统耦合问题

问题:业务系统与基础设施系统(Boss)强耦合,Boss缓存问题影响业务系统鉴权;
方案:Boss数据库单点,缓存多点实时同步;业务系统读取本地缓存进行鉴权;

数据服务类

渠道分流控制工具/自动分流工具

需求:渠道调用超时自动切换,渠道恢复正常自动切换;
分析:1个服务对应多个提供者,多个提供者可配置权重,要求多个提供者之间可根据超时时间down或者on
技巧:超时时间=接口平均调用时间*2

保证主流程用户体验,减少故障点

梳理主流程,区分立即一致和最终一致,最终一致的业务逻辑可以消息中间件异步执行,以减少主流程阻塞时间;

eg 在实名验证+人脸比对前,异步调用防骇客接口;在认证结束时,从缓存获取防骇客接口调用结果,若检测到活体攻击,进入人审;若无攻击,正常返回;

认证结果通知机制

认证结果通知:SDK端同步返回和服务端异步返回,SDK同步返回时需支持敏感字段掩码(开关);
实时性要求不高,提供异步通知接口;实时性要求高,提供认证结果查询接口;
1)异步通知双层设计:
第一层:实时通知,设置正常超时时间(3S)且不重试,不论通知成功与否,都写表记录通知结果标识;
第二层:扫描异步通知表,对未成功通知的记录进行重试通知(3次,重试时间递增)
2)异步通知:商户异步通知地址不能保证Https,数据需加密传输
3)认证结果查询接口:独立查询库

通用问题

异常处理

调用外部服务异常时打印所有日志;
自定义异常,在最外围捕捉抛出

网络超时问题

从三个关键点排查

  1. 对端:TCP握手问题
  2. 数据传输:
  3. 读取结果:readTimeout的实际含义
    the read timeout is that it corresponds to the timeout on a socket read.
    So it’s not the time allowed for the full response to arrive, but rather the time given to a single socket read.
    So if there are 4 socket reads, each taking 9 seconds, your total read time is 9 * 4 = 36 seconds.
    http://stackoverflow.com/questions/9873810/using-apache-httpclient-how-to-set-the-timeout-on-a-request-and-response

HttpClient超时类型

  1. connectionRequestTimeout:从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
  2. connectTimeout:连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
  3. socketTimeout:服务器返回数据(response)的时间,超过该时间抛出read timeout

线程池使用场景

  1. 节省时间,多个线程并行处理后返回,如双重比对
  2. 异步任务,不影响主流程

输入提示服务

高并发系统的设计,关键在合理的数据结构的设计,而不在架构的套用

缓存+哈希

把搜索的搜索提示词存在redis集群中,每次来了请求直接redis集群中查找key,然后返回相应的value值就行了,完美解决,虽然耗费点内存,但是空间换时间嘛;

trie树

这种搜索提示的功能一般用trie树来做,耗费的内存不多,查找速度为O(k),其中k为字符串的长度,虽然看上去没有哈希表的O(1)好,但是少了网络开销,节约了很多内存,并且实际查找时间还要不比缓存+哈希慢多少,
一种合适当前场景的核心数据结构才是高并发系统的关键,缓存+哈希如果也看成一种数据结构,但这种数据结构并不适用于所有的高并发场景。

LRU缓存

LRU是Least Recently Used 近期最少使用算法;
硬盘上有N条数据,并且有一个程序包,提供GET和SET方法,可以操作磁盘读写数据,但是速度太慢,请设计一个内存中的数据结构,也提供GET和SET方法,保存最近访问的前100条数据,这个数据结构就是一个LRU了,让面试者实现出来,如果觉得写代码麻烦,可以把数据结构设计出来描述一下就行了,就这样,还很多人不会,这怎么能说是对缓存技术有深入了解呢?就这样,怎么能说有过大型高并发系统的经验呢?这只是开源工具的使用经验罢了。

常用容错机制

常见容错机制:failover ,failsafe,failfase ,failback,forking,来源于阿里的定义

  • Failover 失败自动切换
    当出现失败,重试其它服务器,通常用于读操作(推荐使用)。 重试会带来更长延迟。
  • Failfast 快速失败
    只发起一次调用,失败立即报错,通常用于非幂等性的写操作。 如果有机器正在重启,可能会出现调用失败 。
  • Failsafe 失败安全
    出现异常时,直接忽略,通常用于写入审计日志等操作。 调用信息丢失 可用于生产环境 Monitor。
  • Failback 失败自动恢复
    后台记录失败请求,定时重发。通常用于消息通知操作 不可靠,重启丢失。 可用于生产环境 Registry。
  • Forking 并行调用多个服务器
    只要一个成功即返回,通常用于实时性要求较高的读操作。 需要浪费更多服务资源 。
  • Broadcast
    广播调用,所有提供逐个调用,任意一台报错则报错。通常用于更新提供方本地状态 速度慢,任意一台报错则报错 。