一、接口安全性校验
-
签名
根据用户名或者用户id,结合用户的ip或者设备号,生成一个token。在请求后台,后台获取http的head中的token,校验是否合法(和数据库或者Redis中记录的是否一致,在登录或者初始化的时候,存入数据库/redis)
-
加密
加密的算法可以有很多种选择,常用的可以使用RSA256,在对需要发送的数据按照某一定制好的key进行加密之后,生成一个加密结果集(sign)和数据一起发送
接口服务方在接受到数据之后,按照同样的方式进行加密,这里使用的key在对称加密的情况下可以使用和客户端一样的key,然后将加密后的结果集和客户端的sign进行对比,如果是一致,表明数据没有被修改,验证通过 -
鉴权(是否具有该路径的访问权限)
这里可以使用比较成熟的解决方案JWT,配置JWT访问白名单存入redis等相关持久化数据库当中,在接口接收数据之前先进行路径比较,判断是否当前的路径具有访问的权限
-
幂等性校验
传统的重复性校验一般都是使用DB中的某一张table.利用table的唯一索引进行重复性校验。或者是使用redis,查询当前的key是否已经存在再验证是否通过
如果单纯的是某一种方式去实现,这里有一个比较明显的问题就是在数据量比较大的时候会有大量多余的累积的数据在db中,造成后续的校验查询速度变慢,影响项目整体的性能
鉴于之前我们的项目经验来看,我们这里在将数据如表的时候可以添加相关的规则,扩展出多张表,再映射对应出redis中的相关key值,结合redis和table做 幂等性校验,不仅可以扩展我们的数据存储,同时引入了redis也不会造成后续的查询缓慢问题
二、接口限流
-
限流相关算法介绍
做限流 (Rate Limiting/Throttling) 的时候,除了简单的控制并发,如果要准确的控制 TPS,简单的做法是维护一个单位时间内的 Counter,如判断单位时间已经过去,则将 Counter 重置零。
此做法被认为没有很好的处理单位时间的边界,比如在前一秒的最后一毫秒里和下一秒的第一毫秒都触发了最大的请求数,也就是在两毫秒内发生了两倍的 TPS。漏桶算法
漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率。可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。
令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解。随着时间流逝,系统会按恒定 1/QPS 时间间隔(如果 QPS=100,则间隔是 10ms)往桶里加入 Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了。新请求来临时,会各自拿走一个 Token,如果没有 Token 可拿了就阻塞或者拒绝服务。
令牌桶的另外一个好处是可以方便的改变速度。一旦需要提高速率,则按需提高放入桶中的令牌的速率。一般会定时(比如 100 毫秒)往桶中增加一定数量的令牌,有些变种算法则实时的计算应该增加的令牌的数量。
三、rabbitmq如何做到消息的顺序消费
-
什么事消息的顺序消费
消息的顺序性是指消费者消费到的消息和发送者发布的消息的顺序是一致的。举个例子,不考虑消息重复的情况,如果生产者发布的消息分别为1、2、3,那么消费者必然也是按照1、2、3的顺序进行消费的。
-
顺序消费的条件
1 首先,肯定需要确定的是我们的系统A,这里成为客户端,在发送数据的时候需要自己保证一个消息的顺序性
2 在进入队列的时候,我们需要保证之后一个通道连接一个队列,消费端也只能有一个消费者,如果存在多个消费者,那么默认rabbitmq的轮询消费模式是无法保证消息的顺序性消费的显然,这里的条件是比较苛刻的,实际生产中我们不能按照这样的方式去建立队列使用的,所以我们最好是在业务层自己去处理,比如我们可以手动的去添加一个有序标识(类似SequenceID)来实现。
-
破坏顺序消费的情况
1 如果生产者使用了事务机制,在发送消息之后遇到异常进行了事务回滚,那么需要重新补偿发送这条消息,如果补偿发送是在另一个线程实现的,那么消息在生产者这个源头就出现了错序。同样,如果启用publisher confirm时,在发生超时、中断,又或者是收到RabbitMQ的Basic.Nack命令时,那么同样需要补偿发送,结果与事务机制一样会错序。或者这种说法有些牵强,我们可以固执地认为消息的顺序性保障是从存入队列之后开始的,而不是在发送的时候开始。
2 考虑另一种情形,如果生产者发送的消息设置了不同的超时时间,并且也设置了死信队列,整体上来说相当于一个延迟队列,那么消费者在消费这个延迟队列的时候,消息的顺序必然不会和生产者发送消息的顺序一致。
3 再考虑一种情形,如果消息设置了优先级,那么消费者消费到的消息也必然不是顺序性的。如果一个队列按照前后顺序分有msg1、msg2、msg3、msg4这4个消息,同时有ConsumerA和ConsumerB这两个消费者同时订阅了这个队列。队列中的消息轮询分发到各个消费者之中,ConsumerA中的消息为msg1和msg3,ConsumerB 中的消息为msg2、msg4。ConsumerA 收到消息msg1之后并不想处理而调用了Basic.Nack/.Reject将消息拒绝,与此同时将requeue设置为true, 这样这条消息就可以重新存入队列中。消息msg1之后被发送到了ConsumerB中,此时ConsumerB已经消费了msg2、 msg4,之,后再消费msgl,这样消息顺序性也就错乱了。或者消息msg1又重新发往ConsumerA中,此时ConsumerA已经消费了msg3,那么再消费msg1,消息顺序性也无法得到保障。同样可以用在Basic. Recover这个AMQP命令中。
四、死信队列及相关的应用
-
什么是死信队列
死信队列&死信交换器:DLX 全称(Dead-Letter-Exchange),称之为死信交换器,当消息变成一个死信消息,
如果这个消息所在的队列存在x-dead-letter-exchange参数,那么它会被发送到x-dead-letter-exchange对应值的交换器上,这个交换器就称之为死信交换器,与这个死信交换器绑定的队列就是死信队列。死信消息:
1 消息被拒绝(Basic.Reject或Basic.Nack)并且设置 requeue 参数的值为 false
2 消息过期了
3 队列达到最大的长度 -
死信队列的应用
1 “生产者”(也可以是消费者再转发)把消息丢到一个无人消费的队列Q1,并为其设置存活时长,也就是需要延时的时长,例如10秒,
2 再为其设置消息死信交换机和死信路由,为了让消息死亡后可以通过设置的路由和路由键去往真正的消费队列Q2这里代码我就不写了,因为网上有太多现成的例子,大家知道怎么用就好
总结
关于rabbitmq的知识点还有很多,需要总结的也还有很多,前面介绍的接口的安全性以及限流等都是整合rabbitmq去使用的时候我曾经在项目中真实遇到过的,所以在这里也一并总结了一下