Forum Discussion

dragonflymr's avatar
dragonflymr
Icon for Cirrostratus rankCirrostratus
Dec 04, 2015

Subtables, performance and resouces

Hi,

 

I know that subtables should be be used sparingly because each subtable is pinned to TMM instance that created subtable - so it's using RAM of this TMM - could create uneven RAM consumption.

 

So I would like to verify if my idea is good considering performance and resource usage.

 

I need to collect plenty of different data about HTTP session. Sure I do not know session id value in advance - it's created as cookie by some app server.

 

My idea is:

 

  • Create subtable named using cookie value of cookie used to track session
  • Then create key is such subtable using strings describing data I need to collect and store - some with indefinite lifetime some with set lifetime
  • As value for keys I will use data that is necessary to be stored to make decisions how to handle given session or just for string statistical info
  • Using such setup I can lookup subtable using session id as name and then key to retrieve data I need to proceed with necessary logic for my iRule
  • That allows me to handle situation when subtable name is not known in advance - created dynamically using my session cookie value that I can't control, then I am able to retrieve both know keys and unknown key (using subtable keys enumeration)

Question is if that is good approach performance is resource wise? Or maybe there is better way?

 

Some keys will have lifetime or timeout set, other (for statistical/historical purposes indefinite) not.

 

That is some other related question - is there easy/fast way to check creation and last touch time for keys? I know that there are -remaining options for keys, but I cant't find such options to retrieve mentioned metadata - is there any? Can figure out how to check calculate creation time if lifetime is known for key - just retrieve remaining and do some math based on current time. Similar probably for timeout - but still it's indirect - some math is needed - maybe there is some direct way?

 

Piotr

 

