Apache Cassandra + PHPcassa + Code Igniter = large scale PHP app in 5 minutes


I’m working on a new project, migrating an existing site using custom code with a very monolithic design on top of MySQL.

Design goals : Implement all the same functionality using a manageable framework with a small footprint on a distributed NoSQL database.
Small footprint? I’m thinking Code Igniter (CI)… Distributed NoSQL (my favorite part)? I’m thinking Apache Cassandra!!!
First problem…issue, whatever you want to call it. CI is built with SQL DB tied in fairly tightly. How do I separate the two without hacking the CI core and allow me to have the flexibility of upgrading CI in the future? And at the same time being able to integrate Cassandra tightly enough to not make it stand out like a penguin in Africa  sore thumb?

Enough with the questions, I’m very new to CI so this took me about an hour to make it happen. The idea is, CI provides a $this->db object when “database” is one of the auto loaded options. I want to still have this db instance available but providing  methods to access Cassandra. I also want this to be auto loaded and available in all controllers… So how?

PHPCassa is probably one of the best PHP client libraries available for Cassandra so the choice on library was about 20 seconds. Since I wasn’t going to use raw thrift calls, this choice was even easier.

Get started then:
Create a file, in your application/config folder, name it cassandra.php i.e. application/config/cassandra.php
In that file add the following:

<?php
$servers[0] = array('host' => '192.168.2.6', 'port' => 9160);
$servers[1] = array('host' => '192.168.2.7', 'port' => 9160);
$servers[3] = array('host' => '192.168.2.8', 'port' => 9160);
$config['cassandra_servers'] = $servers;
$config['keyspace'] = "Keyspace1";
$config['default_cf'] = "Standard1";

The servers array should be obvious, its a list of servers you want to have available for your connection
pooling stuff. It’ll later be accessible using:

$this->CI->config->item('cassandra_servers')

The next config option is the Keyspace your application will use, this allows you to specify only a single Keyspace
since, ideally an application would only use one of these. This is later accessible through:

$this->CI->config->item('keyspace')

The final option is a default column family. This column family is the one that will be available when CI initialises
the database object, db.Later available using:

$this->CI->config->item('default_cf')

That’s it for the configuration file… Next up, our Cassandra library or libraries should I say…
At this point its important to say that if you have database being auto loaded then the following may
not be what you want to do.
In application/libraries create a file called db.php i.e. application/libraries/db.php

<?php

require_once('phpcassa/connection.php');
require_once('phpcassa/columnfamily.php');

/**
 * @author Courtney
 */
class Db {

    private $CI;
//    public $db;
    private $conn;
    /**
     * @var ColumnFamily
     */
    private $cf;

    /**
     * Init connection for the database using the settings in the cassandra.php
     * config file...
     */
    public function __construct() {
        $this->CI = & get_instance();
        try {
            $this->conn = new Connection($this->CI->config->item('keyspace'),
                            $this->CI->config->item('cassandra_servers'));
        } catch (Exception $e) {
            show_error( $e->getMessage());
        }
        $this->cf = $this->CI->config->item('default_cf');
//        $this->db = $this;
    }

    /**
     * Creates a new instance of the given CF which will be returned
     * for interaction by <code>cf()</code>
     * @param string $cf The column family to interact with
     */
    public function setCF($cf) {
        $this->cf = new ColumnFamily($this->conn, $cf);
    }

    /**
     * Returns the instance of the last column family created by
     * calling <code>setCF()</code>... If setCF hasn't been called
     * then the default_cf set in cassandra.php config file is returned,
     * once setCF is called then the last one to be set is always returned.
     * @return ColumnFamily
     */
    public function cf() {
        return $this->cf;
    }

}

This approach is the most simplistic I could think of for this blog post, ideally you’d want to cache
the Column family objects you create so that a new instance isn’t created every time you use a different CF.
There will is a basic caching version implemented on the github page hosting this project’s files… available here
https://github.com/zcourts/cassandraci
Its important to name the file db.php if you want to be able to access the database instance using $this->db as you
would if it was the native CI MySQL object. That purely because CI automatically creates an instance of your library
using the name of the file or class (Not sure but file =db.php class =Db.php so…)
The next important step, download phpcassa… Its available here https://github.com/thobbs/phpcassa
Extract its contents and put its files into application/libraries/phpcassa, the structure needs to be in the form
to allow db.php to include “phpcassa/ColumnFamily.php”; etc… You only need the .php files from php cassa and
everything in the Thrift folder, docs and test folder aren’t used so they can be left out.

