Resources.DocsTutMemcache History

Hide minor edits - Show changes to markup

April 24, 2013, at 07:02 PM by 213.233.101.41 -
Changed lines 1-178 from:

Resources -> Documentation -> Tutorials -> Memory Caching

This page has been visited 15159 times. (:toc-float Table of Content:)


OpenSIPS MemCache

The Memory Caching support from OpenSIPS wants to provide a way of caching at runtime different kind of data. These data will globally available (anywhere in the routing script) and shared between all OpenSIPS processes.

The idea is to be able to store (cache) custom values for later usage. The main purpose of this MemCache support is to reduce the number of DB queries by caching data that does not need constant update from DB. DB queries are known to be one of bottle necks in the current design (see design considerations) and MemCache support will help in avoiding unnecessary DB hits.


OpenSIPS MemCache Design

The Memory Caching support in OpenSIPS has a flexible and expendable design. The idea is to have a simple and transparent way of operating (in the same time) with multiple implementations / forms of memory caching. A memory caching system can be via the local shared memory (see Local Cache module) or via the System V shared memory (mem cache shared across independent applications) or via the MemCache server.

The OpenSIPS core offers an API for operating with any memory caching system from the script. This API is composed out of three functions that allow the basic operations with a memory cache:

  • store - cache_store()
  • fetch - cache_fetch()
  • remove - cache_remove()

The MemCache design from OpenSIPS allow to set a lifetime (timeout) to an attribute when inserting it in the cache. This provides support for auto-removal of attributes (for re-fetching or clean-up purposes) from the cache.

The implementations for the memory caching support are provided by the OpenSIPS modules. Right now there is a single implementation (see Local Cache module) that caches the data into the shared memory of OpenSIPS. In the future release, more implementations are planned to be added.


MemCache usage - Password caching for DB authentication

The best way of describing the MemCache way of usage is to provide a real example - how to use memcache support for reducing the DB queries due user authentication.

The idea - how to

The idea is, after performing a DB authentication (authentication by fetching the password from DB) to store the password in memcache; the password is stored with a certain lifetime to ensure that from time to time the password is read from DB again.

When a new authentication is needed, first we check if the password is available in memcache (previously stored and not yet expired); if so, we use the value from there to perform authentication without a DB hit.

As we have to store in the same time the passwords of more than one users, we need to use different names for the attributes -> the attribute name will contain the user name, something like "passwd_username".

The logic - diagram

  1. REGISTER request received
  2. is password stored in "passwd_$tu" attribute?
    1. NO -> perform DB authentication
    2. store the used password into "passwd_$tu" with s lifetime (1200 seconds - 10 minutes)
    3. DONE
  3. YES -> use the value from the memcache do to authentication from script variables.
  4. DONE

Script

Current format of authentication script for REGISTER is:

	if (!www_authorize("", "subscriber")) {
		www_challenge("", "0");
		exit;
	};

By adding memcache support, the script looks like:

....
loadmodule "modules/db_mysql/db_mysql.so"
loadmodule "modules/auth/auth.so"
loadmodule "modules/auth_db/auth_db.so"
loadmodule "modules/localcache/localcache.so"
....
modparam("auth","username_spec","$avp(i:54)")
modparam("auth","password_spec","$avp(i:55)")
modparam("auth","calculate_ha1",1)

modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url","mysql://opensips:opensipsrw@localhost/opensips_1_2")
modparam("auth_db", "load_credentials", "$avp(i:55)=password")
....

