应用集群(1)-节点间的文件同步策略

公司要将第七代产品进行集群化部署,设计方案自然是花落我家,哈哈。首先我们在研发7代产品时,已经兼顾了集群部署,但总还有一些遗漏的地方。趁着这个机会梳理出来,并附上解决方案。
今天先谈下集群中应用文件的同步问题。应用文件指的是保存在应用节点下的文件。为什么文件要保存在应用节点下,而不是保存在FTP、NFS等存储媒介呢?是因为这些文件是表单、流程、移动平台的过程文件。比如你画一个表单,就会产生一个记录表单控件的edit.html文件;你画一个流程,就会产生一个记录节点位置信息的xml文件。这些文件记载了表单、流程等运行的基础信息,由于历史原因,这些信息并不能入库,只能保存在各个应用节点 。
那么问题来了,你在维护了某表单的信息,request会通过nginx转发到node_01上,这时仅node_01修改了html文件。当你要访问这个表单时,request又会转发到另node_02上,而02节点是没有修改html文件的。这就是应用间文件不一致的问题引发的问题。
如何解决呢?方案有三个
方案1:节点更新文件后,使用httpClient将文件推动到其它节点;
优点:实时性高
缺点:稳定性差
方案2:节点更新文件后,将文件上传到FTP,在数据库中生成消息;可以在其它节点在访问文件时,根据消息判断是否从ftp上下载文件;也可以建立定时任务来自动同步文件;
优点:实时性低
缺点:稳定性高
方案3:使用redis实现发布/订阅功能(当然最好用队列,但公司明确表示不部署MQ服务,只好退而求其次选择redis了),当节点更新文件后,将文件上传到FTP,再发布消息,其它节点收到消息后立即从ftp下载最新文件。因为redis实现的消息队列功能没有完备的可靠发布和可靠消费,先暂时用数据库记录下节点的是否发布和是否下载。
Redis发布订阅功能的特性:
1.消息发送者与接收者通过channel绑定,channel是可以确定的字符串,也可机遇模式匹配;
2.客户端可以订阅任意过个channel;
3.发送者发送的消息无法持久化,所以可能会造成消息丢失;
4.由于消息无法持久化,所以消费者无法订阅channel之间发送的消息;
5.发送者与客户端之间的消息发送与接收不存在ACK机制.

最终领导选择了方案3(欣慰),顺便贴出一段伪代码。其实在springboot使用redis订阅发布很简单:

/**
 * 第一步:初始化redis主题(这里引用的redisson的jar,也可用其它封装好的jar)
 * @from redisCongif.java
 * @author chengmeng
 */
private void initRedisTopic() {
	//webSocket通信
	RTopic webSocketTopic = redissonClient.getTopic(Constant.TOPIC_WEBSOCKETMSG, new SerializationCodec());
	webSocketTopic.addListener(Map.class, new SocketPushMsgListener());
	//应用文件同步
	RTopic syncFileTopic = redissonClient.getTopic(Constant.TOPIC_SYNCFILEMSG, new SerializationCodec());
	syncFileTopic.addListener(Map.class, new SyncFileListener());
}
/**
 * 第二步:发布消息
 * @author chengmeng
 */
public static RFuture<Long> pushMsg(String topicName, Object obj) {
    RedissonClient RedissonClient = BeanUtils.getBean(RedissonClient.class);
    RTopic rTopic = RedissonClient.getTopic(topicName, new SerializationCodec());
    RFuture<Long> result = rTopic.publishAsync(obj);
	return result ;
}
/**
 * 第三步:接受消息(定义的监听器,覆写onMessage方法即可)
 * @from SyncFileListener.java
 * @author chengmeng
 */
@Override
public void onMessage(CharSequence charSequence, Map<String, String> msg) {
	//1.下载
	AttachUtils.downloadTempFile(fileCode, null);
	//2.入库
	SyncFileUtils.writeSyncInfoToDB(new Object[] {fileCode, "remark"});
}

你可能感兴趣的:(集群,redis,消息队列)