前面的一篇博文Makefile之大型工程项目子目录Makefile的一种通用写法介绍了大型项目子目录Makefile的一种通用写法,然而最近在写Linux网络方面的demo,一个目录下有几个文件,如果手工输命令显得太不专业了。于是按该博文的方法改编了一下Makefile,也当学习之用。该Makefile适用于一个C文件生成一个可执行程序的场景(代码片段3适用于多个C文件生成一个可执行程序),使用该方法当工程目录内的文件有增删时无需对Makefile进行改动,可以说相当的智能。如果对patsubst、wildcard及subst函数不了解的话可参阅上述博文。同时在测试过程中,又发现了一种更简洁的写法,如代码片段2,应该是使用了某些隐式规则,由于项目较忙,还未来得及深入研究,先记录下来,等空下来再研究,还望路过大侠多多指点。
1:如果在当前目录中直接make的话使用下列代码:
#General Purpose Makefile by guoqingbo objects := $(patsubst %.c,%.o,$(wildcard *.c)) executables := $(patsubst %.c,%,$(wildcard *.c)) all : $(objects) $(objects) : %.o: %.c gcc -c $< -o $@ gcc $< -o $(subst .o, ,$@) clean : @rm -rf *.o *~ @rm -rf ${executables} .PHONY : clean2:后来发现下列代码也可以有相同效果,难道使用了什么隐式规则,还不是很明白,先记录下来:
#General Purpose Makefile by guoqingbo CC = gcc executables := $(patsubst %.c,%,$(wildcard *.c)) all : $(executables) clean : @rm -rf *.o *~ @rm -rf ${executables} .PHONY : clean3:多个C文件生成一个可执行程序的情况:
#General Purpose Makefile by guoqingbo CC = gcc #source_file := $(wildcard *.c) objects := $(patsubst %.c,%.o,$(wildcard *.c)) #executables := $(patsubst %.c,%,$(wildcard *.c)) target := client #%.o : %.c # gcc -c $< -o $@ all: $(target) $(target): $(objects) gcc $^ -o $@ clean: rm -f *.o rm -rf $(target) .PHONY: clean
查看端口:
ps -aux | grep tomcat
发现并没有8080端口的Tomcat进程。
使用命令:netstat –apn
查看所有的进程和端口使用情况。发现下面的进程列表,其中最后一栏是PID/Program name
发现8080端口被PID为9658的Java进程占用。
进一步使用命令:ps -aux | grep java,或者直接:ps -aux | grep pid 查看
就可以明确知道8080端口是被哪个程序占用了!然后判断是否使用KILL命令干掉!
方法二:直接使用 netstat -anp | grep portno
即:netstat –apn | grep 8080
查看进程:
1、ps 命令用于查看当前正在运行的进程。
grep 是搜索
例如: ps -ef | grep java
表示查看所有进程里 CMD 是 java 的进程信息
2、ps -aux | grep java
-aux 显示所有状态
ps
3. kill 命令用于终止进程
例如: kill -9 [PID]
-9 表示强迫进程立即停止
通常用 ps 查看进程 PID ,用 kill 命令终止进程
在实际生产开发中,遇到一些多节点共存,需要选主,并且要实现HA自动容错的场景,思考了写方法拿出来和大家分享一下。
系统中有很多应用场景要类似主从架构,主服务器(Master)对外提供服务,从服务器(Salve)热备份,不提供服务但随时活着,如果Master出现宕机或者网络问题,Slave即可接替Master对外服务,并由Slave提升为Master(新主)。典型的多节点共存,但只能同时存在一个主,并且所有节点的状态能统一维护。
大家一定首先想到了著名的Paxos算法(http://baike.baidu.com/view/8438269.htm)。简单的说,Paxos通过每个节点的投票算法,来决议一个事情,当多余1/2个节点都投票通过时,Paxos产生一个唯一结果的决议,并通知各个节点维护这个信息。例如Paxos的选主,首先产生一个关于某个节点希望当Master的投票,然后各个节点给出反馈,最终Paxos集群维护唯一的Master的结论。Zookeeper就是Paxos的一种实现。这种场景最适合用zookeeper来选主,但zookeeper有个明显的缺点,当存活的节点小于zookeeper集群的1/2时,就不能工作了。比如zk有10各节点,那么必须满足可用的节点大于5才可。
在实际环境中,如果对Master要求不是那么严格的话,可以通过某些改进和取舍来达到目的。比如可能在秒级别允许Master暂时不能访问、选主时间内可能存在一定的冲突但通过再次选主即可。本人设计了一个简易的利用Mysql一致性和简易版Lease来workaround。
Mysql ACID保证了一条数据记录的一致性、完整性,不会出现多进程读写的一致性问题和唯一正确性。Lease协议(协议细节可以Google之)通过向Master发送一个lease(租期)包,Master在这个lease期之内充当主角色,如果lease期到了则再次去申请lease,如果lease期到了,但是网络除了问题,这时Master可以i主动下线,让其他节点去竞选Master。举个例子,三个节点A、B、C经过第一轮选主之后,A成为Master,它获得了10秒的lease,当前时间假设是00:00:00,那么它Master地位可以用到00:00:10,当时间到达00:00:10时,A、B、C会重新进行Master选举,每个节点都有可能成为Master(从工程的角度触发,A继续为Master的概率更大),如果这时候A的网络断了,不能联通B、C的集群了,那么A会自动下线,不会去竞争,这样就不会出现“脑裂”的现象。
---------------------------------------------- 华丽的分割线 ----------------------------------------------
设计方案如下:(server代表集群中的一台机器,也可看作一个进程,server之间是平等的)
这其中比较棘手的问题是:
1、由于数据库访问和休眠的时间(lease的一半),有时延的存在,要处理Mysql异常、网络异常。
2、可能存在同时抢占Master的server,这个时候就需要一个验证机制保证为抢到Master的server自动退位为Slaver
下面给出图实例 :(10.0.0.1为Master)
10.0.0.1 crash了。mysql中维护的10.0.0.1的主信息已过期,其他节点去抢占
各个节点再次读取数据库,查看是否是自己抢占成功了:
之后,10.0.0.3作为Master对外服务。此时如果10.0.0.1重启,可作为Slaver。如果10.0.0.1因为网络分化或者网络异常而不能维护心跳,则在超过自身lease时自动停止服务,不会出现“双Master”的现象。
每个Server遵循如下流程:
数据库设计:
某一时刻,数据库中Master的信息:
当前时间: 45分15秒
当前Master Lease :6秒
当前Master Lease可用到: 45分21秒
---------------------------------------------- 华丽的分割线 ----------------------------------------------
3、适用的场景
一、生命周期内可使用Mysql、并且各个server之间时间同步。
二、需要集群中选出唯一主对外提供服务,其他节点作为slaver做standby,主lease过期时竞争为Master
三、对比zookeeper,可满足如果集群挂掉一半节点,也可正常工作的情况,比如只有一主一备。
四、允许选主操作在秒级容错的系统,选主的时候可能有lease/2秒的时间窗口,此时服务可能不可用。
五、允许lease/2秒内出现极限双Master情况,但是概率很小。
---------------------------------------------- 华丽的分割线 ----------------------------------------------
4、Java语言实现描述
一些配置信息和时间相关、休眠周期相关的时间变量
final long interval = lease / intervalDivisor; long waitForLeaseChallenging = 0L; lease = lease / 1000L; long challengeFailTimes = 0L; long takeRest = 0L; long dbExceptionTimes = 0L; long offlineTime = 0L; Random rand = new Random(); Status stateMechine = Status.START; long activeNodeLease = 0L; long activeNodeTimeStamp = 0L;
数据库异常的处理:
KeepAlive keepaliveNode = null; try { /* first of all get it from mysql */ keepaliveNode = dbService.accquireAliveNode(); if (stateMechine != Status.START && keepaliveNode==null) throw new Exception(); // recount , avoid network shake dbExceptionTimes = 0L; } catch (Exception e) { log.fatal("[Scanner] Database Exception with times : " + dbExceptionTimes++); if (stateMechine == Status.OFFLINE) { log.warn("[Scanner] Database Exception , OFFLINE "); } else if (dbExceptionTimes >= 3) { log.fatal("[Scanner] Database Exception , Node Offline Mode Active , uniqueid : " + uniqueID); stateMechine = Status.OFFLINE; dbExceptionTimes = 0L; offlineTime = System.currentTimeMillis(); online = false; } else continue; }
总的循环和状态机的变迁:
while (true) { SqlSession session = dbConnecction.openSession(); ActionScanMapper dbService = session.getMapper(ActionScanMapper.class); KeepAlive keepaliveNode = null;