随着互联网的发展, 各项软件的客户量日益增多, 当客户量达到一定峰值时, 当数以万计的流量来临时, 程序的顺利运行以及即时响应则显得尤为重要, 就像双 11 那天的淘宝一样. 那么, 如何设计架构才能够抗住这千万级的流量.
首先, 要在我们架构设计的时候建立一些原则.
1. 实现高并发
服务拆分: 将整个项目拆分成多个子项目或者模块, 分而治之, 将项目进行水平扩展.
服务化: 解决服务调用复杂之后的服务的注册发现问题.
消息队列: 解耦, 异步处理
缓存: 各种缓存带来的并发
2. 实现高可用
集群, 限流, 降级
3. 业务设计
幂等: 就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的, 不会因为多次点击而产生了副作用, 就像数学里的数字 1, 多少次幂的结果都是 1. 举个最简单的例子, 那就是支付, 用户购买商品后支付, 支付扣款成功, 但是返回结果的时候网络异常, 此时钱已经扣了, 用户再次点击按钮, 此时会进行第二次扣款, 返回结果成功, 用户查询余额发现多扣钱了, 流水记录也变成了两条...
详细内容参考 分布式中的幂等性https://www.cnblogs.com/vveiliang/p/6643874.html
防重: 防止同样的数据同时提交
除了在业务方向判断和按钮点击之后不能继续点击的限制以外, 在服务器端也可以做到防重:
在服务器端生成一个唯一的随机标识号 (Token < 令牌>) 同事在当前用户的 Session 域中保存这个令牌, 然后将令牌发送到客户端的 form 表单中, 在 form 表单中使用隐藏域来存储这个 Token, 表单提交的时候联通这个 Token 一起提交到服务器, 然后在服务器端判断客户提交上来的 Token 与服务器端生成的 Token 是否一致, 如果不一致, 那就重复提交了, 此时服务器端就可以不处理重复提交的表单, 如果相同则处理表单, 处理完后清楚当前用户的 Session 域中存储的标识号.
在下列情况中, 服务器程序将拒绝处理用户提交的表单请求:
1)存储 Session 域中的 Token 与表单提交的 Token 不一致
2)当前用户的 Session 中不存在 Token
3)用户提交的表单数据中没有 Token.
状态机
软件设计中的状态机概念, 一般是指有限状态机 (英语: finite-state machine, 缩写: FSM) 又称有限状态自动机, 简称状态机, 是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.
这里着重讲一下限流的概念和例子
限流的目的:
限流的目的是通过对并发访问 / 请求进行限速或者一个时间窗口内的请求进行限速来保护系统的可用性, 一旦达到限制速率就可以拒绝服务. 就像手机预售一样, 假如要卖出 3 万台, 只需要接收 3 万用户的请求就可以, 其他的用户请求可以选择过滤, 可以提示 "当前服务器过忙, 请稍后再试" 的提示.
限流方式:
1. 限制瞬时并发数 : 比如在入口层 (nginx 添加 nginx_http_limit_conn_module) 来限制同一个 ip 来源的连接数, 防止恶意攻击访问的情况.
2, 限制总并发数: 通过配置数据库连接池, 线程池大小来约束总并发数
3. 限制时间窗口内的平均速率: 在接口层面, 通过限制访问速率来控制接口的并发请求.
4. 其他方式: 限制远程接口的调用速率, 限制 MQ 的消费速率.
常用限流算法
1. 滑动窗口协议: 一种常见的流量控制技术, 用来改善吞吐量的技术.
滑动窗口协议的由来:
滑动窗口 (sliding window) 是一种流量控制技术. 早期的网络通讯中, 通信双方不会考虑网络的拥挤情况直接发送数据. 由于大家不知道网络拥塞状况, 同时发送数据, 导致中间节点阻塞掉包, 谁也发送不了数据, 所以就有了滑动窗口机制来解决此问题. 发送和接收方都会维护一个数据帧的序列, 这个序列被称为窗口.
定义: 滑动窗口协议(Sliding Window Protocol), 属于 TCP 协议的一种应用, 用于网络数据传输时的流量控制, 以避免拥塞的发生. 该协议允许发送方在停止并等待确认前发送多个数据分组. 由于发送方不必每发一个分组就停下来等待确认, 因此该协议可以加速数据的传输, 提高网络吞吐量.
发送窗口: 就是发送端允许连续发送的帧的序号表. 发送端可以不等待应答而连续发送数据(可以通过设置窗口的尺寸来控制)
接收窗口: 接收方允许接收的帧的序列表, 凡是落在接收窗口内的帧, 接收方都必须处理, 落在接收窗口外的帧将被丢弃. 接收方每次允许接收的帧数称为接收窗口的尺寸
演示地址: https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html
2. 漏桶: 漏桶算法能强行限制数据的传输速率.
漏桶算法思路很简单, 请求先进入到漏桶里, 漏桶以一定的速度出水. 当水请求过大会直接溢出, 可以看出漏桶算法能强行限制数据的传输速率. 进入端无需考虑出水端的速率, 就像 mq 消息队列一样, provider 只需要将消息传入队列中, 而不需要关心 Consumer 是否接收到了消息.
对于溢出的水, 就是被过滤的数据, 可以直接被丢弃, 也可以通过某种方式暂时保存, 如加入队列之中, 像线程池里对溢出数据的 4 种处理机制一样
3. 令牌桶: 属于控制速率类型的限流算法.
对于很多应用场景来说, 除了要求能够限制数据的平均传输速率外, 还要求允许某种程度的突发传输. 这时候漏桶算法可能就不合适了, 令牌桶算法更为适合. 令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌, 而如果请求需要被处理, 则需要先从桶里获取一个令牌, 当桶里没有令牌可取时, 则拒绝服务.
设置 Rate = 2 : 每秒放入令牌的个数
桶的大小: 100
4. 计数器: 最简单的一种. 通过控制时间段内的请求次数.
未完待续...
来源: https://www.cnblogs.com/GodHeng/p/8834810.html