Forum Discussion

Bruce_Bronczyk's avatar
Bruce_Bronczyk
Icon for Altostratus rankAltostratus
Jun 13, 2014

Randomly unpredictable rate limiting using the iRule iRules.virtual_server_connection_rate_limit_with_tables.ashx

Has anyone used this iRule, https://devcentral.f5.com/wiki/iRules.virtual_server_connection_rate_limit_with_tables.ashx, and seen issues with random rate limiting for some connections well below the set value? We have ours set at 20 conn/sec for the virtual server which normally averages about 20 per second for all source IPs. Could there be issues with how the table keeps track of each unique client connection rate vs. the total connections per second for all source IPs?

 

11 Replies

  • Try this and let me know how it performs for you...

    when CLIENT_ACCEPTED {
       this will give you 20 connections per second per source IP address
      set cid [clock clicks]
      set conns 20
      set rate 1
    
      table set -subtable [virtual]:[IP::client_addr] $cid 0 indef $rate
      if {[table keys -subtable [virtual]:[IP::client_addr] -count] > $conns} { 
        table delete -subtable [virtual]:[IP::client_addr] $cid
        TCP::close
      }
    }
    

    In a BIGIP there will be many other instances of this iRule (one per TCP connection) running at the same time. When we get to the IF condition they could all say they are under the connection limit because they perform the test at the same moment in time.

    To allow for this, we allocate the connection entry (table set), then backout (table delete) if we are over the limit (table keys -count). Since the table is always the source of truth, we never exceed the rate limit.

    • Kevin_Davies_40's avatar
      Kevin_Davies_40
      Icon for Nacreous rankNacreous
      One second is the lowest resolution of table expiry timer. You may want to up this a little so if its 20 connections per second, you may get better results with 200 per 10 seconds.
    • Kevin_Davies_40's avatar
      Kevin_Davies_40
      Icon for Nacreous rankNacreous
      If any of the above posts have provided a solution to your issue, please indicate so by clicking the tick to the left of them. This gives feedback and recognition to the volunteers who responded to your issue
    • Bruce_Bronczyk's avatar
      Bruce_Bronczyk
      Icon for Altostratus rankAltostratus
      Thanks for the suggestion. I am not very experienced with editing iRules, so does your suggested change insert into the iRule at a specific spot or does it replace some of the existing iRule below the 'when CLIENT_ACCEPTED' point? Thanks.
  • Some results from apachebench testing...

    20 requests in .23 seconds, all succeeded.

    Concurrency Level:      1
    Time taken for tests:   0.238 seconds
    Complete requests:      20
    Failed requests:        0
    Write errors:           0
    Total transferred:      9320 bytes
    HTML transferred:       1860 bytes
    Requests per second:    83.98 [/sec] (mean)
    Time per request:       11.908 [ms] (mean)
    Time per request:       11.908 [ms] (mean, across all concurrent requests)
    Transfer rate:          38.22 [Kbytes/sec] received
    

    40 requests in .36 seconds, 20 succeeded.

    Concurrency Level:      1
    Time taken for tests:   0.366 seconds
    Complete requests:      40
    Failed requests:        20
       (Connect: 0, Receive: 0, Length: 20, Exceptions: 0)
    Write errors:           0
    Total transferred:      9320 bytes
    HTML transferred:       1860 bytes
    Requests per second:    109.26 [/sec] (mean)
    Time per request:       9.152 [ms] (mean)
    Time per request:       9.152 [ms] (mean, across all concurrent requests)
    Transfer rate:          24.86 [Kbytes/sec] received
    

    40 requests (10 threads) in .08 seconds, 20 succeeded

    Concurrency Level:      10
    Time taken for tests:   0.084 seconds
    Complete requests:      40
    Failed requests:        20
       (Connect: 0, Receive: 0, Length: 20, Exceptions: 0)
    Write errors:           0
    Total transferred:      9320 bytes
    HTML transferred:       1860 bytes
    Requests per second:    477.45 [/sec] (mean)
    Time per request:       20.945 [ms] (mean)
    Time per request:       2.094 [ms] (mean, across all concurrent requests)
    Transfer rate:          108.64 [Kbytes/sec] received
    
  • Thanks very much Kevin. Our early testing looks good. Will keep you posted.

    One question for you. If we have multiple vips with this irule applied, will the table be different for each vip? or shared.

    Example. source ip 1.2.3.4

    we want 1.2.3.4 to have 20 connections/sec to vip 1 and 20 connections/sec to vip 2.

    Will it work that way, or will it only allow 20 connections from that source ip total.

    we added a few tweaks for tcp::respond and logging.

    when CLIENT_ACCEPTED { set static::whitelist_class vsratelimit_whitelist_class

    if {[class match [IP::client_addr] equals vsratelimit_whitelist_class]}{

      return
    

    }

    this will give you 20 connections per second per source IP address set cid [clock clicks] set conns 10 set rate 1 set key "[IP::client_addr]:[TCP::client_port]" set current [table keys -subtable [virtual]:[IP::client_addr] -count] table set -subtable [virtual]:[IP::client_addr] $cid 0 indef $rate

    if {$current > $conns} { table delete -subtable [virtual]:[IP::client_addr] $cid log local0. "$key: Connection to [IP::local_addr]:[TCP::local_port]\ ([virtual name]). At limit, rejecting (current: $current / max: $conns)" TCP::respond "Your request is being rate limited. Please reduce the frequency of your requests and try again later"

    TCP::close } }

    thanks, Ben

  • when CLIENT_ACCEPTED {

    set static::whitelist_class vsratelimit_whitelist_class

    if {[class match [IP::client_addr] equals vsratelimit_whitelist_class]}{

      return
    

    }

    set cid [clock clicks] set conns 20 set rate 1 Track this connection in the subtable using the client IP:port as a key set key "[IP::client_addr]:[TCP::client_port]" set current [table keys -subtable [virtual]:[IP::client_addr] -count] table set -subtable [virtual]:[IP::client_addr] $cid 0 indef $rate

    if {$current > $conns} { table delete -subtable [virtual]:[IP::client_addr] $cid log local0. "$key: Connection to [IP::local_addr]:[TCP::local_port]\ ([virtual name]). At limit, rejecting (current: $current / max: $conns)" TCP::respond "Your request is being rate limited. Please reduce the frequency of your requests and try again later"

    TCP::close } }
    • Kevin_Davies_40's avatar
      Kevin_Davies_40
      Icon for Nacreous rankNacreous
      The table name actually is made up of [virtual]:[IP::client_addr] which is the name if your virtual with the clients IP address.