I am researching possibilities of using memcached as a session storage for a system built on CodeIgniter. Has anybody done this before(that's probably a stupid question :) and if so what's your experience folks? Have you used any existing libraries/extensions?
As far as performance improvement what have you seen? Any caveats?
Having PHP put the sessions into Memcache directly, rather than through framework code is easy - it's just changing two lines in the PHP.ini:
# see http://php.net/manual/en/memcache.ini.php
session.save_handler = memcache
session.save_path="tcp://127.0.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15"
This uses the slightly older (but still entirely supported) 'memcache' extension from PECL.
You can choose the CodeIgniter Multicache Library, which can be found here: http://www.haughin.com/code/multicache/
In the code you can simple use like this:
$this->load->library('cache');
//To use memcache
$this->cache->useMemcache($iptomemcache, $port); /*if you want, you can check to see if the connection even worked, as this will return false if the connection failed.*/
$this->cache->save('testkey', 'testdata', NULL, 3600); /*caches the testdata string for 1 hour. */
echo $this->cache->get('testkey');
//To switch back to file based caching
$this->cache->useFile();
//etc.
It's not practical to use Memcached for storage of relational data (like MySQL); it would be inefficient to request each item from Memcached and then test to see if it matches a query. There are better solutions to a problem like that (consider Memory tables in MySQL, for instance).
On the other hand, if you're looking for simple key/value storage, that's certainly a practical application for Memcached. What I'd be a little wary of, though, is writing a CodeIgniter driver for it. The interface for Memcached in PHP is already dead simple:
$memcached->get('my key');
$memcached->set('my key', 'my value');
I would suggest simply using the Memcached classes directly. Adding all the extra overhead to CI just seems dirty and unnecessary to me.
On the flip-side of that, I've seen implementations of Memcached used for CodeIgniter's session engine. That's certainly a very valid reason to write a driver, and I would highly encourage it (sessions are a pain in the neck to scale).
Good luck
Related
Is there a way in PHP to use "out of session" variables, which would not be loaded/unloaded at every connexion, like in a Java server ?
Please excuse me for the lack of accuracy, I don't figure out how to write it in a proper way.
The main idea would be to have something like this :
<?php
...
// $variablesAlreadyLoaded is kind of "static" and shared between all PHP threads
// No need to initialize/load/instantiate it.
$myVar = $variablesAlreadyLoaded['aConstantValueForEveryone'];
...
?>
I already did things like this using shmop and other weird things, but if there is a "clean" way to do this in "pure PHP" without using caching systems (I think about APC, Redis...), nor database.
EDIT 1 :
Since people (thanks to them having spent time for me) are answering me the same way with sessions, I add a constraint I missed to write : no sessions please.
EDIT 2 :
It seems the only PHP native methods to do such a thing are shared memory (shmop) and named pipes. I would use a managed manner to access shared objects, with no mind of memory management (shared memory block size) nor system problems (pipes).
Then, I browsed the net for a PHP module/library which provides functions/methods to do that : I found nothing.
EDIT 3 :
After a few researches on the way pointed out by #KFO, it appears that the putenv / setenv are not made to deal with objects (and I would avoid serialization). Thus, it resolves the problem for short "things" such as strings or numbers but not for more large/comples objects.
Using the "env way" AND another method to deal with bigger objects would be uncoherent and add complexity to the code and maintenability.
EDIT 4 :
Found this : DBus (GREE Lab DBus), but I'm not having tools to test it at work. Has somebody tested it yet ?
I'm open to every suggestion.
Thanks
EDIT 5 ("ANSWER"):
Since DBus is not exactly what I'm looking for (needs to install a third-party module, with no "serious" application evidence), I'm now using Memcache which has already proven its reliability (following #PeterM comment, see below).
// First page
session_id('same_session_id_for_all');
session_start();
$_SESSION['aConstantValueForEveryone'] = 'My Content';
// Second page
session_id('same_session_id_for_all');
session_start();
echo $_SESSION['aConstantValueForEveryone'];
This works out of the box in PHP. Using the same session id (instead of an random user-uniqe string) to initialize the session for all visitors leads to a session which is the same for all users.
Is it really necessary to use session to achieve the goal or wouldn't it better to use constants?
There is no pure PHP way of sharing information across different
threads in PHP! Except for an "external"
file/database/servervariable/sessionfile solution.
Since some commentators pointed out, that there is serialize/unserialize functionality for Session data which might break data on the transport, there is a solution: In PHP the serialize and unserialize functionality serialize_handler can be configured as needed. See https://www.php.net/manual/session.configuration.php#ini.session.serialize-handler It might be also interesting to have a look at the magic class methods __sleep() and __wakeup() they define how a object behaves on a serialize or unserialize request. https://www.php.net/manual/language.oop5.magic.php#object.sleep ... Since PHP 5.1 there is also a predefined Serializable interface available: https://www.php.net/manual/class.serializable.php
You can declare a Variable in your .htaccess. For Example SetEnv APPLICATION_ENVIRONMENT production and access it in your application with the function getenv('APPLICATION_ENVIRONMENT')
Another solution is to wrap your variable in a "persistent data" class that will automatically restore its data content every time the php script is run.
Your class needs to to the following:
store content of variable into file in __destructor
load content of variable from file in __constructor
I prefer storing the file in JSON format so the content can be easily examined for debugging, but that is optional.
Be aware that some webservers will change the current working directory in the destructor, so you need to work with an absolute path.
I think you can use $_SESSION['aConstantValueForEveryone'] that you can read it on every page on same domain.
Consider to refer to it's manual.
I have never used memcache before now so please excuse my inexperience. Although it is pretty self explanatory, I would like to make sure I am using the built in functions correctly as I am creating a class that will be used commercially so it must be correctly coded and efficient.
I have several questions but as they are very basic I felt it would be alright to combine them into one Stackoverflow question.
If they require an essay answer, please dont bother and I will post it up as a separate question
When would I need to use memcache::addServer and what is the difference between this and memcache::connect?
Does memcache overwrite stored values if it runs out of memory, even if the item has not yet expired?
What would I use memcache::getExtendedStats for?
How do I check to see if a connection to memcache already exists and if not, create a connection?
If I have my usual memcache server of 'localhost' set up, how would I go about setting up another memcache server on my same dedicated server?
Apart from more memory, what is the benefit of having more than one memcache server?
Should I check for memcache server updates regularly?
Does it use a lot of memory to run memcache::connect at the beginning of each page, even if I am not using it?
When am I likely to return errors and how do I catch these?
Most importantly, if I am using memcache within another class that has several methods that may be called more then once per script, how should I go about initialising the object and connecting to the server within each method?
My guess for the last question would be to do it like so:
class test {
public function blah(){
// Make sure the memcache object is accessible
global $memcache;
// Do something ...
// Save result in memcache
$memcache->set(...);
}
public function foo(){
// Do something ...
// No use for memcache
}
}
// Initialise each class
$test = new test;
$memcache = new memcache;
$memcache->connect(...);
// Call some methods from the test class
$test->blah();
$test->foo();
$test->blah();
As you can see in the above example, I connect to the memcache server at the beginning of the script. If I was to include this at the beginning of every page, even on pages that do not use memcache, would this increase the response time a lot or minimal amounts? Hence, question 8!
You might need some coffee or something before you read this:
You'd want to use Memcache::addServer when you need to add more Memcached servers. For example, if you had a really busy website or web app... you'd probably want to have more than one Memcached server running1. Memcache::connect is used when you want to start a connection to one of your Memcached servers. Also, according to the Memcache::addServer docs, another difference between Memcache::addServer and Memcache::connect is that with Memcache::addServer, the connection is not established until actually needed2.
If Memcached runs out of RAM, it will discard the oldest values3.
Memcache::getExtendedStats is used to check information about your Memcached server. For example, if you need to find out how long the server has been up (uptime,) how many connections the server has, or general server usage4, this is a great tool.
Probably the easiest way to check if a connection to Memcached already exists is to check your $memcache connection variable to see if it returns TRUE5. If you need to have a persistent connection (that keeps on going even after your script ends,) there is the option to use Memcache::pconnect6.
If you want to have two Memcached servers going on... and your first server is already your localhost, you will most likely need to have a separate, distinct server for the second7.
At least one other benefit of having more than one Memcached server is the idea that whenever you diversify your data (or servers,) even when one server goes down... you still have however many other servers there to pick up the pieces. Memcached looks8 like it is distributed over however many servers you have running... so if a server goes down, you are still losing that part of the cache. But, you do still have other servers up and running to help keep going.
In general, it's not a bad idea to keep almost any type of software up to date. It looks like Memcached is still a highly active project9 so you may want to update it when you can. But the essence of Memcached doesn't seem to change a whole lot over past versions... so, it might not be as critical to update it compared to something like operating system software.
It sounds like the way that Memcached allocates memory for TCP connections (when you make a call to your Memcached server via Memcache::connect,) does end up costing you memory10. If you are sure you aren't going to need that connection on some of your pages, you may want to avoid making that connect call.
Hard to say what type of errors might come up in your code. But, with something like Memcached, you may find errors coming up when you are running out of memory11.
Like the answer to question eight, I would still recommend trying to only call that $memcache->connect() in areas where you absolutely need it. You might be using Memcached in a lot of your application or scripts; but there still will probably be places where you won't need it.
As far as your code idea for question 10 goes, it's really up to you as far as the implementation goes. In general, it's good to try to avoid global variables12 when possible, though. Instead, like that article (12) in the footnote talks about, it's easier to just use a singleton class call for a connection... and then just call that each time you want to make a connection.
Wow, my eyes are tired. I hope this helps, man...!
1 http://en.wikipedia.org/wiki/Memcached (see Architecture section)
2 http://www.php.net/manual/en/memcache.addserver.php
3 http://en.wikipedia.org/wiki/Memcached (see Architecture section)
4 http://www.php.net/manual/en/memcache.getextendedstats.php
5 http://www.php.net/manual/en/memcache.connect.php (see Return Values section)
6 http://www.php.net/manual/en/memcache.pconnect.php
7 http://www.php.net/manual/en/memcache.addserver.php#101194
8 Benefits of multiple memcached instances
9 http://code.google.com/p/memcached/
10 http://www.facebook.com/note.php?note_id=39391378919 (from Facebook's point of view)
11 http://groups.google.com/group/memcached/browse_thread/thread/9ce1e2691efb283b
12 How to avoid using PHP global objects?
I've been caching the output buffer of pages lately, but now I want to cache the values of variables.
I have a PHP file that does a bunch of MySQL queries, then fills variables with various data from those queries.
Some of those variables will never change but some will change quite often. How can I cache certain variables in this manner? I'm using file-based caching, if it helps.
Yup, file based caching is an option.
There are also other options like memcache and APC
You should have a look at these as well. If your application is putting a lot of load on your MySQL server, and if your DB is already optimized, caching is a step you can take.
You can dump any variable (including an array) using serialize, and the inverse is unserialize.
Dumping to a file would be quite a useless cache solution, you can consider using memcache which can store any variable in memory, but requires some work on server side.
I find that a local mysql with MEMORY tables can be useful, too...
I dont know, how you structured your current caching stuff, so this is just a short template on how you can save any kind of variable (as long as its content is serializeable) to a file.
file_put_contents($filename, serialize($variable));
Since you asked about file-based caching, both memcache and APC are no option, although I would certainly recommend both in cases where the stored data is not too large.
For file based caching, I would recommend you to use a caching framework. For example, you could use Zend_Cache from the Zend Framework. It allows you to store your query results in files by using a nice object oriented interface. Plus, you've got a lot of options, such as validation and serialization. There are also other caching frameworks out there.
I'm working on a big project with several http servers that use one main sql database.
The project has many settings that are frequently used(almost every request).
The settings are stored in the main sql database.
I wanted to know, if there is some way to initialize settings only once in php, because it makes no sense for every request to go and read same setting from sql server over and over again, it feels like a waste of resources.
Thanks in advance
2 solutions:
Create a (perhaps also PHP) script that exports settings from database into a plain text file, and includes that file on every http server;
use a memory cache server like http://memcached.org/ and preload data there from an external script, then have http servers connect to memcache instead of SQL.
Edit: Other than that, PHP does not give you a real web application, where you "run" your application and it has its own memory and persistant, global variables. This is one of the reasons I personally got tired of PHP and moved to Python (and Django, specifically).
Hard code these settings in your PHP code.
// Your current code, somthing like this:
$setting_1 = getDataFromMySQL('setting1');
// Hard coded
$setting_1 = TRUE;
You can use shared memory in php if it is compiled that way.
Another possibility is that you store a combined value of your settings as PHP code in one field (a PHP array for example), then you can read them all with only one query to the DB server. Of course this cached value have to be updated when settings change.
APC is the best solution if you are using a single server, otherwise I would go with memcached. However, you may also consider a MYSQL memory table, it is very efficient for fast reads and writes. Another solution is using Linux to keep and call settings with Linux exec. However, this might be a trouble and there might be some security issues. Also let me remind you that efficient INNODB indexes can help you a lot. MYISAM is also considered a good "read" performer, however my benchmarks show me that INNODB indexes are faster.
You can store the settings in the user's session -
session_start();
if (!isset($_SESSION['settings'])) {
$settings_array = //pulled from database
$_SESSION['settings'] = $settings_array;
}
That way, it'll only query once per user
You could use a session to store those settings.
i'm planning on making my own custom session handling functions. i want to save it in the database but i have some doubts.
is it viable or will just slow down my app?
i have to save the session after each set or can i just save it all at once? because i had this idea to put this function in the class destructor method. so, when the program ends, it will save the data in the database.
but how can i use my other class (database class) for this, being sure it won't be destructed before the session class?
if the user quits the connection and the app stops running, the destructor will still be called?
so, what do you guys think? what do you suggest me to do?
I use DB sessions all the time with Zend and Symfony so its definitely viable, there will be a cost of course but most likely nothing significant.
Normally the way these handlers work is to use session_set_save_handler that way it works as normal except for the actual function called which writes the data. However pay attention to the warnings about object destruction.
Yes it will normally be slightly slower than PHP's native session handler, however it shouldn't be noticeable. This is unless you are having problems with file locking issues (like Windows does)
Why would you want to permanently store session data?
Usually people use different session handlers to make application faster (we use memcache for sessions, because our application is quite complex and distributed and we want it to run fast). I consider this requirement as bad application design, if you want to track your visitors in some way, there are a lot of better ways doing it. Or you are using session for the things it is not quite intended/suitable for. Of course i can imagine that there might be that kind of requirement, just i dont think that this is the case.