一致性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的分布,还引入了虚拟节点的概念,一个实际的节点,可以化生为多个不同的虚拟节点,这样能够让区间映射更加平衡。 下面是我测试的代码 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 |
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; } } } |
原文:http://www.cnblogs.com/cquccy/p/3556118.html