为什么要分片?一般是数据库因业务的增长产生了巨大的压力情况下,开始是主从,然后是缓存,分区,均衡等,最后才会考虑的方案分片(一般是对主写入库进行操作),但,有经验的架构师应该从一开始就考虑到这种可能性,随着业务的增长可以线性的横向扩展数据库系统。在应用层开发时,预先考虑到以前架构要适应分片时的改造的可能性,在各方面进行优化,如sql尽量少用Join等。对于一量负载的网站,没必要很早就引入分片功能,这样反而使得业务逻辑更加复杂。
本文尝试给出一种用PHP实现的设计方案,shard_id的结构是64bit,10bit sharid系统+10bit为类型id+10子类型id+34bit自增id。关于分片设计的更多知识请参考我的其它文章。
<?php
/**
* 生产数据库分区id
*
* 描述
*
* @package api
* @author xxx
* @copyright Copyright (c) 2014, xx.im.
* @since Version 1.0
* @filesource
*
* @property database2 $database
*/
define( 'TOTAL_SHARD_NUM', 1 );
class shard
{
var $database = null;
function shard()
{
$this->database = load( 'database' );
}
function get_shard_id( $table_name, $cate_id, $subcate_id )
{
return $this->gen_shard_id( $this->get_next_id( $table_name ), $cate_id, $subcate_id );
}
/**
* 生成shared id
*
* ID的结构:
* 一共64位,10位shard_id,10位类型id,10位子类型id,34位自增id
* 10 bits shard_id,10 bits cate_id,10 bits subcate_id,34 auto increment id
* 10+10+10+34
*
* @param $next_auto_increment_id required 自增id
* @param $cate_id required 类型id
* @param $subcate_id optional 子类型id
*
* @return bigint
*/
function gen_shard_id( $next_auto_increment_id, $cate_id, $subcate_id )
{
if( empty( $next_auto_increment_id ) )
{
return 0;
}
$shard_id = $this->get_shard_num( $next_auto_increment_id, TOTAL_SHARD_NUM );
$shard_id = $shard_id << ( 64 - 10 ); //shard id
$shard_id |= $cate_id << ( 64 - 10 - 10 ); //大类型
$shard_id |= $subcate_id << ( 64 - 10 - 10 - 10 ); //子类型
$shard_id |= $next_auto_increment_id; //自增id
return $shard_id;
}
/**
* 解析 shard id 结构
*
* ID的结构:
* 一共64位,10位shard_id,10位类型id,10位子类型id,34位自增id
* 10 bits shard_id,10 bits cate_id,10 bits subcate_id,34 auto increment id
* 10+10+10+34
*
* @param $shard_id
*
* @return array('shard_num'=>0,'cate_id'=>0,'subcate_id'=>'','id'=>0)
*/
function parse_shard_id( $shard_id )
{
$ret = array( 'shard_num' => 0,
'cate_id' => 0,
'subcate_id' => 0,
'id' => 0 );
if( empty( $shard_id ) )
{
return $ret;
}
$ret[ 'shard_num' ] = $shard_id >> ( 64 - 10 );
$ret[ 'cate_id' ] = ( $shard_id >> ( 64 - 10 - 10 ) ) & 1023;
$ret[ 'subcate_id' ] = ( $shard_id >> ( 64 - 10 - 10 - 10 ) ) & 1023;
$ret[ 'id' ] = $shard_id & 17179869183;
return $ret;
}
/**
* get shard location
*
* @param $next_auto_increment_id
* @param $total_shard_num
*
* @return int
*/
function get_shard_num( $next_auto_increment_id, $total_shard_num )
{
return $total_shard_num>0?$next_auto_increment_id % $total_shard_num:0;
}
/**
* 查询表的下一个自增id
*
* @param $table_name
*
* @return int
*/
function get_next_id( $table_name )
{
if( empty( $table_name ) )
{
return 0;
}
//
// need grant access information_schema privilege
//
$sql = "SELECT auto_increment FROM information_schema.tables WHERE table_name = '$table_name' AND table_schema = DATABASE()";
/** @var CI_DB_Result $query */
$data = $this->database->unique( $sql );
if( !empty( $data ) )
{
return isset( $data[ 'auto_increment' ] ) ? $data[ 'auto_increment' ] : 0;
}
else
{
return 0;
}
}
}
<作者 朱淦 350050183@qq.com 2015.8.30>