....
route[x]{
	.....
	# do we have the password cached ?
	if(cache_fetch("local","passwd_$tu",$avp(i:55))) {
		$avp(i:54) = $tU;
		xlog("SCRIPT: stored password is $avp(i:55)\n");
		# perform auth from variables
		# $avp(i:54) contains the username
		# $avp(i:55) contains the password
		if (!pv_www_authorize("")) {
			# authentication failed -> do challenge			
			www_challenge("", "0");
			exit;
		};
	} else {
		# perform DB authentication ->
		# password will be loaded from DB automatically
		if (!www_authorize("", "subscriber")) {
			# authentication failed -> do challenge		
			www_challenge("", "0");
			exit;
		};
		# after DB authentication, the password is available
		# in $avp(i:55) because of the "load_credentials"
		# module parameter.
		xlog("SCRIPT: storing password <$avp(i:55)>\n");
		# use a 20 minutes lifetime for the password;
		# after that, it will erased from cache and we do
		# db authentication again (refresh the passwd from DB)
		cache_store("local","passwd_$tu","$avp(i:55)",1200);
	}

	....
}

References:

  1. auth module - see functions and parameters
  2. auth_db module - see functions and parameters

Improvements

You can easily add 2 improvements to the previous script.

Force password re-fetching

When PV authentication (based on cached password) fails because of invalid password (see the error codes of the pv_www_authorize() function). So, if the function returns "-2" (invalid password) it may mean that the password may changed (in DB), so you need to re-fresh.

In such a case, you can simple remove the cached password and try to do DB authentication (that will use the DB password). Of course, after such a re-load, store into the cache the new value.

WWW and PROXY authentication

You can use the same cached password for both WWW (REGISTER) and PROXY (INVITE, MESSAGE, etc) authentication. The logic is the same in both blocks (WWW and PROXY) and you can share the same cached password for both blocks. This will dramatically reduce the number of DB queries.

NOTE: for WWW authentication the authentication name is extracted from TO hedear, but for PROXY authentication the auth name is extracted from FROM header, so when operating with the cache, build the attribute name as "passwd_$tU" for WWW auth and as "passwd_$fU" for PROXY auth.

Performance estimation

Assuming a 30 minute registration period and placing a call each 20 minutes, without any caching, there will be 5 authentication queries to DB per hour per user.

This means, for 1000 users, per day : 1000 * 3 * 24 = 72000 queries per day for auth.

If you set a 2 hours lifetime for cached data, you have one query per user at each 2 hours.

So, for the same 1000 users, per day, you have : 1000 * 0.5 * 24 = 12000 queries per day for auth

So, this gives you a reduction to with 83% (to 17%) of the numbers of queries!


(:nl:)>>messagehead<<

aidanna?13 August 2010, 04:37

Thanks guys for the tutorial on the caching API. Using a layered localcache -> memcache -> db scheme (where our application controls the last two), we've been able to see almost a 95% performance gain after tuning compared to a straight Opensips 1.4.5 db only scheme.

(:nl:)>>messagehead<<

Manas?08 February 2011, 14:59

How do the timeout value specified in the cache_store method interact with the cache_clean_period specified at the module level?

 		cache_store("local","passwd_$tu","$avp(i:55)",1200);

modparam("localcache", "cache_clean_period", 600)


For example: at 10:00 - I insert a record with timeout "1200" - so the record is set to expire at 10:20.

For the sake of the example - if the module setting was 1800 - the above record wont be purged till 10:30.

Am I correct?

(:nl:)>>messagehead<<

Cleide?18 March 2012, 05:03

Did you test this patch, i personnaly tisnalled because i need to use distributed cache for apache ssl cache but it could not retreive the session from cache, session is setted successly but when retriving it it tells memcache scache get_session' CORRUPT'when i look in memcache it seems that the session is bad because it contains lines of logthank you for reply

(:commentboxchrono:)

to:

(:redirect Documentation.Tutorials-MemoryCaching quiet=1 :)

August 21, 2012, at 10:10 AM by bogdan -
Deleted lines 175-180:

(:nl:)>>messagehead<<

Sar?19 August 2012, 18:07

Hi Shawn,Just wondering if it was pisosble for you to share the WordPress cache that you created? I'd love to cache my wordpress pages for 60 seconds (or even longer ). Thanks for your vBulletin Stats plugin for Memcached by the way. Very nice to have that information in a place I visit daily!

August 19, 2012, at 06:07 PM by Sar - Comment added
Added lines 176-181:

(:nl:)>>messagehead<<

Sar?19 August 2012, 18:07

Hi Shawn,Just wondering if it was pisosble for you to share the WordPress cache that you created? I'd love to cache my wordpress pages for 60 seconds (or even longer ). Thanks for your vBulletin Stats plugin for Memcached by the way. Very nice to have that information in a place I visit daily!

March 18, 2012, at 05:03 AM by Cleide - Comment added
Added lines 171-176:

(:nl:)>>messagehead<<

Cleide?18 March 2012, 05:03

Did you test this patch, i personnaly tisnalled because i need to use distributed cache for apache ssl cache but it could not retreive the session from cache, session is setted successly but when retriving it it tells memcache scache get_session' CORRUPT'when i look in memcache it seems that the session is bad because it contains lines of logthank you for reply

May 11, 2011, at 09:18 AM by bogdan - Comments Cleanup
Deleted lines 170-177:

(:nl:)>>messagehead<<

Matei?10 May 2011, 08:28

Good to see a talnet at work. I can’t match that.

May 10, 2011, at 08:28 AM by Matei - Comment added
Added lines 172-177:

(:nl:)>>messagehead<<

Matei?10 May 2011, 08:28

Good to see a talnet at work. I can’t match that.

February 08, 2011, at 02:59 PM by Manas - Comment added
Added lines 153-171:

(:nl:)>>messagehead<<

Manas?08 February 2011, 14:59

How do the timeout value specified in the cache_store method interact with the cache_clean_period specified at the module level?

 		cache_store("local","passwd_$tu","$avp(i:55)",1200);

modparam("localcache", "cache_clean_period", 600)


For example: at 10:00 - I insert a record with timeout "1200" - so the record is set to expire at 10:20.

For the sake of the example - if the module setting was 1800 - the above record wont be purged till 10:30.

Am I correct?

August 13, 2010, at 04:37 AM by aidanna - Comment added
Added lines 149-154:

(:nl:)>>messagehead<<

aidanna?13 August 2010, 04:37

Thanks guys for the tutorial on the caching API. Using a layered localcache -> memcache -> db scheme (where our application controls the last two), we've been able to see almost a 95% performance gain after tuning compared to a straight Opensips 1.4.5 db only scheme.

March 09, 2009, at 07:33 PM by bogdan -
Added line 2:

This page has been visited 15159 times.

March 03, 2009, at 10:47 AM by bogdan -
Changed lines 145-148 from:

So, this gives you a reduction to with 83% (to 17%) of the numbers of queries!

to:

So, this gives you a reduction to with 83% (to 17%) of the numbers of queries!


(:commentboxchrono:)

January 31, 2009, at 07:10 AM by 92.80.76.125 -
Changed lines 135-136 from:
Performance estimation
to:

Performance estimation

January 31, 2009, at 07:09 AM by 92.80.76.125 -
Added lines 134-145:
Performance estimation

Assuming a 30 minute registration period and placing a call each 20 minutes, without any caching, there will be 5 authentication queries to DB per hour per user.

This means, for 1000 users, per day : 1000 * 3 * 24 = 72000 queries per day for auth.

If you set a 2 hours lifetime for cached data, you have one query per user at each 2 hours.

So, for the same 1000 users, per day, you have : 1000 * 0.5 * 24 = 12000 queries per day for auth

So, this gives you a reduction to with 83% (to 17%) of the numbers of queries!

January 30, 2009, at 07:52 PM by 81.180.102.217 -
Added lines 114-117:

References:

  1. auth module - see functions and parameters
  2. auth_db module - see functions and parameters
January 30, 2009, at 07:50 PM by 81.180.102.217 -
Changed line 60 from:

[=

to:

[@

Changed line 107 from:
		cache_store("local","passwd_$tu","$avp(i:55)",1200);
to:
		cache_store("local","passwd_$tu","$avp(i:55)",1200);
Changed lines 112-129 from:

=]

to:

@]


