【性能优化】9.6 [集群] 备胎式容错
9.6 备胎式容错
事先把数据加载进内存,能够获得比外存好得多的性能。数据量太大超出单机内存时,也可以利用集群的分机分段加载,同时分担计算量。我们前述的多机并行框架以及集群表也能支持内存运算。
不过,集群环境下,同样会面临容错和容错度的问题。而且,对于内存中的数据,却不能使用上节讲的冗余式容错方案。
冗余式容错方案中,我们把数据多冗余了 k 倍,即用了 k+1 份数据,才获得了 k 容错度。也就是说,为了得到 k 容错度,存储的利用率仅有 1/k。这对于外存来讲是可以接受的,因为硬盘足够便宜且几乎可以无限扩容。但是,内存要昂贵得多而且扩容有上限,仅有 1/k 的利用率是无法容忍的。
内存可以使用备胎式容错。数据仍然分成 n 个分区,分别加载到 n 个分机,然后再准备 k 个空闲的分机作为备用机。当正在运行的某个分机发生失效时,则立即启用某个备用机,临时加载失效分机的数据,和其它分机重新组成拥有完整数据的集群继续提供服务。失效的分机排除故障后恢复使用,可以再充当备用机。整个过程和汽车更换备胎的模式很像。
如果同时失效的分机超过 k 个,那会把 k 个备用机都用完也不能再组合出拥有完整数据的集群,这时候只能宣告集群失效了。
这种方案的内存利用率可以高达 n/(n+k),远远高于冗余式容错的 1/k。能加载进内存的数据量通常不会非常大,分机失效后临时加载的时间并不多,集群服务就可以较快地恢复。而对于外存,如果也采用这种备胎式容错,分机失效后需要临时准备的数据量可能会非常大,就会导致集群长时间不能提供服务。
使用内存装载数据的分机需要有个加载动作:
A |
B |
|
1 |
if z>0 |
>hosts(z) |
2 |
=file("orders.ctx":z).open().memory() |
|
3 |
>env(ORDERS,B2) |
参数 z 表示分区号,要用 hosts 函数向集算服务器登记本分机的内存数据的分区号,然后加载数据并命名为分机的全程变量。
运算代码就可以利用加载好的内存数据了:
A |
|
1 |
["192.168.0.101:8281","192.168.0.102:8281",…, "192.168.0.105:8281"] |
2 |
=hosts(4,A1) |
3 |
=memory(A2,ORDERS) |
4 |
=A3.cursor().groups(area;sum(amount)) |
注意 A1 这里有 5 个分机,hosts 函数要从这些分机中找出 4 个可用的(对应 4 个分区),如果找不到 4 个未失效分机,则会返回失败。找到后再看这些分机中已经加载的数据分区号是否完整,发现有缺失的分区号则以该分区号为参数执行分机上的加载代码,凑成拥有完整数据的集群,再产生集群内存表进行计算。