在做一個爬蟲,其中有一部分是評論資料。因為評論數太多,所以想要將爬取下來的評論進行分表。
目前的思路是:
每個表儲存100萬條資料(1-1000000儲存在table1,1000001-2000000儲存在table2)。
在redis建立一個String鍵comment:totalNum,儲存資料庫中已有的評論數。
根據 comment:totalNum 來確定評論的主鍵id以及儲存到哪個表中。
目前思路是:
$id = $redis->get( 'comment:totalNum' );$tableName = getTableName( $id );$sql = "insert xxx";$res = $db->mysql_query( 'sql' );if( $res ){ $redis->incr( 'comment:totalNum' );}
因為考慮用多線程,所以當一個錶快要到100萬條資料時,就會有一個問題:
如果一個進程擷取了comment:totalNum為1000000,判斷可以放在表一中,然後去執行對資料庫的操作,但是如果此時也有一個進程擷取了comment:totalNum的值,那麼也會進行對資料庫的操作,結果就會是資料庫中增加了兩條記錄,一條主鍵為1,000,000,一條主鍵為1,000,001,不符合初衷。
所以我想問一下,有沒有比較好的方法,能實現:
原子操作 start $id = $redis->get( 'comment:totalNum' ); $tableName = getTableName( $id ); $sql = "insert xxx"; $res = $db->mysql_query( 'sql' ); if( $res ){ $redis->incr( 'comment:totalNum' ); }原子操作 end
回複內容:
在做一個爬蟲,其中有一部分是評論資料。因為評論數太多,所以想要將爬取下來的評論進行分表。
目前的思路是:
每個表儲存100萬條資料(1-1000000儲存在table1,1000001-2000000儲存在table2)。
在redis建立一個String鍵comment:totalNum,儲存資料庫中已有的評論數。
根據 comment:totalNum 來確定評論的主鍵id以及儲存到哪個表中。
目前思路是:
$id = $redis->get( 'comment:totalNum' );$tableName = getTableName( $id );$sql = "insert xxx";$res = $db->mysql_query( 'sql' );if( $res ){ $redis->incr( 'comment:totalNum' );}
因為考慮用多線程,所以當一個錶快要到100萬條資料時,就會有一個問題:
如果一個進程擷取了comment:totalNum為1000000,判斷可以放在表一中,然後去執行對資料庫的操作,但是如果此時也有一個進程擷取了comment:totalNum的值,那麼也會進行對資料庫的操作,結果就會是資料庫中增加了兩條記錄,一條主鍵為1,000,000,一條主鍵為1,000,001,不符合初衷。
所以我想問一下,有沒有比較好的方法,能實現:
原子操作 start $id = $redis->get( 'comment:totalNum' ); $tableName = getTableName( $id ); $sql = "insert xxx"; $res = $db->mysql_query( 'sql' ); if( $res ){ $redis->incr( 'comment:totalNum' ); }原子操作 end
1.mysql 基本上是單表1000w 資料,100w 量很小,不要急著分表
2.分表要根據需求來處理.
現在你需要儲存聊天記錄,可以根據時間維度進行分表,先做個統計,一天的資料量能達到多少,計算下大概多久可以達到1000w 的資料量,假設一個月資料量到達1000w, 那麼就一個月一張表.
說下你現在方案問題,依賴性較強, redis 掛了或者資料丟失,你就需要手動處理.
如果按你現在的方案來做,要解決的是這個衝突問題,可以使用 redis的 watch 和 事務功能.
Talk is cheap. Show me the code
$num = $redis->get("num");$redis->watch("num");//開啟 mysql 事務begin()//根據 num 插入資料到指定表中insert xxxxxx//開啟 redis 事務,進行遞增$redis->multi();$redis->incr("num");$incr = $redis->exec();//如果在這期間,其他進程更改了 num 的值,會返回 false, 沒有就返回遞增後的值if(! $incr ){ //復原}else{ //提交 mysql 事務}
根據評論的id號 模數 表的數量 然後在每個表平均的插入資料 你覺得是不是好點? 原子操作都可以不要了