【问题标题】:Avoiding rate-limiting (throttling) in java (IRC)避免 java (IRC) 中的速率限制(节流)
【发布时间】:2015-03-19 18:37:06
【问题描述】:

所以我一直在编写一个基于 java 的 irc-bot,它相当简单。与服务器建立套接字连接,将缓冲的读取器/写入器附加到套接字,然后使用这些缓冲区读取/写入。

除了打印出一个 json 对象并因过度泛滥而被踢出网络时,我没有遇到任何问题。我不确定网络的消息速率限制,但我确实通过相同的简单函数传递所有消息。

我希望为其添加某种 x 字节/时间范围限制。有人建议我研究 NIO,但这似乎有点过度设计了这个问题。

这是我当前的 write-to-irc 通道方法的样子:

public static void writeMsg(BufferedWriter writer, String Channel, String Message) {
    try {
        System.out.println("Bot Command: PRIVMSG " + Channel + Message); //diagnostic
        writer.write("PRIVMSG " + Channel + Message);
        writer.flush();
    } catch(IOException ioe) {
        ioe.printStackTrace();
    }
}

可能传入/传出该函数的示例:

输入:

writer(我的 BufferedWriter 对象)、“#Testing1234:”、“!wiki China”;

输出:

PRIVMSG #BeginnersProgramming :http://en.wikipedia.org/wiki/China

【问题讨论】:

  • FWIW,大多数速率限制可能主要着眼于在一个时间范围内发送的消息量,而不是它们的长度。例如。假设您在 20 秒内发布 10 条 100 个字符的消息时超时,那么如果所有消息只有 1 个字符长,您也可能会超时。因此,根据消息长度分布,简单地检查一个时间范围内发送的字节数可能不足以逃避禁令;您应该(或另外)检查时间范围内发送的消息数量。
  • 是的,我正在与管理员交谈,它是消息的数量(更容易实现)和它们的内容的长度。
  • 你知道有一些用于 irc bot 的 API 吗?也许最好只实施,这取决于你想要什么。这是我前一段时间使用的一个:jibble.org/pircbot.php

标签: java time irc rate


【解决方案1】:

我会在你的方法开始时随机睡眠。这样,您可以模拟人类打字。

非线程安全版本

private static SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN"); 

public static void writeMsg(BufferedWriter writer, String Channel, String Message){
    try {
        // Sleep randomly between 2 (inclusive) and 5 (exclusive) seconds.
        int duration = 2000 + sr.nextInt(3000);
        System.out.println("Pausing execution for " + duration + " ms..."); 
        TimeUnit.MILLISECONDS.sleep(duration);

        System.out.println("Bot Command: PRIVMSG " + Channel + Message); //diagnostic
        writer.write("PRIVMSG " + Channel + Message);
        writer.flush();
    } catch(IOException ioe){
       ioe.printStackTrace();
    } catch (InterruptedException e) {
       e.printStackTrace();
    }
}

线程安全版本

如果您的方法将被多个线程调用,请考虑使用锁定此代码。锁在发送消息时增加了一些随机性。

private static final Lock writeLock = new ReentrantLock();
private static SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN"); 

public static void writeMsg(BufferedWriter writer, String Channel, String Message){
    writeLock.lock();
    try {
        // Sleep randomly between 2 (inclusive) and 5 (exclusive) seconds.
        int duration = 2000 + sr.nextInt(3000);
        System.out.println("Pausing execution for " + duration + " ms..."); 
        TimeUnit.MILLISECONDS.sleep(duration);

        System.out.println("Bot Command: PRIVMSG " + Channel + Message); //diagnostic
        writer.write("PRIVMSG " + Channel + Message);
        writer.flush();
    } catch(IOException ioe){
       ioe.printStackTrace();
    } catch (InterruptedException e) {
       e.printStackTrace();
    } finally {
       writeLock.unlock();
    }
}

【讨论】:

  • 这比这个线程中的其他选项更时尚一点,你可以通过随时间发送的字节而不是任意时间来重新实现它吗?
【解决方案2】:

我希望为其添加某种 x 字节/时间范围限制

最简单的方法是按照

final int rateLimit = 50; // Bytes per second

final float msPerByte = 1000.0f / rateLimit;

writer.write(message);

int numBytes = message.length();

Thread.sleep((int)(msPerByte * numBytes + 1));

但是,根据消息的长度,一条消息的单次突发可能已经触发了服务器的速率限制。在这种情况下,您必须将消息拆分成更小的部分,然后在适当的延迟之间一个接一个地发送。

如果仅针对每个时间帧的消息强制实施速率限制,您只需在每条消息之后sleep() 固定时间。

我相信虽然有更复杂的算法在起作用,其中可能包括更多基于时间的参数来决定。

【讨论】:

猜你喜欢
  • 2019-12-25
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 2018-05-12
  • 2018-05-04
  • 2020-08-02
相关资源
最近更新 更多