9 Replies

  • Hi Piotr,

     

    using a (random?) "cookie value" as "subtable_name" would be a good choice to distribute the RAM consumption across your TMMs evenly. Each cookie value will get its own subtable and each single subtable would be randomly pinnend to a different TMM.

     

    But I still dont get the point how you're trying to access and enumerate a specific subtable without knowing its name in advanced? I'm asking because you simply can't enumerate subtable names using the table command. You are just able to enumerate every contained "subtable key" of a given "subtable name", but the "subtable name" MUST be somehow known (a fixed value or provided by the client).

     

    But you may want to store every "subtable_name" (aka. your cookie values) in an seperated and known "subtable_name_subtable" (aka. a subtable containing every cookie value as a key). By doing this, it will be possible to enumerate the currently strored subtable_name's and access the data of every single key of those tables.

     

    If using a single "subtable_name_subtable" the RAM consumption may become distributed uneven again. Using multiple well-known "subtable_name_subtables" (e.g. a dedicated subtable for every first letter/didgit of the cookie value) the ressource consumption of the contained data could be distributed across multiple TMMs again.

     

    BTW1: There is no option to query the creation or last accessed time. Either store/update a timestamp when created/accessed or do some math based on the -remaining values.

     

    BTW2: Using indefinite key lifetimes could be a dangerous task, if the creation of the keys can be triggered by end-users without restricting the maximum number of tables/keys. It may exhaust to much of your TMM memory without releasing it and therefor requires a manual garbage collection.

     

    Cheers, Kai

     

  • Hi,

     

    Thanks a lot for your answer. Yes indeed I am planning to use "master table" storing all names of session vale based subtables. That presents danger of unbalanced RAM usage so probably I will try to implement this solution.

     

    Probably simplest way to overcome creation and last touched will to store those in session named subtable as keys containing clock cmd base values.

     

    I am aware that indefinite is dangerous so I am planing some cleanup routine to get rid of subtables after data is exported to external system.

     

    Piotr

     

  • Hi Piotr,

     

    using a [expr {[crc32 $COOKIE_VALUE] % $NUMBER_OF_TABLES}] to splitt the master table would work like a charm and is always safe to use.

     

    Using a [string range $COOKIE_VALUE 0 0] would be little faster, but it's not as variable (e.g. configurable table number) as CRC and also strongly depends on the format of the provided cookie values.

     

    Cheers, Kai

     

  • Hi,

     

    Thanks a lot. I will try this. I guess I am a bit exaggerating issue here as I do not except subtables with more than 30 000 - 50 000 keys. Do you thin for subtables of this size it's still necessary to use splitting?

     

    Piotr

     

  • Hi Piotr,

    if the stored cookie values are not that big (e.g. ~50bytes) then it wouldn't be a big deal. It should consume just a few Mbytes in total.

    To see the resulting RAM consumption of 50.000 keys you may want to use a "while" loop to create 50.000 dummy keys and then measure the resulting memory consumption using.

    tmsh show /sys tmm-info

    Cheers, Kai

  • Hi,

     

    I just started to think about implementing splitting master subtable and then performing lookups. Probably there is quite easy way to resolve this but I am a bit stuck.

     

    Let's say I am using second method and splitting my master subtable (storing session ids as keys) int 3. From my test it looks like I have no control in advance which crc value from three possible will be generated. So in the end I don't know in which master subtable given session id key will be created.

     

    Am I right here?

     

    If do I assume that it's necessary to iterate through all subtables until given key will be found. I can't see any other way to check in which of master subtables given sessionID was stored - or I am wrong?

     

    Piotr

     

  • Hi Piotr,

    You can initialize (aka. "set") a new COOKIE_VALUE by specifying the subtable name "master_table[expr {[crc32 $COOKIE_VALUE] % $NUMBER_OF_TABLES}]", the KEY_NAME "$COOKIE_VALUE" and KEY_VALUE "1".

    You can write data related to a COOKIE_VALUE by specifying the subtable name "$COOKIE_VALUE", a specific KEY_NAME, and a KEY_VALUE.

    You can read data related to a COOKIE_VALUE by specifying the subtable name "$COOKIE_VALUE", a specific KEY_NAME.

    You can search the contained KEY_NAMEs of a specific COOKIE_VALUE by specifying the subtable name "$COOKIE_VALUE"

    You can check the existence of an existing COOKIE_VALUE by "lookup" the subtable name "$COOKIE_VALUE", some mandatory KEY_NAME (e.g. time stamp, etc.) and validate the output.

    You can check the existence of an existing COOKIE_VALUE by "lookup" the subtable name "master_table[expr {[crc32 $COOKIE_VALUE] % $NUMBER_OF_TABLES}]", the KEY_NAME "$COOKIE_VALUE" and validate the output.

    You can search a specific session_id or dump every session_ids (aka. data export) by performing "while", "foreach" or "for" to access each of you master tables sequentially.

    set table_id 0
    while {$table_id < $NUMBER_OF_TABLES} {
        foreach session_id [table keys -subtable "master_table$table_id"] {
             set KEY_VALUE_A [table lookup $session_id KEY_NAME_A]
             ...
             set KEY_VALUE_Z [table lookup $session_id KEY_NAME_Z]
            
             Perform a "set found_session_id 1" and "break" to skip further foreach processing
        }
         Evalute "$found_session_id and "break" to skip further while processing
        incr table_id
    }
    
    foreach table_id { 0 1 2 } {
        foreach session_id [table keys -subtable "master_table$table_id"] {
             set KEY_VALUE_A [table lookup $session_id KEY_NAME_A]
             ...
             set KEY_VALUE_Z [table lookup $session_id KEY_NAME_Z]
            
             Perform a "set found_session_id 1" and "break" to skip further foreach processing
        }
         Evalute "$found_session_id and "break" to skip further foreach processing
    }
    
    for {set table_id 0} {$table_id < $NUMBER_OF_TABLES} {incr table_id} {
        foreach session_id [table keys -subtable "master_table$table_id"] {
             set KEY_VALUE_A [table lookup $session_id KEY_NAME_A]
             ...
             set KEY_VALUE_Z [table lookup $session_id KEY_NAME_Z]
            
             Perform a "set found_session_id 1" and "break" to skip further foreach processing
        }
         Evalute "$found_session_id and "break" to skip further for processing
    }
    

    Do you miss anything in particular?

    Cheers, Kai

  • Hi Kai,

     

    Great post. Plenty of data I have to analyze - I ma quite new to iRules, not programmer and HTTP expert - so it's not so easy for me to figure out things on the fly :-(

     

    Anyway my plan is to:

     

    • Use master subtable (probably with splitting) to store all generated cookie values (from Set-Cookie in HTTP_RESPONSE) - in iRule attached to VS it will be only used to enforce limit of concurrent HTTP sessions. So we would like to issue given number of sessionID via cookies and then stop to accept any new HTTP request without know cookie value returned. So -count will be used on one or more master subtables for that.
    • New HTTP session will be accepted again when number of keys in master sutable/s will drop below limit (either by expired lifetime or being deleted)
    • Later on, this master subtable can be as well used to be able to reference session specific subtables (we need to retrieve subtable names to be able to iterate keys stored in this specific subtables)
    • I do not need master subtable to reference session cookie named subtables as I am extracting session id from cookie at runtime - so when request comes, I am getting my session value from cookie and then checking if subtable named with session id value contains any key (-count). If yes session is valid, if no session is not valid.
    • Any necessary keys can as well be set on session subtable at runtime because I know subtable name and key names to be set. Values for specific keys are retrieved according to some iRule created logic.

    Any flaw in above? If not I am all good and it's time to create code - hopeful good one performance wise :-)

     

    Thanks again for time and all advises you gave mi!

     

    Piotr

     

  • Hi Piotr,

    when you need to count the "master_subtable" for a maximum number of concurrent "session id" on each or even most of the requests then it may be better to not splitt the table at all.

    Its like that, that splitting the table may cause a better RAM consumption, but on the other hand it would require additional cpu cycles to count every subtable independently and finaly calculate the total result.

    A good compromise of CPU cycles and RAM distribution could be achived if a certain tolerance for the maximum session counter could be accepted by your application logic. In this case you could implement some additional caches to calculate the current total only once in a while...

    if { [set master_table_current_size [table lookup -notouch master_table_current_size]] eq "" } then {
        set master_table_current_size 0
        for {set table_id 0} {$table_id < $NUMBER_OF_TABLES} {incr table_id} {
            incr master_table_current_size [table keys -subtable -count "master_table$table_id"]
        }
        table set master_table_current_size $master_table_current_size indef 5
    } else {
         Use the retrived $master_table_current_size value parameter
    }
    

    The outline example would -count the independend master_tables only once every 5 seconds and request in between would use the previously cached total number fetched from a regular table entry... 😉

    Cheers, Kai