Improvements

You can easily add 2 improvements to the previous script.

Force password re-fetching

When PV authentication (based on cached password) fails because of invalid password (see the error codes of the pv_www_authorize() function). So, if the function returns "-2" (invalid password) it may mean that the password may changed (in DB), so you need to re-fresh.

In such a case, you can simple remove the cached password and try to do DB authentication (that will use the DB password). Of course, after such a re-load, store into the cache the new value.

WWW and PROXY authentication

You can use the same cached password for both WWW (REGISTER) and PROXY (INVITE, MESSAGE, etc) authentication. The logic is the same in both blocks (WWW and PROXY) and you can share the same cached password for both blocks. This will dramatically reduce the number of DB queries.

NOTE: for WWW authentication the authentication name is extracted from TO hedear, but for PROXY authentication the auth name is extracted from FROM header, so when operating with the cache, build the attribute name as "passwd_$tU" for WWW auth and as "passwd_$fU" for PROXY auth.

January 30, 2009, at 07:38 PM by 81.180.102.217 -
Changed line 60 from:

[@

to:

[=

Changed line 112 from:

@]

to:

=]

January 30, 2009, at 07:35 PM by 81.180.102.217 -
Changed line 107 from:
		cache_store("local","passwd_$tu","$avp(i:55)",1200);
to:
		cache_store("local","passwd_$tu","$avp(i:55)",1200);
January 30, 2009, at 07:34 PM by 81.180.102.217 -
Changed lines 47-112 from:
  1. DONE
to:
  1. DONE

Script

Current format of authentication script for REGISTER is:

	if (!www_authorize("", "subscriber")) {
		www_challenge("", "0");
		exit;
	};

By adding memcache support, the script looks like:

....
loadmodule "modules/db_mysql/db_mysql.so"
loadmodule "modules/auth/auth.so"
loadmodule "modules/auth_db/auth_db.so"
loadmodule "modules/localcache/localcache.so"
....
modparam("auth","username_spec","$avp(i:54)")
modparam("auth","password_spec","$avp(i:55)")
modparam("auth","calculate_ha1",1)

modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url","mysql://opensips:opensipsrw@localhost/opensips_1_2")
modparam("auth_db", "load_credentials", "$avp(i:55)=password")
....

....
route[x]{
	.....
	# do we have the password cached ?
	if(cache_fetch("local","passwd_$tu",$avp(i:55))) {
		$avp(i:54) = $tU;
		xlog("SCRIPT: stored password is $avp(i:55)\n");
		# perform auth from variables
		# $avp(i:54) contains the username
		# $avp(i:55) contains the password
		if (!pv_www_authorize("")) {
			# authentication failed -> do challenge			
			www_challenge("", "0");
			exit;
		};
	} else {
		# perform DB authentication ->
		# password will be loaded from DB automatically
		if (!www_authorize("", "subscriber")) {
			# authentication failed -> do challenge		
			www_challenge("", "0");
			exit;
		};
		# after DB authentication, the password is available
		# in $avp(i:55) because of the "load_credentials"
		# module parameter.
		xlog("SCRIPT: storing password <$avp(i:55)>\n");
		# use a 20 minutes lifetime for the password;
		# after that, it will erased from cache and we do
		# db authentication again (refresh the passwd from DB)
		cache_store("local","passwd_$tu","$avp(i:55)",1200);
	}

	....
}
January 30, 2009, at 07:24 PM by 81.180.102.217 -
Added line 2:

(:toc-float Table of Content:)

January 30, 2009, at 07:23 PM by 81.180.102.217 -
Changed lines 45-46 from:
  1. YES
to:
  1. YES -> use the value from the memcache do to authentication from script variables.
  2. DONE
January 30, 2009, at 07:21 PM by 81.180.102.217 -
Changed lines 42-43 from:
  1. no ->