Next you need to change your autoload.php file
the settings need to look like:

$autoload['libraries'] = array('db','otherlib');

Unless I’ve forgotten something, that should be it…
Now in any of your controllers or files where autoloaded libraries are available, you can use
$this->db-cf()->phpCassaMethod();  to access Cassandra.
Feel free to ask any questions…comment suggestions are all welcome.

About these ads

27 Responses to Apache Cassandra + PHPcassa + Code Igniter = large scale PHP app in 5 minutes

  1. Pingback: Courtney Robinson’s Blog: Apache Cassandra+PHPcassa+Code Igniter = large scale PHP app in 5 minutes | Development Blog With Code Updates : Developercast.com

  2. Andy Leon says:

    Nice technique, although I do have one issue with what you’ve written… certain types of penguin are actually native to Africa ;)

    • Courtney says:

      lool, thanks, should be more specific and say “Northern Africa”?

  3. Pingback: A semana no mundo PHP (15/04/2011) | raphael.dealmeida

  4. Alex Hernandes says:

    Anyone get this on vps dreamhost?

    • Courtney says:

      I managed to get it working on DH’s vps but that was more than a year a go, not too long after they started offering VPSs (Assuming you mean Cassandra)

      • Alex Hernandes says:

        I will try install on dh’s vps, thank you so much

        • Courtney says:

          No problem, good luck

  5. Andy Liang says:

    Hi Courtney.

    Thanks for the nice tutorial. I tried to install it locally, but I got the following error:
    Fatal error: Call to undefined method Db::query() in C:\wamp\www\phpcassa\application\controllers\home.php on line 10

    is there anything that I missed?

    thanks

    Andy

    • Courtney says:

      http://php.net/manual/en/language.oop5.paamayim-nekudotayim.php double colon in php is for accessing static methods and constants etc, as described at that URL.
      See the example project on github, my home.php controller here for e.g. https://github.com/zcourts/cassandraci/blob/master/application/controllers/home.php
      Line 10 uses $this->db->query()->insert(‘key’, array(‘column1′ => ‘value1′, ‘column2′ => ‘value2′)); not Db::query. I’m assuming here that you followed the tutorial and didn’t download my code… see if that URL with home.php helps and let me know. If not I might need to see the code to get a better idea of what you have.

      • Andy Liang says:

        Thanks for the quick response. I download the example project and spent a whole day to test it, but I still have some issue. i will be greatly appreciated if you could give me any adive.

        Here is what I did and test:

        1) download cassandra 1.0.6
        2) download codeigniter 2.1
        3) download phpcassa and extract it to the new codeigniter application/libraries/phpcassa folder
        4) download cassandraci
        4.1) copy and modify cassandra.php to the new codeigniter, and modify autoload
        (I use only single node, so I used 127.0.0.1:9160 )
        4.2) copy home.php to the new codeigniter application/controlers folder
        4.3) copy db.php to the new codeigniter application/libraries folder
        4.3) copy home.php to the new codeigniter application/views folder

        5) create keyspace Keyspace1;
        6) create column family Standard;

        7) test http://localhost/CodeIgniter_21/index.php/home

        I got the following error:
        Fatal error: Uncaught exception ‘NoServerAvailable’ with message ‘An attempt was made to connect to every server twice, but all attempts failed. The last error was: TTransportException:TSocket: timed out reading 4 bytes from 127.0.0.1:9160′ in C:\wamp\www\CodeIgniter_21\application\libraries\phpcassa\connection.php on line 233

        NoServerAvailable: An attempt was made to connect to every server twice, but all attempts failed. The last error was: TTransportException:TSocket: timed out reading 4 bytes from 127.0.0.1:9160 in C:\wamp\www\CodeIgniter_21\application\libraries\phpcassa\connection.php on line 233

        8) You could download my code at http://www.ipplate.com/cassandratest/CodeIgniter_21.zip

        9) I also test the cassandra and phpcassa without codeigntier, cassandra and phpcassa are working fine with the demo at http://asaddurrani.wordpress.com/2011/07/09/complete-cassandra-guide-for-cassandra-beginners-with-php-demo-app/

        thanks

        Andy

        • Courtney says:

          Sorry, that’s probably my fault for not stating the versions I use. First look at your error and it seems you didn’t upgrade the thrift version, or rather phpcassa. I don’t have a machine setup to test any of this right now but if you just download https://github.com/thobbs/phpcassa the latest version should work. I’ll check it out later, upgrade everything and then update this post. Look at my project on github again, there is folder, phpcassa in application/libraries

          • Andy Liang says:

            In my code, I had replaced application/libraries/phpcassa with the update version from https://github.com/thobbs/phpcassa. not too sure what’s wrong with my code. I am looking forward to the update of your post. thanks a lot. Andy

          • Courtney says:

            I did a quick update, see https://github.com/zcourts/cassandraci (make sure the branch is cassandra1.0.6 NOT MASTER)
            It uses code igniter 2.1, cassandra 1.0.6 and phpcassa-0.8.a.2
            Look at application/config/cassandra use the clie and run


            connect localhost/9160;
            create keyspace Keyspace1;
            use Keyspace1;
            create column family Standard1;

            Then look at the controller, welcome and its welcome_message view
            In config.php notice I autoload the cassandra config as well as the db library

            I need to spend some time to update this properly, the code was just a quick run through so double check it before using it in production.
            I’ll go over it when I get more time.

  6. Pingback: Cassandra, phpcassa & CI | CodeIgniter Forums | Programmer Solution

  7. Andy Liang says:

    Hi Courtney,

    The updated version works like a charm. Thank you very much for your help.

    Andy

    • Courtney says:

      No problem, I’ll probably put some time into it soon but for now good luck

  8. atlas says:

    can you do that in video well be emazing

  9. Sunjith says:

    Any update with phpcassa 1.0.x?

    • zcourts says:

      No sorry, gave PHP+Cassandra break, only using Java/Scala+Cassandra now.
      Not sure how much PHPCassa has come along since I last looked but unless the APIs have changed a lot it shouldn’t be difficult to change the PHPCassa version

  10. Tod says:

    Superb post however I was wondering if you could write a litte more on this subject?
    I’d be very grateful if you could elaborate a little bit more. Kudos!

    Tod

    • zcourts says:

      To be honest I haven’t used PHP to connect to Cassandra in a while. Almost everything I’m doing now is Java, Scala or Node JS (JavaScript) but if its about Cassandra in general then let me know specifically what would be useful and I can put a blog post together.

  11. saravanan says:

    i have downloaded your code and run in my browser it display the following error :

    Fatal error: Uncaught exception ‘cassandra_NotFoundException’ in D:\xampp\htdocs\cass\cassandraci\application\libraries\phpcassa\columnfamily.php:204 Stack trace: #0 D:\xampp\htdocs\cass\cassandraci\application\libraries\db.php(95): ColumnFamily->__construct(Object(ConnectionPool), ‘Standard1′) #1 D:\xampp\htdocs\cass\cassandraci\application\libraries\db.php(31): Db->initCFs(Array) #2 D:\xampp\htdocs\cass\cassandraci\system\core\Loader.php(1099): Db->__construct() #3 D:\xampp\htdocs\cass\cassandraci\system\core\Loader.php(975): CI_Loader->_ci_init_class(‘Db’, ”, NULL, NULL) #4 D:\xampp\htdocs\cass\cassandraci\system\core\Loader.php(216): CI_Loader->_ci_load_class(‘db’, NULL, NULL) #5 D:\xampp\htdocs\cass\cassandraci\system\core\Loader.php(1178): CI_Loader->library(‘db’) #6 D:\xampp\htdocs\cass\cassandraci\system\core\Loader.php(152): CI_Loader->_ci_autoloader() #7 D:\xampp\htdocs\cass\cassandraci\system\core\Controller.php(51): CI_Loader->initialize() #8 D:\xampp\htdocs\cass\cassandraci\system\core\CodeIgniter.php(308): in D:\xampp\htdocs\cass\cassandraci\application\libraries\phpcassa\columnfamily.php on line 204

    please advice on me on this

    • saravanan says:

      sorry that was my mistake . now its working for me thanks nice tutorial

  12. saravanan says:

    i have one doubt , i need to use both sql and cassandra means what can i do ?

    • Brian says:

      You should be able to use both without an issue, you’re calling a completely different library/class. I will be needing to do the same thing soon though, so I’ll try and confirm this for you.

  13. Arunraj says:

    How to change the default keyspace and columnfamily to connect with dynamic columnfamily.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 1,384 other followers

%d bloggers like this: