天天看点

Cassandra客户端连接的说明---PHP版

这次一起来看看基于PHP的一些连接Cassandra的实现(higher level libaries)

目前已知的有:

1) phpcassa

https://github.com/thobbs/phpcassa

https://github.com/hoan/phpcassa

API:http://thobbs.github.com/phpcassa/

2) Pandra

https://github.com/mjpearson/Pandra

接下来我们需要通过一个例子来说明他们的用法:

参考文档:http://crlog.info/2011/04/07/apache-cassandra-phpcassa-code-igniter-large-scale-php-app-in-5-minutes/

测试代码:https://github.com/zcourts/cassandraci

以下将按照上述参考演示在CodeIgniter2下使用phpcassa 0.8.a.2的示例。

1. 通过CLI在cassandra中创建Keyspace以及Column Family,这里略过。

2. 在application/config下新建文件cassandra.php,内容如下:(注意,请按照实际情况修改参数)

<?php

$servers[0] = array('host' => '192.168.11.124', 'port' => 9160);
$servers[1] = array('host' => '192.168.11.185', 'port' => 9160);
$config['cassandra_servers'] = $servers;
$config['keyspace'] = "LiftDNA_DB"; //keyspace name
$config['default_cf'] = "LiftDNA_Table"; //default column family
//set of column families your application uses and you want to have initialied and cached
$config['init_cf'] = array("LiftDNA_Table");
$config['pool_size'] = 5;
$config['max_retries'] = 5;
$config['send_timeout'] = 5000;
$config['recv_timeout'] = 5000;
$config['recycle'] = 10000;
//if needed then array("username"=>user1,"password"=>pass); replaces NULL
$config['credentials'] = 0;
$config['framed_transport'] = true;
           

3. 下载phpcassa 0.8.a.2,解压后把文件夹改名phpcassa,拷贝至application/libraries下。

4. 在application/libraries下新建文件db.php,内容如下:(实际操作中发现,上述测试代码中该文件需要部分修改才能兼容0.8.a.2版本,故请以下列代码为准)

<?php

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

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

    private  $cf, $CI;
    /**
     *
     * @var ConnectionPool
     */
    private $conn;
    /**
     * @var ColumnFamily
     */
    private $cfObj;
    private $cfList = array();

    /**
     * Init connection for the database using the settings in the cassandra.php
     * config file...
     */
    public function __construct() {
        $this->CI = & get_instance();
        $this->creatPool($this->CI->config->item('keyspace'), $this->CI->config->item('cassandra_servers'));
        $this->cf = $this->CI->config->item('default_cf');
        $this->initCFs($this->CI->config->item('init_cf'));
    }

    /**
     * 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->cfObj = 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->cfObj;
    }

    /**
     * Allows you to query any CF that was initalised either by setting a list of
     * CF names in the cassandra.php config file or by calling initCFs(array)
     * @param string $cfName The name of the column family to perform the query on
     * this parameter is option. If it is not specified then the last cf used is
     * returned, if its the first call then the default cf is returned
     * - case insensitive
     * @return ColumnFamily
     */
    public function query($cfName=NULL) {
        if ($cfName === NULL) {
            return $this->cfList[strtolower($this->cf)];
        } else {
            //set cf as the last cf so that subsequent queries don't need 
            //to specify the cf name
            $this->cf = $cfName;
            return $this->cfList[strtolower($cfName)];
        }
    }

    /**
     * Initialises a set of column families which are stored in an associative
     * array, keyed by the CF name to avoid using setCF which creates a new
     * instance of your CF each time.
     * @param array $cfl An array containing a list of CFs to initalise and
     * "cache" for queries later...
     * @param $reinit defaults to false, if true then the given cf are re instanciated
     * even if an instance already existed, if false then its not and the
     * arg is ignored
     */
    public function initCFs($cfl, $reinit=false) {
        foreach ($cfl as $icf) {
            $createCFInstance = false;
            if (!isset($this->cfList[strtolower($icf)])) {
                $createCFInstance = true;
            }
            if ($reinit) {
                $createCFInstance = true;
            }
            if ($createCFInstance) {
                //init the CFs to be accessible by name
                $this->cfList[strtolower($icf)] = new ColumnFamily($this->conn, $icf);
            }
        }
    }

    /**
     * A straight rip of phpcassa's old Connection constructor. Connection class
     * is now depreciated so it issues a warning when used, only thing it did
     * was what's contained in this method, which is create an instance of the 
     * ConnectionPool. Without having to modify anything else copying the
     * contructor was the fastest/easiest way to do this...
     * @param type $keyspace
     * @param type $servers
     * @param type $max_retries
     * @param type $send_timeout
     * @param type $recv_timeout
     * @param type $recycle
     * @param type $credentials
     * @param type $framed_transport 
     */
    private function creatPool($keyspace, $servers=NULL) {
        try {
            if ($servers != NULL) {
                $new_servers = array();
                foreach ($servers as $server) {
                    $new_servers[] = $server['host'] . ':' . (string) $server['port'];
                }
            } else {
                $new_servers = NULL;
            }

            $this->conn = new ConnectionPool
           (
		$keyspace, 
            	$new_servers,
            	$this->CI->config->item('pool_size'),
             	$this->CI->config->item('max_retries'),
               	$this->CI->config->item('send_timeout'),
           	$this->CI->config->item('recv_timeout'),
              	$this->CI->config->item('recycle'),
              	$this->CI->config->item('credentials'),
             	$this->CI->config->item('framed_transport')
            );
        } catch (Exception $e) {
            show_error($e->getMessage());
        }
    }
}
           

5. 修改autoload.php文件如下:

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

$autoload['config'] = array('cassandra');

6. 在application/controllers下新建home.php文件,内容如下:

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

class Home extends CI_Controller {

    function index() {
    	
        //query using default cf set in cassandra.php
        $this->db->query()->insert('key', array('column1' => 'value1', 'column2' => 'value2'));
        
        //query using users cf init from setting in cassandra.php
        $this->db->query("LiftDNA_Table")->insert('key', array('column1' => 'value1', 'column2' => 'value2'));
        
        //no param but still query using users until another call to query
        //specifies a different cf the users cf will be used
        $this->db->query()->insert('key1', array('column3' => 'value1', 'column4' => 'value4'));
        $r1 = $this->db->query()->get('key');
        $r2 = $this->db->query()->get('key1');
        //query using the default cf set in cassandra.php
        $r3 = $this->db->query($this->config->item('default_cf'))->get('key');
        
        $val = array('query1' => $r1, 'query2' => $r2, 'query3' => $r3);
        $this->load->view('home', $val);
    }

}
           

7. 在application/views下新建home.php文件,内容如下:

<?php
print_r($query1);
print_r($query2);
print_r($query3);
?>
<p><br />Page rendered in {elapsed_time} seconds</p>
           

至此,访问该页面即可看到效果。

请注意,如果对性能有要求,请使用PHPCassan的C语言编译扩展,主页上有使用说明。

另外:Cassandra的Cluster Admin工具其实是基于PHPCassa的,可以参考一下他的源码来学习更多用法。

https://github.com/sebgiroux/Cassandra-Cluster-Admin

继续阅读