to:
  1. NO -> perform DB authentication
  2. store the used password into "passwd_$tu" with s lifetime (1200 seconds - 10 minutes)
  3. DONE
  4. YES
January 30, 2009, at 07:19 PM by 81.180.102.217 -
Changed lines 41-43 from:
  1. is password
to:
  1. is password stored in "passwd_$tu" attribute?
    1. no ->
January 30, 2009, at 07:18 PM by 81.180.102.217 -
Added lines 10-11:

Changed line 25 from:
to:

January 30, 2009, at 07:18 PM by 81.180.102.217 -
Changed lines 8-9 from:

The idea is to be able to store (cache) custom values for later usage. The main purpose of this MemCache support is to reduce the number of DB queries by caching data that does not need constant update from DB. DB queries are known to be one of bottle necks in the current design (see design considerations and MemCache support will help in avoiding unnecessary DB hits.

to:

The idea is to be able to store (cache) custom values for later usage. The main purpose of this MemCache support is to reduce the number of DB queries by caching data that does not need constant update from DB. DB queries are known to be one of bottle necks in the current design (see design considerations) and MemCache support will help in avoiding unnecessary DB hits.

Added lines 19-20:

The MemCache design from OpenSIPS allow to set a lifetime (timeout) to an attribute when inserting it in the cache. This provides support for auto-removal of attributes (for re-fetching or clean-up purposes) from the cache.

Added lines 23-39:

MemCache usage - Password caching for DB authentication

The best way of describing the MemCache way of usage is to provide a real example - how to use memcache support for reducing the DB queries due user authentication.

The idea - how to

The idea is, after performing a DB authentication (authentication by fetching the password from DB) to store the password in memcache; the password is stored with a certain lifetime to ensure that from time to time the password is read from DB again.

When a new authentication is needed, first we check if the password is available in memcache (previously stored and not yet expired); if so, we use the value from there to perform authentication without a DB hit.

As we have to store in the same time the passwords of more than one users, we need to use different names for the attributes -> the attribute name will contain the user name, something like "passwd_username".

The logic - diagram

  1. REGISTER request received
  2. is password
January 30, 2009, at 07:04 PM by 81.180.102.217 -
Changed lines 4-5 from:

OpenSIPS MemCache Design

to:

OpenSIPS MemCache

The Memory Caching support from OpenSIPS wants to provide a way of caching at runtime different kind of data. These data will globally available (anywhere in the routing script) and shared between all OpenSIPS processes.

The idea is to be able to store (cache) custom values for later usage. The main purpose of this MemCache support is to reduce the number of DB queries by caching data that does not need constant update from DB. DB queries are known to be one of bottle necks in the current design (see design considerations and MemCache support will help in avoiding unnecessary DB hits.

OpenSIPS MemCache Design

January 30, 2009, at 06:58 PM by 81.180.102.217 -
Changed lines 4-5 from:

OpenSIPS memcache

to:

OpenSIPS MemCache Design

The Memory Caching support in OpenSIPS has a flexible and expendable design. The idea is to have a simple and transparent way of operating (in the same time) with multiple implementations / forms of memory caching. A memory caching system can be via the local shared memory (see Local Cache module) or via the System V shared memory (mem cache shared across independent applications) or via the MemCache server.

The OpenSIPS core offers an API for operating with any memory caching system from the script. This API is composed out of three functions that allow the basic operations with a memory cache:

  • store - cache_store()
  • fetch - cache_fetch()
  • remove - cache_remove()

The implementations for the memory caching support are provided by the OpenSIPS modules. Right now there is a single implementation (see Local Cache module) that caches the data into the shared memory of OpenSIPS. In the future release, more implementations are planned to be added.

January 30, 2009, at 06:29 PM by 81.180.102.217 -
Added lines 1-5:

Resources -> Documentation -> Tutorials -> Memory Caching


OpenSIPS memcache


Page last modified on April 24, 2013, at 07:02 PM