我们在生产中会遇到这样的场景:
1:接口限速:针对每个接口分不同维度的限制调用次数:
如:请求url -/order/xxx/ , -/stock/xxx//
A接口限制 200次/分钟,1000次/小时,10000次/天
B接口限制 300次/分钟,2000次/小时,50000次/天
那么我们怎么设计这套服务那,
第一步设计后台管理功能,支持针对不同的接口设置不同维度的限制规则。 存储到redis中
第二步设计规则控制引擎:首先想到用分布式redis 存储规则后,针对每种规则生成计数器,每个计数器都设置相应的过期时间,在过期时间内的计数都是有效的。超过访问计数阈值或者次数减为零,则认为访问无效做无效处理。
这样做看似没有问题但是针对大型的开放平台来说调用量是海量的,redis本身的吞吐将成为瓶颈。如果是小型网站是可以采用这种方案的。
那么如何解决这个问题那,我们想能不能用内存缓存来做那,这样我们用每个应用服务的本地缓存来记录规则和来计数就不会有分布式缓存的瓶颈了。那么本地缓存又存在数据如何持久化,保证一致性的问题,一般我们都是用应用的本地缓存来做读服务,那么针对这种计数服务也用应用的本地缓存的话就要考虑是否可以牺牲严格的一致性问题,只要保证最终相对一致性就可以, 我们从全局分析这个场景其实是没有那么严格的要求一定要保证强一致性的,好了我们看怎么来这几这套架构吧:
第一:要考虑我们的服务一定是分布式部署多台的,那么每个上面都是全量数据,就限制不住了,相当于N倍的计数,还有一种方案就是在负载均衡层做hash保证同一个接口总是命中同一个服务,那么服务又成了单点。
第二,怎么破,我们用redis存储全量数据,然后我们事先预估我们部署了几个服务,那么我们每个服务只从redis中将自己分到的那部分减掉,以此类推,这样每个服务就差不多均匀啦,如果还有剩余那么某个服务消耗完之后再去缓存中去取,直到减为零,这个也有个问题那就是可能偶尔会提示用户调用资源不足,但是再次调用打到其他服务上,可能又可以了,不过没关系,我们这样已经保证了海量调用的可靠和性能,牺牲一些一致性也是没办法的事情,这个用户容忍度应该可以接受,
场景二,再有黑白名单的场景,也可以用这个方式不过还得借助zk,在注册zk的时候添加Watcher 事件来监听此节点的变化,当节点来时再看会通知watcher列表中正在监听此节点的所有机器实现时刷新黑白名单的切换
下图为引用小灰的图: watcher 过程
场景三,全局唯一订单号,每个业务的当前最大单号都存在mysql或者redis中,是一天记录,每个应用服务按照规则每次加锁后取出一定的号段,放到本地内存,这样每次从本地内存就可以获取到订单号啦,非常高效,但是这样如果有某一台服务挂了,会浪费一些单号,不过也是可以忍受的,如果怕浪费的多可以把偏移量设置的小一些
网友评论