Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

RemoteMountain/DesignPattern

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
26 Commits
 
 
 
 
 
 
 
 

Repository files navigation

DesignPattern

设计模式之美 https://time.geekbang.org/column/intro/100039001?tab=catalog

虚拟钱包

钱包系统分为虚拟钱包和三方支付

功能清单

  • 充值
  • 提现
  • 支付
  • 查询余额
  • 查询交易流水

基于贫血模型的MVC开发模式

基于充血模型的DDD开发模式

接口鉴权

需求:只有鉴权通过的请求可以调用接口api

分析

  • 调用方进行接口请求的时候,将 URL、AppID、密码、时间戳拼接在一起,通过加密算法生成 token,并且将 token、AppID、时间戳拼接在 URL 中,一并发送到微服务端。
  • 微服务端在接收到调用方的接口请求之后,从请求中拆解出 token、AppID、时间戳。
  • 微服务端首先检查传递过来的时间戳跟当前时间,是否在 token 失效时间窗口内。如果已经超过失效时间,那就算接口调用鉴权失败,拒绝接口调用请求。
  • 如果 token 验证没有过期失效,微服务端再从自己的存储中,取出 AppID 对应的密码,通过同样的 token 生成算法,生成另外一个 token,与调用方传递过来的 token 进行匹配。如果一致,则鉴权成功,允许接口调用;否则就拒绝接口调用。

设计与实现

根据需求描述拆分功能点

  1. 把URL、AppID、密码、时间戳拼接形成字符串
  2. 对字符串通过加密算法加密生成token
  3. 将 token、AppID、时间戳拼接到 URL 中,形成新的 URL;
  4. 解析 URL,得到 token、AppID、时间戳等信息;
  5. 从存储中取出 AppID 和对应的密码;
  6. 根据时间戳判断 token 是否过期失效;
  7. 验证两个 token 是否匹配;

积分兑换系统

需求定义

积分赚取和兑换规则

1、根据订单金额定义可兑换积分比例 100元的订单可以兑换10积分,兑换比例为10% 2、评论换取积分 评论后可获得1积分 3、每日签到兑换积分 签到后可获得1积分

积分消费和兑换规则

1、积分换算为订单金额比例 10积分可兑换1元,兑换比例为10% 2、积分兑换优惠券 100积分可兑换10元的优惠券 3、积分换购 1w积分可换购100元的商品

积分及其明细查询

查询用户的总积分,以及赚取积分和消费积分的历史记录。

系统(模块)划分

1、订单系统 --》 营销系统 --》积分系统(仅包括积分的增删改查,兑换规则在营销系统中)

2、订单系统 --》 积分系统(仅包括积分的增删改查,兑换规则在订单等系统中)

3、订单系统 --》 积分系统(包括积分的增删改查,积分兑换规则)

按照 系统设计的高内聚 低耦合 以及上层系统可以依赖下层系统, 下层系统不可依赖上层系统的原则 ,选择方案1或2

系统交互

同层系统异步调用(如:基于消息系统解耦),上下层系统同步调用,此原则也是为了系统解耦。 同层系统可能存在相互依赖,通过消息队列异步调用解耦。 而,上下层系统,一般不存在相互依赖,只有上层系统依赖下层系统,则可以同步调用。

设计系统(模块)接口、数据库、业务模型

积分系统可以单独形成一个项目,也可以是营销系统一个模块,根据目前架构实际情况而定。

接口

  • 兑换积分
  • 消费积分
  • 查询总可用积分
  • 查询兑换的积分明细
  • 查询消费的积分明细

数据库

积分明细表

  • id
  • userId
  • 积分 正值表示兑换 负值表示消费
  • 渠道id 如 订单、评论、每日签到、优惠券、积分商城等
  • 事件id 如 订单id、评论id、优惠券id等
  • create_time 积分赚钱或消费时间
  • expired_time 积分过期时间

接口性能计数器

项目背景

开发一个小的框架,能够获取接口调用的各种统计信息,比如,响应时间的最大值(max)、最小值(min)、平均值(avg)、 百分位值(percentile)、 接口调用次数(count)、频率(tps) 等, 并且支持将统计结果以各种显示格式(比如:JSON 格式、 网页格式、自定义显示格式等)输出到各种终端(Console 命令行、HTTP 网页、Email、日志文件、自定义输出终端等),以方便查看。

开发这样一个通用的框架,应用到各种业务系统中,支持实时计算、查看数据的统计信息,如何设计和实现呢?

需求分析

功能性需求分析

  • 接口统计信息:包括接口响应时间的统计信息,以及接口调用次数的统计信息等。

  • 统计信息的类型:max、min、avg、percentile、count、tps 等。

  • 统计信息显示格式:Json、Html、自定义显示格式。

  • 统计信息显示终端:Console、Email、HTTP 网页、日志、自定义显示终端。

  • 统计触发方式:包括主动和被动两种。主动表示以一定的频率定时统计数据,并主动推送到显示终端,比如邮件推送。被动表示用户触发统计,比如用户在网页中选择要统计的时间区间,触发统计,并将结果显示给用户。

  • 统计时间区间:框架需要支持自定义统计时间区间,比如统计最近 10 分钟的某接口的 tps、访问次数,或者统计 12 月 11 日 00 点到 12 月 12 日 00 点之间某接口响应时间的最大值、最小值、平均值等。

  • 统计时间间隔:对于主动触发统计,我们还要支持指定统计时间间隔,也就是多久触发一次统计显示。比如,每间隔 10s 统计一次接口信息并显示到命令行中,每间隔 24 小时发送一封统计信息邮件。

