這次一起來看看基于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