1. 程式人生 > >springboot之專案叢集生成hash的key導致快取不一致。

springboot之專案叢集生成hash的key導致快取不一致。

場景:

叢集專案使用訪問策略使用的隨機,快取使用的redis,自定義key當傳入兩個引數以上時候,使用Arrays.deepHashCode來計算快取的key。

問題:

然後出現在機器1剛訪問過這個介面,redis也有快取,訪問到機器2的時候仍然走service方法,也就是沒有從redis取快取。

(從日誌看是否走的快取,在自定義key生成裡面打上日誌,和介面呼叫的service打上日誌,如果走了自定義key方法兩遍就是在生成快取,如果走一遍自定義key這個方法就是取的快取)

然後找日誌,同一個介面,在訪問到不同機器的時候,生成的快取key不一樣,所以導致每個機器都需要快取一遍。

原因:生成hash key的方法為Arrays.deepHashCode看方法

public static int deepHashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a) {
            int elementHash = 0;
            if (element instanceof Object[])
                elementHash = deepHashCode((Object[]) element);
            else if (element instanceof byte[])
                elementHash = hashCode((byte[]) element);
            else if (element instanceof short[])
                elementHash = hashCode((short[]) element);
            else if (element instanceof int[])
                elementHash = hashCode((int[]) element);
            else if (element instanceof long[])
                elementHash = hashCode((long[]) element);
            else if (element instanceof char[])
                elementHash = hashCode((char[]) element);
            else if (element instanceof float[])
                elementHash = hashCode((float[]) element);
            else if (element instanceof double[])
                elementHash = hashCode((double[]) element);
            else if (element instanceof boolean[])
                elementHash = hashCode((boolean[]) element);
            else if (element != null)
                elementHash = element.hashCode();

            result = 31 * result + elementHash;
        }

        return result;
    }

檢視

elementHash = element.hashCode();

 public native int hashCode();

這是c寫的,看看上面註釋。

 address of the object into an integer, but this implementation

說會根據資料儲存的地址生成,所以資料在不同機器上存的位置不一樣,導致hash生成的key不一致。

結論:

叢集情況下生成hash值想要保持一致,需要避免使用public native int hashCode(); 這個受儲存地址影響的hashcode方法。

比如String重新了hashcode,沒有呼叫原生的hashcode,沒有任何受地址影響的地方。

 public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

可以在叢集情況下。每個機器上,相同引數的情況下,保持生成的hash key一致。

這樣就可以保證,在一個機器上生成快取,下次請求到另外一個機器,仍然可以使用這個快取。