非功能性需求分析

  • 易用性

框架要容易集成到业务系统、易插拔、不与业务系统耦合、 接口是否灵活, 文档的好坏也会影响到框架的易用性

  • 性能

  • 扩展性

  • 容错性

容错性这一点也非常重要。对于性能计数器框架来说, 不能因为框架本身的异常导致接口请求出错。所以, 我们要对框架可能存在的各种异常情况都考虑全面, 对外暴露的接口抛出的所有运行时、非运行时异常 都进行捕获处理。

  • 通用性

框架设计

先基于简单的场景,基于此设计实现一个简单的原型。 比如,统计登录、注册两个接口的响应时间最大值和平均值、 接口调用次数, 并且将结果以json格式输出到命令行中。

模块划分

  • 数据采集
  • 数据存储
  • 聚合统计
  • 显示

版本迭代

小步快跑、逐步迭代

v1版本

  • 数据采集:负责打点采集原始数据,包括记录每次接口请求的响应时间和请求时间。
  • 存储:负责将采集的原始数据保存下来,以便之后做聚合统计。数据的存储方式有很多种,我们暂时只支持 Redis 这一种存储方式,并且,采集与存储两个过程同步执行。
  • 聚合统计:负责将原始数据聚合为统计数据,包括响应时间的最大值、最小值、平均值、99.9 百分位值、99 百分位值,以及接口请求的次数和 tps。
  • 显示:负责将统计数据以某种格式显示到终端,暂时只支持主动推送给命令行和邮件。命令行间隔 n 秒统计显示上 m 秒的数据(比如,间隔 60s 统计上 60s 的数据)。 邮件每日统计上日的数据。

1. 划分职责进而识别出有哪些类

  • MetricsCollector 类负责提供 API,来采集接口请求的原始数据。我们可以为 MetricsCollector 抽象出一个接口,但这并不是必须的,因为暂时我们只能想到一个 MetricsCollector 的实现方式。
  • MetricsStorage 接口负责原始数据存储,RedisMetricsStorage 类实现 MetricsStorage 接口。这样做是为了今后灵活地扩展新的存储方法,比如用 HBase 来存储。
  • Aggregator 类负责根据原始数据计算统计数据。
  • ConsoleReporter 类、EmailReporter 类分别负责以一定频率统计并发送统计数据到命令行和邮件。至于 ConsoleReporter 和 EmailReporter 是否可以抽象出可复用的抽象类,或者抽象出一个公共的接口,我们暂时还不能确定。

2. 定义类及类与类之间的关系

统计和显示所要完成的功能逻辑

  1. 根据给定的时间区间,从数据库中拉取数据;
  2. 根据原始数据,计算得到统计数据;
  3. 将统计数据显示到终端(命令行或邮件);
  4. 定时触发以上 3 个过程的执行。

v2版本

在v1版本的基础上,将性能计数器划分为几个部分,但是其中存在一些问题:

  1. Aggregator 类代码有点多,当需要新增或修改统计方式,会不断增加代码,影响代码可读性和可维护性
  2. ConsoleReporter 类、EmailReporter 类 存在代码重复问题:拉取一段时间的数据,调用Aggregator 类获取统计数据,这部分逻辑需要合并,不然违反了DRY原则
  3. ConsoleReporter 类、EmailReporter 类 既有统计逻辑也有显示逻辑,特别是EmailReporter 类,组装成xml比较复杂。因此需要将统计逻辑和显示逻辑分离,这样违反了SRP原则
  4. ConsoleReporter 类、EmailReporter 类的代码中设计线程操作,并且调用Aggregator 类的静态函数,代码可测试性不高

针对V1的重构

Aggregator 类和 ConsoleReporter、EmailReporter 类主要负责统计显示的工作。 如果我们把统计显示所要完成的功能逻辑细分一下,主要包含下面 4 点:

  1. 根据给定的时间区间,从数据库中拉取数据;
  2. 根据原始数据,计算得到统计数据;
  3. 将统计数据显示到终端(命令行或邮件);
  4. 定时触发以上三个过程的执行。

具体的重构工作:

  1. 根据给定时间区间,从数据库中拉取数据。这部分逻辑已经被封装在 MetricsStorage 类中了,所以这部分不需要处理。
  2. 根据原始数据,计算得到统计数据。我们可以将这部分逻辑移动到 Aggregator 类中。这样 Aggregator 类就不仅仅是只包含统计方法的工具类了。
  3. 将统计数据显示到终端。我们将这部分逻辑剥离出来,设计成两个类:ConsoleViewer 类和 EmailViewer 类,分别负责将统计结果显示到命令行和邮件中。

v2重构后的问题

  1. EmailReporter类和ConsoleReporter仍然存在代码重复问题,且都用使用到多线程,因而代码可测试性不好
  2. 框架易用性不高,创建EmailReporter类和ConsoleReporter过程比较复杂

About

设计模式之美

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.