Forum Discussion

David_Murphy_20's avatar
David_Murphy_20
Icon for Nimbostratus rankNimbostratus
Jul 16, 2013

Limit HTTP Requests per second on virtual server

Hello -

 

I need to implement an iRule that dynamicly monitors HTTP Requests per second on a virtual server - and in the event that we reach the pre-defined limit - serve a custom HTTP response (that includes an iFile). I have tried using some of the previously posted "throttling" rules - but none of them seem to be working for my situation.

 

Currently - I am trying to get the rule below working - but when i check the syntax in the iRules editor, I keep getting: "Response is not well-formed XML". Can anyone offer some assistance with this?

 

Thanks!

 

-David

 

 

when RULE_INIT {

 

set static::win_size 1000

 

set static::qps_hwm 10

 

set static::no_bid_file "/Common/RTB_no_bid_response"

 

set static::window_count 10

 

 

set static::debug 1

 

 

array set ::time_windows {}

 

set ::req_counter 0

 

set ::sample_rate 100

 

set ::last_time [clock microseconds]

 

}

 

 

when HTTP_REQUEST {

 

set ::req_counter [incr ::req_counter]

 

 

if { ::req_counter == $static::win_size } {

 

set timestamp [clock microseconds]

 

set differnce [expr {$timestamp - $::last_time}]

 

set current_qps [expr {$difference / $static::win_size}]

 

 

if {[info exists ::time_windows($static::window_count)]} {

 

for {set i 0} {$i < $static::window_count} {incr i} {

 

set tmp [lindex [array get ::time_windows [expr {$i + 1}]] 1]

 

set ::time_windows($i) $tmp

 

}

 

set ::time_windows($static::window_count) $current_qps

 

} else {

 

set ::time_windows([array size ::time_windows]) $current_qps

 

}

 

 

set total 0

 

foreach index [array names ::time_windows] {

 

set total [expr {$total + ::time_windows($index)}]

 

}

 

 

set avg_qps [expr {double($total) / [array size ::time_windows]}]

 

 

if { $avg_qps < $static::qps_hwm } {

 

set ::sample_rate 100

 

} else {

 

set ::sample_rate [expr {100 * [expr {double($static::qps_hwm) / double($avg_qps)}]}]

 

}

 

 

set ::req_counter 0

 

set ::last_time $timestamp

 

 

if { $static::debug == 1 } {

 

log -noname local0. "Current avg qps: ${avg_qps}"

 

log -noname local0. "Current sample rate: ${::sample_rate}"

 

}

 

}

 

 

set random_number [expr {rand() * 100}]

 

 

if { $random_number >= $::sample_rate } {

 

HTTP::respond 200 content [ifile get $static::no_bid_file] Cache-Control "no-cache,no-store,must-revalidate" Pragma "no-cache" Expires "Fri, 01 Jan 1990 00:00:00 GMT"

 

return

 

}

 

}

 

 

 

3 Replies

  • [clock microseconds]i understand microseconds is not supported.

     

     

    Is microsecond precision available in an iRule?

     

    https://devcentral.f5.com/community/group/aft/1178832/asg/50

     

     

    if { ::req_counter == $static::win_size } {is $ missing (i.e. $::req_counter)?

     

     

    set total [expr {$total + ::time_windows($index)}]is $ missing (i.e. $::time_windows($index))?
  • Thank you for this information. It turns out we needed to make these changes, along with a few other tweaks. The code that finally worked is below.

     

     

    Thanks -

     

    David

     

     

  • 
    when RULE_INIT {
    set static::win_size 1000
    set static::qps_hwm 10
    set static::no_bid_file "/Common/RTB_no_bid_response"
    set static::window_count 10
    
    set static::debug 1
    
    array set ::time_windows {}
    set ::req_counter 0
    set ::sample_rate 100
    set ::last_time [clock clicks -milliseconds]
    }
    
    when HTTP_REQUEST {
    set ::req_counter [incr ::req_counter]
    
    if { $::req_counter == $static::win_size } {
    set timestamp [clock clicks -milliseconds]
    set difference [expr {$timestamp - $::last_time}]
    set current_qps [expr {double($static::win_size) / double($difference)}]
    
    if {[info exists ::time_windows($static::window_count)]} {
    for {set i 0} {$i < $static::window_count} {incr i} {
    set tmp [lindex [array get ::time_windows [expr {$i + 1}]] 1]
    set ::time_windows($i) $tmp
    }
    set ::time_windows($static::window_count) $current_qps
    } else {
    set ::time_windows([array size ::time_windows]) $current_qps
    }
    
    set total 0
    foreach index [array names ::time_windows] {
    set total [expr {$total + $::time_windows($index)}]
    }
    
    set avg_qps [expr {double($total) / [array size ::time_windows]}]
    set avg_qps [expr {$avg_qps * 1000}]
    
    if { $avg_qps < $static::qps_hwm } {
    set ::sample_rate 100
    } else {
    set ::sample_rate [expr {100 * [expr {double($static::qps_hwm) / double($avg_qps)}]}]
    }
    
    set ::req_counter 0
    set ::last_time $timestamp
    
    if { $static::debug == 1 } {
    log -noname local0. "Current avg qps: ${avg_qps}"
    log -noname local0. "Current sample rate: ${::sample_rate}"
    }
    }
    
    set random_number [expr {rand() * 100}]
    
    if { $random_number >= $::sample_rate  } {
    HTTP::respond 200 content [ifile get $static::no_bid_file] Cache-Control "no-cache,no-store,must-revalidate" Pragma "no-cache" Expires "Fri, 01 Jan 1990 00:00:00 GMT"
    return
    }
    }