1

At work we ran up against the problem of setting server-side cookies - a lot of them. Right now we have a PHP script, the sole purpose of which is to set a cookie on the client for our domain. This happens a lot more than 'normal' requests to the server (which is running an app), so we've discussed moving it to its own server. This would be an Apache server, probably dedicated, with one PHP script 3 lines long, just running over and over again.

Surely there must be a faster, better way of doing this, rather than starting up the whole PHP environment. Basically, I need something super simple that can sit around all day/night doing the following:

  1. Check if a certain cookie is set, and
  2. If that cookie is not set, fill it with a random hash (right now it's a simple md5(microtime))

Any suggestions?

colinmarc
  • 2,421
  • 1
  • 22
  • 34
  • Can you give a little more detail? Why would you set cookies more than 'normal' requests? Maybe tell us when and why you update cookies, and we might have a suggestion. – Mikecito Apr 28 '11 at 05:13
  • I could tell you, but then I'd have to kill you :). I'm just wondering if there's a faster, perhaps more dedicated way to set a cookie than with PHP. The cookies never get updated - just set, once, then read by other things (the app, a tracking pixel on some other pages, etc). – colinmarc Apr 28 '11 at 05:16
  • You could try setting them directly with Apache or something, but something else seems amiss here. Cookies shouldn't require a dedicated server. Maybe you can pawn some of the processing off on the client instead of the server? Without knowing the context of how the cookies are used and how often, it's hard to give much insight. Maybe consider using a session variable to avoid reading the cookie over and over? Not sure what you really need without more info. – Mikecito Apr 28 '11 at 05:32
  • In order to set a cookie for that domain, it needs to be in the http headers for the response. (http://en.wikipedia.org/wiki/HTTP_cookie#Setting_a_cookie). So setting it with Apache is perhaps an option. – colinmarc Apr 28 '11 at 05:35

4 Answers4

0

You could try using mod_headers (usually available in the default install) to manually construct a Set-Cookie header and emit it -- no programming needed as long as it's the same cookie every time. Something like this could work in an .htaccess file:

Header add Set-Cookie "foo=bar; Path=/; Domain=.foo.com; Expires=Sun, 06 May 2012 00:00:00 GMT"

However, this won't work for you. There's no code here. It's just a stupid header. It can't come up with the new random value you'd want, and it can't adjust the expire date as is standard practice.

This would be an Apache server, probably dedicated, with one PHP script 3 lines long, just running over and over again. [...] Surely there must be a faster, better way of doing this, rather than starting up the whole PHP environment.

Are you using APC or another bytecode cache? If so, there's almost no startup cost. Because you're talking about setting up an entire server just for this, it sounds like you control the server as well. This means that you can turn off apc.stat for even less of a startup hit.

Really though, if all that script is doing is building an md5 hash and setting a cookie, it should already be blisteringly fast, especially if it's mod_php. Do you already know, though benchmarking and testing, that the script isn't performing as well as you'd like? If so, can you share those benchmarks with us?

Charles
  • 50,943
  • 13
  • 104
  • 142
  • I don't... there isn't a problem yet. But we're cautious of serving stuff ourselves, because we use a CDN for most stuff. – colinmarc May 07 '11 at 01:36
  • What's the rest of your technology stack? Can you tell us more about your general performance concerns? – Charles May 07 '11 at 01:39
  • We've got a CentOS server and a RedHat Server. We're not necessarily limited in that regard, though. – colinmarc May 07 '11 at 01:42
  • I meant, what language and platform powers your site? PHP? Perl? Python? Ruby? Java or something on the JVM? Server-side JS? ColdFusion? Mono? COLBOL? INTERCAL? – Charles May 07 '11 at 01:52
  • Most of the app is PHP, using the CakePHP framework. But there is various machinery (log parsing, etc) in Python. – colinmarc May 07 '11 at 02:01
  • Great! You've got APC installed and running, right? Next, install [xhprof](http://mirror.facebook.net/facebook/xhprof/) on the production machine(s). It'll let you measure the actual performance of everything from your main code to the three-line script. Determine what the actual performance is, and start keeping metrics on it. Make sure that it's remaining stable over time, as the site grows. You *probably* don't need to do a darn thing until you decide that performance on the three line script is insufficient or if it's reaction time increases as your site grows. – Charles May 07 '11 at 02:17
  • Be aware that Apache isn't the fastest httpd in the world. Consider looking into lighttpd or nginx, and/or a high-performance reverse proxy like Varnish. If you're *really* concerned about performance, then those might be superior options for you. – Charles May 07 '11 at 02:20
0

It would be interesting to know why do you think you need extra server - do you actually have a bottle neck for generating the cookie or somewhere else ? Is it the log writing as requests happen alot ? ajax polling ? Client download speed ?

Atleast for starters, i'd look something more efficient than fetching time to generate the "random hash". For example, on this intel i7 laptop i have, generating 999999 md5 hashes from microtime takes roughly about 4 seconds and doing same thing with random numbers is second faster (not taking a seeding of rand into account).

Then, if you take opening/and closing of socket into account, just moving your script (which is most likely already really fast - that is, without knowing how your pages take that into account), you will end up actually slowing down the requests. Actually, now that i've re-read your question, it makes me think that your cookie setter script is already a dedicated page ? Or do you just "include" into real content served by another php script? If not, try that approach. Also this would beneficial if you have default logging rules for apache, if cookies are set in on own page, your apache will log a row for that and in high load systems, this will cumulate to total io time spend by apache.

Also, consider that testing if cookie is set and then setting it, might be slower than just to forcefully set it always even if cookie exists or not ?

But overall, i don't think you'd need to set up a server just to offload cookie generation without knowing more about how you handle the cookies now.. Unless you are doing something really nasty.

rasjani
  • 7,372
  • 4
  • 22
  • 35
  • nothing evil, I promise! It's a dedicated page, to answer your question. – colinmarc May 09 '11 at 19:32
  • Ok, then if its dedicated page then i'd – rasjani May 10 '11 at 10:31
  • Ok, then if its dedicated page then i'd say that you will gain abit of time for roundtrip time when client queries your cookie page and combine that with faster cookie/hash generation. See: http://stackoverflow.com/questions/3665247/php-fastest-hash-for-non-cryptographic-uses – rasjani May 10 '11 at 10:54
0

Apache has a module called mod_usertrack which looks like it might do exactly what you want. There's no need for PHP and you could likely create a really optimised lightweight Apache config to serve this with.

If you want to go for something even faster and are happy to not use Apache you could use lighttpd and it's mod_usertrack or nginx's HttpUserId module

James C
  • 14,047
  • 1
  • 34
  • 43
0

You could create a simple http server yourself to accept requests and return the set-cookie header and empty body. This would allow you to move the cookie generation overhead to wherever you see fit.

I echo the sentiments above though; Unless cookie generation is significantly expensive, I don't think you will gain much by moving from your current setup.

By way of an example, here is an extremely simple server written with Tornado that simply sets a cookie on GET or HEAD requests to '/'. It includes an async example listening for '/async' which may be of use depending on what you are doing to get your cookie value.

import time
import tornado.ioloop
import tornado.web


class CookieHandler(tornado.web.RequestHandler):
    def get(self):
        cookie_value = str( time.time() )
        self.set_cookie('a_nice_cookie', cookie_value, expires_days=10)
        # self.set_secure_cookie('a_double_choc_cookie', cookie_value)
        self.finish()

    def head(self):
        return self.get()


class AsyncCookieHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        self._calculate_cookie_value(self._on_create_cookie)

    @tornado.web.asynchronous
    def head(self):
        self._calculate_cookie_value(self._on_create_cookie)

    def _on_create_cookie(self, cookie_value):
        self.set_cookie('double_choc_cookie', cookie_value, expires_days=10)
        self.finish()

    def _calculate_cookie_value(self, callback):
        ## meaningless async example... just wastes 2 seconds
        def _fake_expensive_op():
            val = str(time.time())
            callback(val)
        tornado.ioloop.IOLoop.instance().add_timeout(time.time()+2, _fake_expensive_op)



application = tornado.web.Application([
    (r"/", CookieHandler),
    (r"/async", AsyncCookieHandler),
])


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Launch this process with Supervisord and you'll have a simple, fast, low-overhead server that sets cookies.

Rob Cowie
  • 22,259
  • 6
  • 62
  • 56