欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Consistent HASH(自己读后理解)

程序员文章站 2024-03-19 21:40:40
...

一致性HASH, 作用在于当有服务器实效的情况下,保持CACHE的一致性.避免引起大量读CACHE失效.

假设服务部分的架构如下: appServer(10台)--- servicesServer(3台)---Database(2台 master,slave)

servicesServer有相关用户数据的CACHE, 通过id模servicesServerNum映射到相应的servicesServer上。 假设 有用户 1 到 3 访问某个页面,即用户(u1,u2,u3)访问 appServer. appServer通过接口调用访问servicesServer,用户0的CACHE在servicesServer0上,以此类推.

可是天有不测风云, servicesServer0因为磁盘问题挂掉了,现在会出现什么情况呢?

由于我们通过 id模servicesServerNum映射得到相应的servicesServer,但是现在只有2台机器了, 于是 :

before servicesServer0 down: (0--s0, 1--s1, 2--s2)

u1 1mod3--> s1

u2 2mod3--> s2

u3 3mod3--> s0

after servicesServer0 down(0--s1, 1--s2)

u1 1mod2--> s2  change

u2 2mod2--> s1 change

u3 3mod2--> s2  change

在这种情况下,原来的CACHE全部失效, 所有的读请求全部瞬间压倒Database上面。

一致性CACHE就是为了解决这个问题提出来的。它不是直接的取模映射,而是将一个区间影射到特定服务器上,这样即使机器减少或者增加,大部分的CACHE仍然能够有效,避免了瞬间的冲击。 为了更好的平衡CACHE的分布,还引入了虚拟节点的概念,一个实际的节点,可以化生为多个不同的虚拟节点,这样能够让区间映射更加平衡。 下面是我测试的代码 :

    class Program
    {
        BNode[] _BNodes;
        int _ArrayLength;

        static void Main(string[] args)
        {
            Program ptest = new Program();
            ptest.InitArray(5, 4);
            ptest.ShowNodes(5,4);

            ptest.SortArray();

            int restring = ptest.BserachServer(3);

            restring = ptest.BserachServer(152);

            restring = ptest.BserachServer(155);

            restring = ptest.BserachServer(0);     
            
        }

        void InitArray(int RealNodeNum, int VirtualCopyNum)
        {
            int totalNum = RealNodeNum * VirtualCopyNum ;
            _BNodes =  new BNode[totalNum];
            _ArrayLength = totalNum;

            for (int i = 0; i < RealNodeNum; i++)
            {
                for(int j = 0; j < VirtualCopyNum ; j++)
                {
                    BNode tempNode = new BNode();
                    tempNode.IPAddr = "172.16.73." + (i+1);
                    tempNode.hashcode = ( "V" + j + tempNode.IPAddr ).GetHashCode();
                    //Console.Out.WriteLine(tempNode.hashcode);
                    tempNode.flag = 1;
                    //Console.Out.WriteLine(tempNode.hashcode);
                    _BNodes[i] = tempNode;
                }
            }
        }

        void ShowNodes(int RealNodeNum, int VirtualCopyNum)
        {
            int totalNum = RealNodeNum * VirtualCopyNum;
            for (int i = 0; i < totalNum; i++)
            {
                Console.Out.Write(_BNodes[i].hashcode + " ");
                Console.Out.Write(_BNodes[i].flag + " ");
                Console.Out.WriteLine(_BNodes[i].IPAddr);
            }
        }

        bool DelOneNode(int machineID, int VirtualCopyNum)
        { 
            int i = machineID;
            for (int j = 0; j < VirtualCopyNum; j++)
            {
                string IPAddr = "172.16.73." + (i + 1);
                int hashcode = ("V" + j + IPAddr).GetHashCode();
                BNode delNode = BserachNode(hashcode);
                if (delNode != null)
                {
                    delNode.flag = 0;
                }
            }
            return true;
        }

        int FindNode(int objectHashCode)
        {
            int pos = BserachServer(objectHashCode);
            int tempos = pos;
            int cycleFlag =0;
            while ( !( tempos == pos && cycleFlag == 1) )
            {
                if (_BNodes[pos].flag > 0)
                {
                    return pos;
                }
                else
                {
                    if (pos == 0)
                    {
                        pos = _ArrayLength-1;
                        cycleFlag = 1;
                    }
                    pos = pos - 1;
                    
                }
            }
            return 0;
        }

        void SortArray()
        {
            ShowNodes(5, 4);
            IComparer myComparer = new myCompareClass();
            Array.Sort(_BNodes, myComparer);
            ShowNodes(5, 4);
        }

        int BserachServer(int cmphashcode)
        {
            if (_BNodes[_ArrayLength - 1].hashcode <= cmphashcode || _BNodes[0].hashcode > cmphashcode)
            {
                return _ArrayLength - 1;
            }

            {
                int lowPos = 0;
                int highPos = _ArrayLength; 
                int middlePos = (lowPos + highPos) / 2;

                while (true)
                {
                    middlePos = (lowPos + highPos) / 2;
                    if (middlePos < lowPos )
                    {
                        return middlePos;
                    }

                    if (lowPos > highPos)
                    {
                        return middlePos; 
                    }
                    

                    if (cmphashcode < _BNodes[middlePos].hashcode)
                    {
                        highPos = middlePos - 1;
                    }
                    else if (cmphashcode > _BNodes[middlePos].hashcode)
                    {
                        lowPos = middlePos + 1;
                    }
                    else
                    {
                        return middlePos;
                    }
                }
            }
        }

        BNode BserachNode(int cmphashcode)
        {
            int lowPos = 0;
            int highPos = _ArrayLength;
            int middlePos = (lowPos + highPos) / 2;

            while (middlePos < lowPos || lowPos > highPos)
            {
                middlePos = (lowPos + highPos) / 2;

                if (cmphashcode < _BNodes[middlePos].hashcode)
                {
                    highPos = middlePos - 1;
                }
                else if (cmphashcode > _BNodes[middlePos].hashcode)
                {
                    lowPos = middlePos + 1;
                }
                else
                {
                    return _BNodes[middlePos];
                } 
            }
            return null;
        }

        internal class BNode
        {
            public int     hashcode;
            public string  IPAddr;
            public int     flag;
        }

        internal class myCompareClass : IComparer
        {
             int IComparer.Compare(object x, object y)
            {
                if (((BNode)x).hashcode == ((BNode)y).hashcode)
                {
                    return 0;
                }
                else if (((BNode)x).hashcode > ((BNode)y).hashcode)
                {
                    return 1;
                }
                else
                    return -1;

            }
        }

    }