【踩坑記錄】Sharding-JDBC(3.0.0)之分佈式主鍵衝突

目錄

背景

問題排查

解決

生成workId

配置workId


背景

因爲業務數量較大,單表影響查詢性能,採用了單庫分表解決。引入了sharding-jdbc插件進行分表下的數據庫操作。生產環境都是分佈式部署服務的,有兩臺機器。最近有併發量高的業務場景,偶爾會出現生成主鍵重複的問題 Duplicate entry '******************' for key 'PRIMARY'。

問題排查

主鍵是sharding-jdbc生成的,使用默認的雪花算法,是可以保證分佈式主鍵唯一的。所以就很奇怪爲什麼主鍵會重複,又仔細的查看了官方文檔,發現了問題。由於是分佈式部署,沒有指定不同進程的workId(默認是0),導致兩臺機器的workId相同,致使10bit工作進程位相同,所以兩個寫入請求同時打到兩臺機器上時,就可能會出現主鍵衝突。

下面簡單解釋一下:

符號位固定是0

時間戳位:生產服務器的時間是同步過的,所以同一時間寫入數據,時間戳位是相同的

工作進程位:默認是0,分佈式部署的話,不同進程要自己標記workId來實現區分,由於之前沒有區分,導致工位進程位也相同

序列號位:序列號位是在同一進程中,保證id順序的。有可能兩個進程的請求的序列號是相同的,這時就會出現兩臺機器生成的id完全相同。

解決

定位了原因,之後就是給兩臺機器指定不同的workId就好。考慮到配置的通用性,使用hostname做區分。

生成workId

public class SnowflakeIdWorker {
    
    public static Long getWorkId() {
        String hostAddress = System.getenv("HOSTNAME");
        log.info("============= hostAddress: {} =============", hostAddress);
        int[] ints = org.apache.commons.lang3.StringUtils.toCodePoints(hostAddress);
        int sums = 0;
        int[] var3 = ints;
        int var4 = ints.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            int b = var3[var5];
            sums += b;
        }

        long workId = (long)(sums % 32);
        log.info("============== workId:{} =============", workId);
        return workId;
    }
}

配置workId

import com.yst.b2b.wallet.utils.SnowflakeIdWorker;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

/**
 * sharding-jdbc 使用雪花算法生成主鍵時,workId配置
 *
 * @yx8102 2020/4/24
 */
@Configuration
@Slf4j
public class WorkIdConfig {

    static {

        long workId = 0;
        try {
            workId = SnowflakeIdWorker.getWorkId();
        } catch (Exception e) {
            log.error("生成workId發生異常.", e);
        }

        DefaultKeyGenerator.setWorkerId(workId);
    }
}

 

後續:其他生成workId的方法

【死磕Sharding-jdbc】---分佈式ID

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章