后端开发那些事(一)第三方接口限流了怎么办?

1,669 阅读2分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

前言

前段时间遇到这样一个问题,我们调第三方发短信接口,在业务峰值的时候,经常会有些短信没有发出去。找第三方排查之后发现,发短信接口接口限流了。原因是,发短信接口要求我们传一套账号密码,这个账号密码是第三方提供的。第三方针对这个账号密码做了限流,一套账号密码只有20QPS。尝试和第三方提供商沟通,看看能不能把我们这套账号密码的QPS提上去,得到的反馈是,20QPS是死的,无法针对某个账号来扩大,但是可以给我们提供多个账号。这里就不点名吐槽这个提供商了。咱们只能逆来顺受了。

分析

方案一 试错法

当使用第一套账号发送请求时,如果报了限流错误,捕获该错误。尝试用第二套账号发送请求,如果还报了限流错误,同样捕获错误用下一套账号发送请求。以此类推。 image.png

问题

很容易可以看出来,最坏的情况下,想要请求成功,需要请求n次。而且在业务高峰时,对于靠前的账号的压力会很大。而在业务低谷时,后面的账号几乎用不到。

方案二 顺序轮询(取模)

image.png

问题

首先需要有一个数字类型的id,且是有序的。才能做到顺序轮询。

最终方案 链表队列

所有账号形成一个链表,每次只从取头节点,取完之后删除本节点,再把本节点放到尾节点上,这样本来第二个节点就成了头节点。这样就不依靠外部来循环,让账号本身形成循环做到顺序轮训的效果。

image.png

链表队列源码

public class LinkList<T> {

    private Node head = null;

    class Node {
        Node next = null;
        T data;
        Node(T data) {
            this.data = data;
        }
    }

    /**
     * 插入数据
     *
     * @param data 数据
     */
    public void addNode(T data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
            return;
        }
        Node tmp = head;
        while (tmp.next != null) {
            tmp = tmp.next;
        }
        tmp.next = newNode;
    }

    /**
     * 获取头节点,再把获取到的节点置为尾节点
     * @return
     */
    public synchronized T get() {
        T data = head.data;
        Node tmp = head;
        while (tmp.next != null) {
            tmp = tmp.next;
        }
        tmp.next = head;
        head = head.next;
        tmp.next.next = null;

        return data;
    }
}