首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  Java

请教, Java 怎么控制 API 调用的频率

  •  
  •   liaojl · 53 天前用 Android 发布 · 3091 次点击
    这是一个创建于 53 天前的主题,其中的信息可能已经有所发展或是发生改变。
    服务端需要调用第三方 API,但是第三方 API 有调用频率限制,多次超出调用频率会被拉黑。目前用线程池来调 API,怎么才能控制服务器端每分钟调用次数不超过指定数量,比如每分钟不超过 500 次。
    36 回复  |  直到 2019-05-30 19:52:38 +08:00
        1
    micean   53 天前   ♥ 2
    guava 有 ratelimiter
        2
    oneisall8955   53 天前 via Android
    用变量来记录当前时间分钟对应的调用次数可以否?到下一分钟,重置为 0,这分钟内每次调用增加 1,到 500 提示失败
        3
    oneisall8955   53 天前 via Android
    我渣渣哈哈~没做过这个东西,胡乱猜想的
        4
    liaojl   53 天前 via Android
    @micean 好东西,正是我想要的
        5
    liaojl   53 天前 via Android
    @oneisall8955 我也这么想过,但是后来一想,如果负责置 0 的那个线程阻塞或者发生什么意外,那就 gg 了
        6
    runtu2019   53 天前
    @liaojl 同时放个时间戳,变量只做自增作用,同时校验时间戳和数量,单个线程崩了应该没事
        7
    liaojl   53 天前 via Android
    @runtu2019 好办法
        9
    securityCoding   53 天前
    1. guava 单机限流
    2.阿里开源的 Sentine
        10
    l8g   53 天前
    单机可以看下 Guava 的 RateLimiter
    分布式场景下用 Redis 的 zset 做个简单的限流也可以
        11
    palmers   53 天前
        12
    liaojl   53 天前
    @securityCoding
    @l8g
    @palmers
    谢谢各位!
        13
    dawncold   53 天前
    一个好的 API 设计会告诉你当前时间窗口还剩多少次调用,遵照执行就好
        14
    gz911122   53 天前
    rxjava 被压
        15
    CoderGeek   53 天前
    简单的限流就可以实现 楼上都说了
        16
    xuanbg   53 天前
    redis 里面搞一个过期时间为 1 分钟的 key 作为计数器,读到计数器到达 500 了,就报调用失败或者扔到队列里面去等下一分钟再调用。队列可以满足削峰的需求,但不能满足你每分钟平均次数超过 500 的需求。如果平均每分钟超过 500 的话,只能报错了。
        17
    jorneyr   53 天前
        18
    lihongjie0209   53 天前
    老老实实写日志到 redis 或者是数据库中, 调用之前先查询一下日志.

    基于 guava 这种内存型的, 服务器重启就 GG 了.
        19
    aino   53 天前
    俺用的 RateLimiter
        20
    luozic   53 天前 via iPhone
    kong/其他平台的网关
        21
    liaojl   53 天前 via Android
    @jorneyr 是限制我方调用第三方 API 的频率,不是限制客户端调我方 API 的频率😂,不过还是感谢哈,Nginx 还可以这么用
        22
    liaojl   53 天前 via Android
    @lihongjie0209 哈哈,只是限制每分钟的调用频率,不限制历史总的调用次数的
        23
    lzxz1234   53 天前
    选定一个时间单位,记录这个时间段内所有请求发出去的时间,每次请求时查看最早的那个请求时间,大于时间单位通过并更新请求时间,否则等待或者返回 false,一个循环数组就可以搞定了,根据目标频率选一个合适的大小就可以
        24
    clarkyi   53 天前
    guava 这种不支持分布式吧?多台设备就 gg 了,redis+guava 考虑一下
        25
    lihongjie0209   53 天前
    @liaojl
    00:00:03 秒调用了 300 次
    00:00:05 服务器重启
    00:00:40 重启成功
    00:00:59 又调用了 300 次

    总数超了
        26
    cyhulk   53 天前
    @lihongjie0209 要看场景的,如果是考虑性能问题限制次数,重启了,重新 300 也无所谓,反正服务器重启过了,300 也压的住,直接内存,相对于 redis 调用的性能损耗,要划算的多
        27
    luozic   53 天前 via iPhone
    网关也能干出去调用的,代理一下就行。
        28
    mejee   53 天前 via Android
    单机的话简单的限流算法就可以 令牌桶算法之类的
        29
    vtoee   53 天前
    有点类似于调百度地图 API 坐标转换
        30
    lihongjie0209   53 天前
    @cyhulk 这个限制是第三方 API 的, 不是楼主的
        31
    EastLord   53 天前
    目测 阿里的 Sentine 满足楼主需求
        32
    zzzmode   53 天前
    kong 网关
        33
    opengps   53 天前
    如果是单机应用,服务器上装个安全狗之类的防护工具,可以对所有请求整体频率起效果。
    如果只是某个接口调用,套了 cdn 则被忽视,不套上 cdn 的业务需要做个公共缓存统计,记录一个列表,每次请求顺便释放掉超时的缓存对象
        34
    opengps   53 天前
    如果是单机单接口,那么可以利用系统自带缓存,或者本机 memcached 缓存做个计数(取出结果非等于 1 则++,等于 null 则赋值 1 ),超时时间就设置 1 分钟
        35
    gaius   53 天前
    这问题我遇到过,1 时 0 分 1s 发了 500 个,2 时 0 分 2s 又发了 500,从 1s 到 2s 的这个时间窗口却是 1 小时发了 1000。
    如果消费还有优先级的话,还再麻烦点。
        36
    gscoder   52 天前
    和限流是一样的方法:漏桶算法、令牌桶算法、滑动窗口算法。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3832 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 20ms · UTC 08:30 · PVG 16:30 · LAX 01:30 · JFK 04:30
    ♥ Do have faith in what you're doing.