多服务器处理数据的两种方式

时间:2021-02-09 13:14:34

多台服务器共同处理业务,肯定会遇到资源冲突的问题,笔者采用过两种方法解决这个问题。

方法一:保证多台服务器只有一台在处理!  

下面是一个录题的操作,如果有服务器处理 会在redis(ps:一种内存级别访问速度的缓存)中写入一个时间,其他服务器处理前先看redis里的这个时间,如果有且时间很近(离当前还不到90s),表明已有服务器在运行,本服务器不做任何处理。具体代码如下:

    @Scheduled(cron = "0 * * * * ?")
public void record(){
if(!isExcuteAble()){//上次运行时间存在且到现在还不到90s,返回false,表明不用启动本服务器
System.out.println("ReRecord errqs schedule task is interrupted for other server is working");
return;
}
updateLastRunTime();//成功启动服务更新缓存中的时间
List
<ErrorQuestion> qsList=repository.findAllOfNotRecord();
for(ErrorQuestion qs:qsList){
if(recordService.record(qs.getTestPaper().getOriginalPaperId(), qs.getErrInfo())){
qs.setStatus(ErrqsStatus.NORMAL);
repository.save(qs);
}
updateLastRunTime();//每当处理一条数据更新缓存中的时间标志,保证标志的有效性
}

}
private boolean isExcuteAble(){//判断是否可以启动本服务器
Jedis jedis
= redisConnectionFactory.getJedis();
try{
String lastTimeStr
=jedis.get(LAST_RUN_TIME);
if(null==lastTimeStr) {
return true;
}
Long lastRunTime
=Long.valueOf(lastTimeStr);
return new Date().getTime() - lastRunTime >= 90000;
}
finally{
jedis.close();
}
}
private void updateLastRunTime(){//更新时间标志
Jedis jedis
= redisConnectionFactory.getJedis();
try{
String lastTimeStr
=String.valueOf(new Date().getTime());
jedis.set(LAST_RUN_TIME, lastTimeStr);
}
finally{
jedis.close();
}
}

方法二,多台服务器并行处理,保证资源不冲突。

下面的例子是处理每个学生的考试数据流程,关键代码是解决多台服务器的资源竞争的问题,方案如下:

    /**
*
* @Title: getOneUnhandleAndSetHandling
* @Description: 用于多台服务器操作数据库时的资源竞争问题。
*
@return 找到一条UNHANDLE状态的数据,将其状态置为HANDLING后返回
*/
private ErrorsExam getOneUnhandleAndSetHandling(){
while(true){ //1
try{
ErrorsExam exam
=repository.findOneUnhandle(); //2
if(null==exam) {
return null;
}
exam.setStatus(ErrorBookStatus.HANDLING); //3
return repository.save(exam); //4
}
catch(Exception e){
System.err.println(
"get one unhandle exam confictly and will get the next!");
}
}

}

注意:由于本例中采用mongo,其自带的有版本控制——假如多台服务器同时取到同一条数据,将数据的状态改成HANDLING,然后入库,但是由于存在版本控制,永远只会有一台服务器操作成功,并返回结果,其他服务器会抛出资源OptimisticLockException的异常,然后继续while循环,直到成功或没有资源返回null。

服务处理如下:

    @Override
public void handleAllErrexams() {
while(true){
ErrorsExam exam
=getOneUnhandleAndSetHandling(); //这就是刚才定义的方法!
if(null==exam) break;
handleOneExam(exam);
}

}

是不是很简单!

 更多方法解决资源竞争的,欢迎一起交流学习哦!