成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

數(shù)據(jù)庫分表后,并發(fā)環(huán)境下,生成全局id生成的幾種方式

testbird / 452人閱讀

摘要:對支持很好,分表后無需考慮全局的問題。但是這個項目使用的是進(jìn)行開發(fā),必須自己生成全局。語句的是為了保證并發(fā)環(huán)境下的值只增不減。每次生成全局前,先檢測指定的是否存在。代碼如下另外對于全局的生成,和也都公布了自己的方案。

最近一個項目由于數(shù)據(jù)量變大,需要進(jìn)行數(shù)據(jù)分表。數(shù)據(jù)存儲在淘寶的tddl上。分表后,原先的自增id就不能使用了。tddl對java支持很好,分表后無需考慮全局id的問題。但是這個項目使用的是php進(jìn)行開發(fā),必須自己生成全局id。以下列出幾種分表方案,僅當(dāng)拋磚引玉。

1:使用CAS(compare and swap)

其實(shí)這里并不是嚴(yán)格的CAS,而是使用了比較交換原子操作的思想。
生成思路如下:每次生成全局id時,先從sequence表中獲取當(dāng)前的全局最大id。然后在獲取的全局id上做加1操作。把加1后的值更新到數(shù)據(jù)庫。更新時是關(guān)鍵。
如加1后的值為203,表名是users,數(shù)據(jù)表結(jié)構(gòu)如下:

CREATE TABLE `SEQUENCE` (
    `name` varchar(30) NOT NULL COMMENT "分表的表名",
    `gid` bigint(20) NOT NULL COMMENT "最大全局id",
    PRIMARY KEY (`name`)
) E

那么更新語句是。
update sequence set gid = 203 where name = "users" and gid < 203;
sql語句的 and gid < 203 是為了保證并發(fā)環(huán)境下gid的值只增不減。
如果update語句的影響記錄條數(shù)為0說明,已經(jīng)有其他進(jìn)程提前生成了203這個值,并寫入了數(shù)據(jù)庫。需要重復(fù)以上步驟從新生成。
代碼實(shí)現(xiàn)如下:

//$name 表名
function next_id_db($name){
    //獲取數(shù)據(jù)庫全局sequence對象
    $seq_dao = Wk_Sequence_Dao_Sequence::getInstance();
    $threshold = 100; //最大嘗試次數(shù)
    for($i = 0; $i < $threshold; $i++){
        $last_id = $seq_dao->get_seq_id($name);//從數(shù)據(jù)庫獲取全局id
        $id = $last_id +1;
        $ret = $seq_dao->set_seq_id($name, $id);
        if($ret){
            return $id;
            break;
        }
    }
    return false;
}
2:使用全局鎖

在進(jìn)行并發(fā)編程時,一般都會使用鎖機(jī)制。其實(shí),全局id的生成也是解決并發(fā)問題。
生成思路如下:
在使用redis的setnx方法和memcace的add方法時,如果指定的key已經(jīng)存在,則返回false。利用這個特性,實(shí)現(xiàn)全局鎖。
每次生成全局id前,先檢測指定的key是否存在。
如果不存在則使用redis的incr方法或者memcache的increment進(jìn)行加1操作。這兩個方法的返回值是加1后的值。
如果存在,則程序進(jìn)入循環(huán)等待狀態(tài)。循環(huán)過程中不斷檢測key是否還存在,如果key不存在就執(zhí)行上面的操作。
代碼如下:

