ZAB协议在Zookeeper中的实现

说明

ZAB 协议是为分布式协调服务ZooKeeper专门设计的一种支持崩溃恢复的一致性协议。基于该协议,ZooKeeper 实现了一种主从模式的系统架构来保持集群中各个副本之间的数据一致性。

本文从“通信协议”、“核心数据结构以及API”两方面主要描述Zookeeper中ZAB协议的具体实现,重点关注ZAB协议实现中抽象的对象以及对象之间的关联。弱化请求处理流程,因为这些会在我们描述ZAB协议中重点描述。

Continue reading ZAB协议在Zookeeper中的实现

Centos下调整系统时钟

新装的CentOS系统服务器可能设置了错误的,需要调整时区并调整时间。如下是CentOS系统使用NTP来从一个时间服务器同步。CentOS系统时间同步的步骤如下:

1. yum install -y ntpdate
2. cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
3. ntpdate us.pool.ntp.org
4. crontab -e
0-59/10 * * * * /usr/sbin/ntpdate us.pool.ntp.org | logger -t NTP

说明:

  1. 第一句是把当前时区调整为上海就是+8区,想改其他时区也可以去看看/usr/share/zoneinfo目录;
  2. 然后第二句是利用ntpdate同步标准时间;
  3. 最后是加入定时计划任务,每隔10分钟同步一下时钟

Erlang的递归

通过一个求和(0~N)程序来对比Erlang的递归和尾递归效率并加深对尾递归的理解。

递归

#! /usr/bin/env escript

main([A]) ->
    N = list_to_integer(A),
    io:format("sum 0 - ~w = ~w~n",[N, sum(N)]).


sum(1) -> 1;

sum(N) -> N + sum(N-1).

尾递归

#! /usr/bin/env escript

main([A]) ->
    N = list_to_integer(A),
    io:format("sum 0 - ~w = ~w~n",[N, sum(N)]).


sum(N) -> sum(N, 0).

sum(0, N) -> N;
sum(M, N) -> sum(M-1, N+M).

对比

执行 0 ~ 1000000求和表现 (时间 & 内存消耗):

dingkaideMacBook-Pro:erlang dingkai$ time ./sum 1000000
sum 0 - 1000000 = 500000500000

real    0m4.261s
user    0m3.156s
sys 0m0.775s
内存消耗约为600MB

dingkaideMacBook-Pro:erlang dingkai$ time ./sum_tail 1000000
sum 0 - 1000000 = 500000500000

real    0m2.677s
user    0m2.493s
sys 0m0.177s
内存消耗约为16MB

总结

尾递归函数就是在递归调用前不累计任何未决运算的函数。如果函数子句中函数体的最后一个表达式是对自身的调用或者是个常数,那么它就是尾递归子句。如果一个函数的所有子句都是尾递归子句,那么它就是一个尾递归函数。

Erlang入门: 几个简单小程序

生成斐波那契数列

#! /usr/bin/env escript

main([A]) ->
    I=list_to_integer(A),
    F=fac_list(I),
    io:format("feribo ~w = ~w~n",[I,F]).

element(1) -> 1;
element(2) -> 1;
element(N) -> element(N-1) + element(N-2).

fac_list(N) -> fac_list([], N).

fac_list(L, 0) -> L;
fac_list(L, N) -> fac_list([element(N)|L], N-1).

运行结果

dingkaideMacBook-Pro:erlang dingkai$ ./feibo 25
feribo 25 = [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025]

求平均数

#! /usr/bin/env escript

%main([L]) ->
main([]) ->
    L = [1, 2, 3],
    io:format("list = ~w~n", [L]),
    Avgrage = count_average(L),
    io:format("avrage of ~w = ~w~n",[L,Avgrage]).

num([]) -> 0;
num([H|T]) -> 1+num(T).

sum([]) -> 0;
sum([H|T]) -> H + sum(T).

count_average([]) -> 0;
count_average(L) -> sum(L)/num(L).

运行结果

dingkaideMacBook-Pro:erlang dingkai$ ./avg
./avg:11: Warning: variable 'H' is unused
list = [1,2,3]
avrage of [1,2,3] = 2.0

求N个数的平方和

#! /usr/bin/env escript

main([A]) ->
    N = list_to_integer(A),
    SquareSum = sum_square(N),
    io:format("sum square ~w = ~w~n",[N,SquareSum]).

compute_square(X) -> X*X.

sum_square(1) -> compute_square(1);
sum_square(N) -> sum_square(N-1) + compute_square(N).

运行结果:

dingkaideMacBook-Pro:erlang dingkai$ ./square_sum 10
sum square 10 = 385

连接两个链表

将列表L1和L2连接起来,将L2的元素依次加入L1,代码如下:

#! /usr/bin/env escript

%main([A]) ->
main([]) ->
    L1 = [1, 2, 3],
    L2 = [4, 5, 6],
    L = concatenate(L1, L2),
    io:format("L1 + L2 = ~w~n",[L]),
    io:format("concat of [1, 2, 3] and [4, 5] = ~w~n", [concat([1, 2, 3], [4, 5])]).

%函数reverse将列表逆置
reverse(L) -> reverse(L, []).

reverse([], L) -> L;
reverse([H|T], L) -> reverse(T, [H|L]).

concat(L, []) -> L;
concat(L, [H|T]) -> concat([H|L], T).

concatenate(L1, L2) -> concat(L1, reverse(L2)).

运行结果:

dingkaideMacBook-Pro:erlang dingkai$ ./concat_lists
L1 + L2 = [4,5,6,1,2,3]

这个例子比较有趣的地方在于一个reverse函数和一个concat函数

reverse([H|T], L) -> reverse(T, [H|L]).

的作用是将将第一个列表[H|T]的第一个元素T拿出来放在L的第一位,其实是一个不断剥离原始列表首元素的过程。

举个例子来说,假如L为[1, 2, 3],那么

reverse(L) -> reverse(L, []).

其实就是

reverse([1, 2, 3], [])

而其计算过程是:

reverse([1, 2, 3], []) =>
reverse([2, 3], [1]) =>
reverse([3], [2, 1]) =>
reverse([], [3, 2, 1]) =>
[3, 2, 1]

concat的方法其过程则表达为下面的过程:

concat(L, [H|T]) -> concat([H|L], T)

这就是将第二个列表[H|T]中不断剥离首个元素并插入到L的前面,直到[H|T]为空为止。

例如:contact([1, 2, 3], [4, 5])过程如下:

contact([1, 2, 3], [4, 5]) =>
contact([4, 1, 2, 3], [5]) =>
contact([5, 4, 1, 2, 3], []) =>
[5, 4, 1, 2, 3]

Ceph科普

基本概念

Pool

Pool是Object的逻辑组合,之所以划分成Pool,是因为在Ceph RADOS中,可以按照Pool来设置PG数量、副本策略等。

每个Pool下管辖多个PG,PG的数量可以通过更新Pool的属性来设定。

注意:

  1. Pool是RADOS层抽象的概念,至于映射成更上层的RBD、RGW什么概念,目前尚不清楚;
  2. Pool是逻辑概念,不同Pool可能的内容映射至底层相同的OSD;
  3. 实践中可以为每个pool在crushmap中定义rule,可以指定pool的一些个性化策略,比如可以为某个pool设置特定的存储介质ssd、设定pool的副本数等。

Continue reading Ceph科普