數據庫分片id的設計(PHP實例)

爲何要分片?通常是數據庫因業務的增加產生了巨大的壓力狀況下,開始是主從,而後是緩存,分區,均衡等,最後纔會考慮的方案分片(通常是對主寫入庫進行操做),但,有經驗的架構師應該從一開始就考慮到這種可能性,隨着業務的增加能夠線性的橫向擴展數據庫系統。在應用層開發時,預先考慮到之前架構要適應分片時的改造的可能性,在各方面進行優化,如sql儘可能少用Join等。對於一量負載的網站,不必很早就引入分片功能,這樣反而使得業務邏輯更加複雜。php

本文嘗試給出一種用PHP實現的設計方案,shard_id的結構是64bit,10bit sharid系統+10bit爲類型id+10子類型id+34bit自增id。關於分片設計的更多知識請參考個人其它文章。sql


<?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>數據庫

相關文章
相關標籤/搜索