//使用redis實(shí)現(xiàn)
//$name 為 邏輯表名
function next_id_redis($name){
    $redis = Wk_Redis_Util::getRedis();//獲取redis對象
    $seq_dao = Wk_Sequence_Dao_Sequence::getInstance();//獲取存儲全局id數(shù)據(jù)表對象
    if(!is_object($redis)){
        throw new Exception("fail to create redis object");
    }
    $max_times = 10; //最大執(zhí)行次數(shù) 避免redis不可用的時候 進(jìn)入死循環(huán)
    while(1){
        $i++;
        //檢測key是否存在,相當(dāng)于檢測鎖是否存在
        $ret = $redis->setnx("sequence_{$name}_flag",time());
        if($ret){
            break;
        }
        if($i > $max_times){
            break;
        }
        $time = $redis->get("sequence_{$name}_flag");
        if(is_numeric($time) && time() - $time > 1){//如果循環(huán)等待時間大于1秒,則不再等待。
            break;
        }
    }
    $id = $redis->incr("sequence_{$name}");
    //如果操作失敗,則從sequence表中獲取全局id并加載到redis
    if (intval($id) === 1 or $id === false) {
        $last_id = $seq_dao->get_seq_id($name);//從數(shù)據(jù)庫獲取全局id
        if(!is_numeric($last_id)){
            throw new Exception("fail to get id from db");
        }
        $ret = $redis->set("sequence_{$name}",$last_id);
        if($ret == false){
            throw new Exception("fail to set redis key [ sequence_{$name} ]");
        }
        $id = $redis->incr("sequence_{$name}");
        if(!is_numeric($id)){
            throw new Exception("fail to incr redis key [ sequence_{$name} ]");
        }
    }
    $seq_dao->set_seq_id($name, $id);//把生成的全局id寫入數(shù)據(jù)表sequence
    $redis->delete("sequence_{$name}_flag");//刪除key,相當(dāng)于釋放鎖
    $db = null;
    return $id;
}
3:redis和db結(jié)合

使用redis直接操作內(nèi)存,可能性能會好些。但是如果redis死掉后,如何處理呢?把以上兩種方案結(jié)合,提供更好的穩(wěn)定性。
代碼如下:

function next_id($name){
    try{
        return $this->next_id_redis($name);
    }
    catch(Exception $e){
        return $this->next_id_db($name);
    }
}

另外對于全局id的生成,F(xiàn)licker和Twitter也都公布了自己的方案。感興趣的人,可以了解下。

http://my.oschina.net/u/142836/blog/174465

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/21267.html

相關(guān)文章

  • 金幣(積分)商城架構(gòu)漫談

    摘要:開篇金幣積分商城下稱商城是眾多內(nèi)的一個產(chǎn)品,隨著使用的用戶越來越多,商城對于用戶留存的提升,扮演著重要的角色做為提高用戶黏性的核心產(chǎn)品,在擁有很好用戶體驗(yàn)的同時,也必須存在著一個高效穩(wěn)定的系統(tǒng)。分析上述兩點(diǎn),得到結(jié)論按用戶進(jìn)行分庫分表。 開篇 金幣(積分)商城(下稱商城)是眾多App內(nèi)的一個產(chǎn)品,隨著App使用的用戶越來越多,商城對于用戶留存的提升,扮演著重要的角色;做為提高用戶黏性的...

    Ethan815 評論0 收藏0
  • 談?wù)劮?wù)端緩存幾種用法

    摘要:緩存是一個常談常新的話題,作為一名服務(wù)端的技術(shù),如果你入行一年都還沒用過類產(chǎn)品,那只能說你的公司實(shí)在太小了,或者你干的活實(shí)在太邊緣了。這是緩存最原始的意義,同時也引申出了緩存最普遍的用法。但是現(xiàn)實(shí)中還有一種緩存,是主動更新的。 緩存是一個常談常新的話題,作為一名服務(wù)端的技術(shù),如果你入行一年都還沒用過memcached類產(chǎn)品,那只能說你的公司實(shí)在太小了,或者你干的活實(shí)在太邊緣了。 說起...

    tianhang 評論0 收藏0
  • 談?wù)劮?wù)端緩存幾種用法

    摘要:緩存是一個常談常新的話題,作為一名服務(wù)端的技術(shù),如果你入行一年都還沒用過類產(chǎn)品,那只能說你的公司實(shí)在太小了,或者你干的活實(shí)在太邊緣了。這是緩存最原始的意義,同時也引申出了緩存最普遍的用法。但是現(xiàn)實(shí)中還有一種緩存,是主動更新的。 緩存是一個常談常新的話題,作為一名服務(wù)端的技術(shù),如果你入行一年都還沒用過memcached類產(chǎn)品,那只能說你的公司實(shí)在太小了,或者你干的活實(shí)在太邊緣了。 說起...

    CocoaChina 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<