【JRaft源码分析02】心跳机制以及日志复制

日志复制是所有分布式共识算法最重要也是最复杂的部分,需要考虑各种各样安全性,比如机器挂了持久化没做、网络分区导致term&logindex不一致、成员变化带来两个任期相同的leader、异步网络出现日志乱序等等。

很多个细节,我边看源码边照着论文理解,一个异常判断反复推敲它的作用,想象发生的场景。这是源码级熟悉raft的好处,多多少少能身临其境,获取更多的实战校验。

后面至少还有两篇,成员变化和日志压缩。

花了点时间做张较为直观的简化流程图,红色箭头是日志复制的过程。还是挺复杂的,包括不限于Node、LogManager、Replicator、BallotBox、StateMachine之间的调用,其实还有快照,以后再讲。

本文会分为三部分讲,写请求日志落盘、日志复制、commit执行StateMachine。 日志复制状态机

Read more...

【JRaft源码分析01】启用以及选举过程

最近潜心cap理论和raft算法,选用了蚂蚁金服的sofa-jraft,深入研究具体的实现。该框架参考自百度的BRAFT,可以说是非常优秀的分布式通用框架,很值得学习。

Raft算法的理论就不再多说了,感性认识的话可以看这个动画,非常好懂。

1、启动入口

示例在github的jraft-example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
RaftGroupService raftGroupService = new RaftGroupService(groupId, serverId, nodeOptions, rpcServer);
//依次实例化NodeManager、NodeImpl、RpcServer
Node node = raftGroupService.start();

public synchronized Node start(final boolean startRpcServer) {
    NodeManager.getInstance().addAddress(this.serverId.getEndpoint());
    this.node = RaftServiceFactory.createAndInitRaftNode(this.groupId, this.serverId, this.nodeOptions);
    if (startRpcServer) {
        this.rpcServer.startup();
    }
}

2、包罗万象的Node

分布式系统关键单体就是节点Node,它包括raft分布式算法中需要的所有行为,不限于选举、投票、日志、复制、接收rpc请求等,梦开始的地方。

Node结构图

Read more...

【生产问题】时隔大半年,分享一次Nginx反向代理的需求

博客前面分享了一篇《分享一个 Nginx 正向代理的另类应用案例》,时隔不久,身为救火队员、万金油的博主又再一次接到了一个奇葩需求:

场景和上次有些类似,也是部门引进的第三方应用,部署在各个网络区域,从 OA 办公区域无法直接访问。目前,运营人员都需要登陆 Windows 跳板机,才能打开这些应用的 WEB 控制台。既不方便,而且还有一定 Windows 服务器的维护工作量,于是找到我们团队,希望通过运维手段来解决。

拿到这个需求后,我先问了下各个应用的基本情况,得知每个应用的框架基本是一样的,都是通过 IP+端口直接访问,页面 path 也基本一样,没有唯一性。然后拿到了一个应用 WEB 控制台地址看了下,发现 html 引用的地址都是相对路径。

乍一想,这用 Nginx 代理不好弄吧?页面 path 一样,没法根据 location 来反代到不同的后端,只能通过不同 Nginx 端口来区分,那就太麻烦了!每次他们新上一个应用,我们就得多加一个新端口来映射,这种的尾大不掉、绵绵不绝事情坚决不干,Say pass。

再一想,我就想到了上次那个正向代理另类应用方案,感觉可以拿过来改改做动态代理。原理也简单:先和用户约定一个访问形式,比如:

Nginx 代理地址为 myproxy.oa.com,需要代理到 IP 为 192.168.2.100:8080 的控制器,用户需要访问 http://myproxy.oa.com/192.168.2.100:8080/path

Read more...

【问题小排查】排查 CLOSE_WAIT 堆积

TCP 连接的 CLOSE_WAIT 状态,正常情况下是短暂的,如果出现堆积,一般说明应用有问题。

CLOSE_WAIT 堆积的危害

每个CLOSE_WAIT连接会占据一个文件描述,堆积大量的CLOSE_WAIT可能造成文件描述符不够用,导致建连或打开文件失败,报错too many open files:

