天天看點

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

繼續閱讀