你好,我是田哥
最近,我在对充电桩项目进行微服务升级中,肯定会遇到一些问题
前面分享了:充电桩项目实战:搞定多数据源!
登录界面
在做充电桩项目时,其中用户的登录、注册等都需要用到短信这个功能,所以,我们在开发之前要做一些相对深入的考虑。
比如:
- 短信模板如何存储?
- 常见存储方式有哪些?
- 用户发送次数是否要限制?
- 如何限制?
短信发送后,采取的了60秒后能再次重发,这么设计还有个好处,就是规避有些人恶意攻击系统,频繁发送短信,短信一条也就几分钱,但是量上来了,这个成本就不能小看了。
通常3分/条,如果100条那就是3块,10000条就是300块,100w条那就是3万块
但是,这个60秒也还不能完全杜绝这类事情发生,只是说这个量级变了,一个用户每隔60秒发一次,一小时就可以发60次,一条24*60=1440次,10个用户都这么恶搞,那就是每天短信成本变成:
每天10个用户恶搞,14400*3=43200,换算下来432,恶搞一个月就是
432*30
= 一万多了。
所以,我们还可以对用户进行每天次数限制,每月次数限制。比如:每天每个用户的某个功能发短信的次数限制在8次,或者20次。至少也能规避掉前面带来的问题。
其实,上述问题也可以说不能完全规避掉,只能说在不影响用户使用的前提下,我们可以尽可能规避。所以,我们可以采取一个分布式限流技术,就是每一个用户每天或者每分钟或每小时,最多只能发送xx次-----限流。
分布式限流解决方案
分布式限流方案有以下几种:
1. 基于令牌桶算法的限流
● 优点:实现简单,算法成熟,可以平滑限流请求,具有较高的容错性和稳定性。
● 缺点:限流粒度较粗,无法应对瞬时流量突增的情况。
● 适用场景:对于不需要严格限制每个请求的时间间隔的情况,可以使用基于令牌桶算法的限流方案。
2. 基于漏桶算法的限流
● 优点:实现简单,可以平滑限流请求,具有较高的容错性和稳定性。
● 缺点:限流粒度较粗,无法应对瞬时流量突增的情况。
● 适用场景:对于不需要严格限制每个请求的时间间隔的情况,可以使用基于漏桶算法的限流方案。
3. 基于计数器的限流
● 优点:实现简单,可以较为准确地控制请求的速率。
● 缺点:无法平滑限流请求,容易因瞬时流量突增而导致系统压力过大。
● 适用场景:对于需要严格控制每个请求的时间间隔的情况,可以使用基于计数器的限流方案。
4. 基于分布式缓存的限流
● 优点:可以分布式地存储和管理限流规则,适用于大规模分布式系统。
● 缺点:需要依赖分布式缓存系统,增加了系统的复杂性。
● 适用场景:对于需要分布式地管理限流规则的大规模系统,可以使用基于分布式缓存的限流方案。
5. 基于流量控制网关的限流
● 优点:可以集中管理和控制流量,支持多种限流策略,适用于大规模分布式系统。
● 缺点:需要引入额外的流量控制网关,增加了系统的复杂性。
● 适用场景:对于需要集中管理和控制流量的大规模系统,可以使用基于流量控制网关的限流方案。
不同的限流方案适用于不同的场景,我们需要根据具体的业务需求和系统架构来选择合适的方案。假设我们采用每小时用户最多只能发送6次短信,那我们可以采取滑动窗口来解决。
关于滑动窗口模型图:
滑动窗口
在我们的充电桩项目中,采用的是Redisson来实现限流的。
代码语言:javascript复制 public boolean limitBySlidingWindow(String key,long rate, long rateInterval, RateIntervalUnit rateIntervalUnit) {
RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
rateLimiter.trySetRate(RateType.OVERALL, rate, rateInterval, rateIntervalUnit);
if (rateLimiter.tryAcquire()) {
return false;
} else {
// 触发限流处理
return true;
}
}
trySetRate()方法参数介绍
- RateType mode:速率类型,表示限流的模式,例如固定速率(Fixed)或滑动窗口速率(Sliding Window)。
- long rate:速率值,表示每秒允许的请求数量。
- long rateInterval:速率间隔,表示滑动窗口的时间长度,单位由 rateIntervalUnit 参数指定。
- RateIntervalUnit rateIntervalUnit:速率间隔单位,表示滑动窗口时间长度的单位,例如秒(Seconds)、分钟(Minutes)等。这里可能很多人不太理解这个速率类型,下面来聊聊速率类型的区别。
速率类型
固定速率(Fixed)和滑动窗口速率(Sliding Window)是两种常见的限流算法,它们在实现上有一些区别。
1. 固定速率(Fixed):
- 原理:固定速率算法根据预设的速率限制来控制请求的处理速度。它通过设置一个固定的请求处理时间间隔,确保在单位时间内只处理一定数量的请求。
- 示例:假设我们有一个API接口,我们希望限制每秒最多只能处理10个请求。使用固定速率算法,我们可以设置一个时间间隔为100毫秒,即每个请求之间至少需要等待100毫秒才能被处理。这样,即使有大量请求同时到达,我们也只会在每100毫秒内处理一个请求,从而保证不超过每秒10个请求的限制。
2. 滑动窗口速率(Sliding Window):
- 原理:滑动窗口算法通过维护一个时间窗口来控制请求的处理速度。它将时间划分为多个小的时间窗口,每个窗口都有一个对应的请求处理数量限制。当请求到达时,会根据当前时间所在的窗口来决定是否允许处理该请求。
- 示例:假设我们仍然希望限制每秒最多只能处理10个请求。使用滑动窗口算法,我们可以将时间划分为1秒内的10个等长的小窗口,每个窗口持续100毫秒。每个窗口都有一个计数器,用于记录在该窗口内处理的请求数量。当一个新的请求到达时,我们会检查当前时间所在的窗口,如果该窗口的计数器未达到限制(例如10个请求),则允许处理该请求,并将计数器加一;否则,拒绝该请求。随着时间的流逝,每个窗口都会逐渐向前滑动,旧的窗口将被丢弃,新的窗口将被创建,从而实现对请求的处理速度进行限制。
总结:固定速率算法通过设置固定的请求处理时间间隔来限制请求的处理速度,而滑动窗口算法通过维护一个时间窗口来控制请求的处理速度。两者都可以实现对请求的处理速度进行限制,但具体实现方式和效果略有不同。
估计很多人看了这段话还是不太清楚我们到底要选择哪一种?
两种速率的优缺点
固定速率的优点:
● 实现简单:固定速率算法的实现相对简单,只需要设置一个时间间隔,确保每个请求之间有足够的处理时间。
● 预测性强:由于时间间隔是固定的,所以可以很容易地预测系统的处理能力,便于进行资源规划和分配。固定速率的缺点:
● 不够灵活:在高并发情况下,固定速率可能会导致资源浪费,因为它不考虑实际的请求情况,即使请求量减少,也会保持相同的处理速度。
● 无法应对突发流量:当遇到突发流量时,固定速率可能无法及时响应,因为它不能根据实际情况动态调整处理速度。
滑动窗口速率的优点:
● 灵活性高:滑动窗口算法可以根据实际的请求情况动态调整处理速度,更加灵活地应对不同的流量模式。
● 资源利用率高:通过动态调整时间窗口的大小,滑动窗口算法可以更有效地利用系统资源,避免在请求量少时的资源浪费。
滑动窗口速率的缺点:
● 实现复杂:相比于固定速率,滑动窗口算法的实现更为复杂,需要考虑窗口的大小和滑动的策略。
● 性能开销大:由于需要维护一个时间窗口的数据结构,滑动窗口算法可能会引入额外的性能开销。
总的来说,固定速率算法适合对处理速度要求较为稳定的场景,而滑动窗口速率算法则更适合对处理速度有较高灵活性要求的场景。
短信模块设计
在充电桩项目中短信模块设计,整体流程如下
短信模块设计
用到了策略模式和模板方法模式。关于策略模式和模板方法模式之前我已经分享过,所以,参考之前的文章即可。