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一致。

这样就可以保证,在一个机器上生成缓存,下次请求到另外一个机器,仍然可以使用这个缓存。

猜你喜欢

转载自blog.csdn.net/Mint6/article/details/83859194