Forum Discussion

JRahm's avatar
JRahm
Icon for Admin rankAdmin
Dec 05, 2022

Coding Live: Policies & iRules - Dec 8, 2022

Policies and iRules. iRules and policies. Usage can be either/or OR both/and, but where do you draw the lines of operational control? Join Jason at 10:45 pacific time on Thursday, December 8, 2022 to work through a few scenarios.

 

  • Hi Folks,

    for those how are interested knowing the performance difference of LTP vs. iRules.

    Passthrough Setup:

    The passthrough setup had the purpose to figure out the performance my naked setup to allow comparsion of the "noice"

    when CLIENT_ACCEPTED {
    	set time(Passthrough) [clock clicks]
    }
    when HTTP_REQUEST {
    	lappend time(Passthrough) [clock clicks]
    	eval $static::debug_page
    }

     

    Without any LTP or additional iRule code in between CLIENT_ACCEPTED and HTTP_REQUEST it took a minimum of 13 clicks and an average of 83 clicks per HTTP request (after removing 10% slowest/fastes results) .

    iRule Setup:

    To test the performance of iRules I've added a [switch] statement consisting 50+default hostnames and a pool assigment.  

    when CLIENT_ACCEPTED {
    	set time(iRULE_50switch_default) [clock clicks]
    }
    when HTTP_REQUEST {
    	switch -exact -- [HTTP::host] {
    		"www.domain-01.de" { pool www.itacs.de }
    		"www.domain-02.de" { pool www.itacs.de }
    
    		... truncated ...
    
    		"www.domain-49.de" { pool www.itacs.de }
    		"www.domain-50.de" { pool www.itacs.de }
    		default { pool REST_API }
    	}
    	lappend time(LTP_50rules_default) [clock clicks]
    	eval $static::debug_page
    	
    }

    The test was triggering the "default" condition of the [switch] (worst case) and it took a minimum of 24 clicks and an average of 102 clicks per HTTP request (after removing 10% slowest/fastes results).

    Local Traffic Policy Setup:

    To test the performance of Local Traffic Policies I've added a first match LTP policy consisting 50+1 (exist) hostnames and a pool assigment rules.

    when CLIENT_ACCEPTED {
    	set time(LTP_50rules_default) [clock clicks]
    }
    when HTTP_REQUEST {
    	lappend time(LTP_50rules_default) [clock clicks]
    	eval $static::debug_page
    }

    The test was triggering the "default" condition of the LPT and it took a minimum of 18 clicks and an average of 92 clicks per HTTP request (after removing 10% slowest/fastes results).

    Results:

    The comparsion of Passthrough vs iRule vs LTP Setup is basically a minimum of 13 / 24 / 18 clicks and an average of 83 / 102 / 92 clicks per HTTP request. LPT is round about twice as fast at parsing 50+1 hostnames and assigning a pool.

    So can we all agree that both methods are lightning fast and that LTP still sück because it cant even craft a HTTP response? 🤣

    Cheers, Kai

     

    • JRahm's avatar
      JRahm
      Icon for Admin rankAdmin

      just for giggles, is the iRule switch performance any different if the switch cases are bound since all the pool destinations are the same? Example:

       

      when CLIENT_ACCEPTED {
      	set time(iRULE_50switch_default) [clock clicks]
      }
      when HTTP_REQUEST {
      	switch -exact -- [HTTP::host] {
      		"www.domain-01.de" -
      		"www.domain-02.de" -
      
      		... truncated ...
      
      		"www.domain-49.de" -
      		"www.domain-50.de" { pool www.itacs.de }
      		default { pool REST_API }
      	}
      	lappend time(LTP_50rules_default) [clock clicks]
      	eval $static::debug_page
      	
      }

       

      similar for the policy, a single condition with all the hosts in the matches any field...

      • Hi Jason,

        for the [switch] it does basically dont matter if multiple condition trigger the same script or different scripts. The overhead from evaluating 50 strings is the same... 

        Single Script:

        when HTTP_REQUEST {
        	lappend time(iRule_50rules_single_scripts) [clock clicks]
        	switch -exact -- [HTTP::host] {
        		"www.domain-01.de" -
        		"www.domain-02.de" -
        		... truncated ...
        		"www.domain-48.de" -
        		"www.domain-49.de" -
        		"www.domain-50.de" { pool www.itacs.de }
        		default { pool REST_API }
        	}
        	lappend time(iRule_50rules_single_scripts) [clock clicks]
        	eval $static::debug_page
        }

        Many individual Scripts:

        when HTTP_REQUEST {
        	lappend time(iRule_50rules_single_scripts) [clock clicks]
        	switch -exact -- [HTTP::host] {
        		"www.domain-01.de" { pool www.itacs.de }
        		"www.domain-02.de" { pool www.itacs.de }
        		... truncated ...	
        		"www.domain-50.de" { pool www.itacs.de }
        		"www.domain-50.de" { pool www.itacs.de }
        		default { pool REST_API }
        	}
        	lappend time(iRule_50rules_single_scripts) [clock clicks]
        	eval $static::debug_page
        }

        But it does matter if you trigger [switch]'s first (see below) or default (see above) conditions....

        1st hit:

        25th hit:

        50th hit:

        Old facts remaining the same. The more item in the list and the deeper your have to dig into the list the longer it takes to evaluate it.  

        Lets see if we can find some better replacements for [switch]...

        Using [if]:

        when HTTP_REQUEST {
        	lappend time(iRule_5if_1st_hit) [clock clicks]
        	if { [HTTP::host] eq "www.domain-01.de" } then { pool www.itacs.de }
        	elseif { [HTTP::host] eq "www.domain-02.de" } then { pool www.itacs.de }
        	elseif { [HTTP::host] eq "www.domain-03.de" } then { pool www.itacs.de }
        	elseif { [HTTP::host] eq "www.domain-04.de" } then { pool www.itacs.de }
        	elseif { [HTTP::host] eq "www.domain-05.de" } then { pool www.itacs.de }
        	else { pool REST_API }
        	lappend time(iRule_5if_1st_hit) [clock clicks]
        	eval $static::debug_page
        }

        1st hit [if] is slightly quicker than [switch}, 5th hit [if] is about the same as [switch]. Nothing new about...

        [eval] loading a script from static::array()  with 1.000.000 bucket entries

        when RULE_INIT {
        	for { set x 1 } { $x < 1000000 } { incr x } {
        		set my_conditional_scripts(www.domain-${x}.de) { pool www.itacs.de }
        	}
        }
        when HTTP_REQUEST {
        	lappend time(iRule_eval_1million_bucket) [clock clicks]
        	if { [catch {
        		eval $my_conditional_scripts([HTTP::host])
        	}] } then {
        		 pool REST_API
        	}
        	lappend time(iRule_eval_1million_bucket) [clock clicks]
        	eval $static::debug_page
        }

        Performance in the range of a 50-entry [switch] statemen, not bad. Can LTP handle 1M URLs? And how fast?  

        Will do some additional LTP tests in the evening. Lets see where LTP limits are...

        Cheers, Kai 

  • And many thanks for showing us VS code with the BigIP plugin. I will definitely give it a try and see if I get comfortable with it.

    Cheers, Kai

  • Many thanks for the session Jason. I pretty much enjoyed to see what is not possible with LTP... 🤣 

    Cheers, Kai

  • Who catches the flaw in this X-Forwarded-For protection Jason just has shown us?

    Cheers, Kai

    • JRahm's avatar
      JRahm
      Icon for Admin rankAdmin

      the wonky capitalization within, you mean?

      • in LTP a header-replace has same problems as [HTTP::header replace] in iRule. If user-agent sends 2 header instances, only one instance gets replaced in the request. For a X-Forwarded-For protection this is obviously not the right way to do it... 

        Cheers, Kai

      • I would join, I will take the role of the random dude asking silly questions. Kai take the role of the shiny dude who actually knows stuff.

        Not sure whether my face needs to be on camera...