1
dial udp 9.215.0.48:9073: socket: too many open files

如何判断?

检查系统CLOSE_WAIT连接数:

1
lsof | grep CLOSE_WAIT | wc -l

检查指定进程CLOSE_WAIT连接数:

1
lsof -p $PID | grep CLOSE_WAIT | wc -l

为什么会产生大量 CLOSE_WAIT?

我们看下 TCP 四次挥手过程:

tcp_established

Read more...

【问题小排查】Service无法解析

检查kube-dns或CoreDNS服务是否正常

  1. kubelet 启动参数 –cluster-dns 可以看到 dns 服务的 cluster ip:
1
2
$ ps -ef | grep kubelet  
... /usr/bin/kubelet --cluster-dns=172.16.14.217 ...
  1. 找到 dns 的 service:
1
2
$ kubectl get svc -n kube-system | grep 172.16.14.217  
kube-dns              ClusterIP   172.16.14.217   <none>        53/TCP,53/UDP              47d
  1. 看是否存在 endpoint:
1
2
3
$ kubectl -n kube-system describe svc kube-dns | grep -i endpoints  
Endpoints:         172.16.0.156:53,172.16.0.167:53  
Endpoints:         172.16.0.156:53,172.16.0.167:53
  1. 检查 endpoint 的 对应 pod 是否正常:
1
2
$ kubectl -n kube-system get pod -o wide | grep 172.16.0.156  
kube-dns-898dbbfc6-hvwlr            3/3       Running   0          8d        172.16.0.156   10.0.0.3
Read more...

【问题小排查】关于怎么查IO高负载

系统如果出现 IO WAIT 高,说明 IO 设备的速度跟不上 CPU 的处理速度,CPU 需要在那里干等, 这里的等待实际也占用了 CPU 时间,导致系统负载升高,可能就会影响业务进程的处理速度,导致业务超时。

如何判断 ?

使用top命令看下当前负载:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
top - 19:42:06 up 23:59,  2 users,  load average: 34.64, 35.80, 35.76
Tasks: 679 total,   1 running, 678 sleeping,   0 stopped,   0 zombie
Cpu(s): 15.6%us,  1.7%sy,  0.0%ni, 74.7%id,  7.9%wa,  0.0%hi,  0.1%si,  0.0%st
Mem:  32865032k total, 30989168k used,  1875864k free,   370748k buffers
Swap:  8388604k total,     5440k used,  8383164k free,  7982424k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 9783 mysql     20   0 17.3g  16g 8104 S 186.9 52.3   3752:33 mysqld
 5700 nginx     20   0 1330m  66m 9496 S  8.9  0.2   0:20.82 php-fpm
 6424 nginx     20   0 1330m  65m 8372 S  8.3  0.2   0:04.97 php-fpm

%wa(wait) 表示 IO WAIT 的 cpu 占用,默认看到的是所有核的平均值,要看每个核的%wa值需要按下 “1”:

Read more...

【问题小排查】Linux任务计划crontab不执行的问题排查

朋友弄了一个小项目,要我帮忙做下 Linux 系统运维,上线一段时间后,发现项目偶尔会挂掉导致服务不可用。 开发朋友一时之间也没空去研究项目奔溃的根因,只好由我这个运维先写一个项目进程自拉起脚本, 通过 Linux 任务计划每分钟检查一下进程是否存在来避免项目挂了没人管的情况。

自拉起脚本很简单,随便写几行就搞定了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
processcount=$(pgrep my_app|wc -l)
cd $(cd $(dirname $0) && pwd)
if [[ 0 -eq $processcount ]]
then
        echo "[ $(date) ] : my_app is down, start it!" | tee -ai ./checkprocess.log
        bash ./start.sh #这里是项目的重启脚本
else
        echo my_app is OK!
fi

然后丢到 crontab,1 分钟执行一次:

1
* * * * * bash /data/app_server/checkprocess.sh >/dev/null 2>&1

-_-不过进程还是挂了

Read more...