时钟同步和时钟修正的小技巧

简介:

引入:

时钟同步一直是一个比较热的话题。因为它涉及到许多具体场景。

场景A: 2个系统做交易,A系统下订单,B系统管理订单。结果因为B系统比A慢5分钟,A下单完了,B获得的时间居然是一个未来的时间。

场景B: 搞双十一了,某公司的网上电子商城需要在11月11北京时间凌晨0点启用应急预案,然后启用强大的促销规则。结果因为时钟比北京时间慢了10分钟。等11月11零点,大量抢购的人一下子拥入网上电子商城,造成该公司访问量的“井喷”式的增长,但是因为服务器还在11月10日晚上23:50,所以没有启用应急预案,也没有使用促销规则。结果服务器挂了,客户跑了。。。


解决方案:

以上就是目前一些非常典型的时钟不同步的例子:


对于场景A,一般做法是吧某台服务器作为中央时钟服务器,让其作为标准的时钟服务器。然后确保所有服务器都可以访问此中央时钟服务器,并且依次在每台需要时钟同步的机器上运行命令 ntpupdate <时钟服务器IP>即可。


但是场景A有一个致命缺陷就是所有的服务器都必须能连接到时钟服务器。这对于大型企业有多个区段划分,彼此多个网段,网段之间相互又不通的情况,无法解决。那么在联网的情况下,这里有一个变通的轻量级的方法,可以让所有服务器(尤其是服务器上运行着代码的地方),和北京时间同步,这种解决方案也许更加适合场景B。

这里我写了一个工具类,它可以有效的和北京时间同步,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package  com.charles.study;
 
import  java.io.BufferedReader;
import  java.io.IOException;
import  java.io.InputStreamReader;
import  java.net.HttpURLConnection;
import  java.net.MalformedURLException;
import  java.net.URL;
import  java.text.DateFormat;
import  java.text.SimpleDateFormat;
import  java.util.Calendar;
import  java.util.Date;
import  java.util.TimeZone;
 
/**
  * 这个工具类用于获得标准的北京时间
  * @author charles.wang(mailto:charles_wang888@126.com)
  *
  */
public  class  BeijingDateTimeUtil {
     
     private  BeijingDateTimeUtil(){}
     
     
     public  static  final  String BEIJING_TIME_SERVICE_URL= "http://www.beijing-time.org/time.asp" ;
     public  static  final  String BEIJING_TIME_ZONE =  "GMT+8" ;
     
     
     /**
      * retrieve the standard beijing time by beijing time service
      * @return Calendar which stands for current beijing time
      */
     public  static  Calendar retrieveBeijingStandardDatetime() {
         
         try {
             
             
         //access the webpage which can provide precise beijing-time    
         URL url =  new  URL(BEIJING_TIME_SERVICE_URL);
         HttpURLConnection uc = (HttpURLConnection) url.openConnection();
         uc.connect();
         
         StringBuilder sb =  new  StringBuilder();
         BufferedReader br =  new  BufferedReader( new  InputStreamReader(uc.getInputStream()));
         
         String line;
         while  ((line = br.readLine()) !=  null ) {
             sb.append(line);
         }
         
         String beijingTimeInfoString = sb.toString();
         String[] infos = beijingTimeInfoString.split( ";" );
         
         //split information which can stand for year/month/day/dayOfWeek/hour/minute/second
         int  year         = Integer.parseInt(infos[ 1 ].substring(infos[ 1 ].indexOf( "=" )+ 1 ));
         int  month        = Integer.parseInt(infos[ 2 ].substring(infos[ 2 ].indexOf( "=" )+ 1 ));
         int  day          = Integer.parseInt(infos[ 3 ].substring(infos[ 3 ].indexOf( "=" )+ 1 ));
         int  dayOfWeek    = Integer.parseInt(infos[ 4 ].substring(infos[ 4 ].indexOf( "=" )+ 1 ));
         int  hour         = Integer.parseInt(infos[ 5 ].substring(infos[ 5 ].indexOf( "=" )+ 1 ));
         int  minute       = Integer.parseInt(infos[ 6 ].substring(infos[ 6 ].indexOf( "=" )+ 1 ));
         int  second       = Integer.parseInt(infos[ 7 ].substring(infos[ 7 ].indexOf( "=" )+ 1 ));
         
         //create a calendar object 
         //make sure that (1)using Beijing timezone
         //               (2)month starts from 0 instead of 1
         Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(BEIJING_TIME_ZONE));
         cal.set(year,month- 1 ,day,hour,minute,second);
         return  cal;
         
         } catch (MalformedURLException ex){
             ex.printStackTrace();
             return  null ;
         } catch (IOException ex){
             ex.printStackTrace();
             return  null ;
         }
 
         
     }
     
     
     
     public  static  void  main(String [] args) {
         
         
         Calendar beijingCalendar = retrieveBeijingStandardDatetime();
         if (beijingCalendar!= null ){
             Date beijingDatetime = beijingCalendar.getTime();
             DateFormat df =   new  SimpleDateFormat( "yyyy-MM-dd HH:mm:ss Z" );
             String dateFormatStr  = df.format(beijingDatetime);
             System.out.println( "Beijing Current Datetime:" +dateFormatStr);
         } else {
             System.out.println( "BeijingTime service not available" );
         }    
         
     }
 
}


执行示例代码中的测试,我们可以看到:

wKiom1R7PUPCNP18AAD9EzDMsio971.jpg

这里也可以看出,我的笔记本时间比北京时间快9秒。





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1584883,如需转载请自行联系原作者
目录
相关文章
|
芯片
hi3531的时钟系统
<p>时钟管理模块对芯片时钟输入、时钟生成和控制进行统一的管理,包括:<br> 时钟管理模块有以下两部分输入:<br><img alt="1" src="http://img.blog.csdn.net/20131214090107859?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbWFvMDUxNA==/font/5a6L5L2T/fon
965 0
|
算法 Java Go
分布式系统-同步化-时钟同步-物理时钟与Lamport时间戳(逻辑时钟)
分布式系统 同步化 时钟同步 物理时钟 Lamport时间戳 逻辑时钟
1120 0
分布式系统-同步化-时钟同步-物理时钟与Lamport时间戳(逻辑时钟)
时钟频率是干什么的?底层原理是什么?
时钟频率是干什么的?底层原理是什么?
414 0
通过定时器T1查询方式控制LED1周期性闪烁(模模式)
通过定时器T1查询方式控制LED1周期性闪烁(模模式) 宏定义与函数声明 初始化 主函数
269 0
|
10月前
[STM32F10x] 利用定时器测量频率
[STM32F10x] 利用定时器测量频率
88 2
|
12月前
【蓝桥杯嵌入式】STM32定时器的配置,解析预分频系数和重装载值与时钟频率的关系
【蓝桥杯嵌入式】STM32定时器的配置,解析预分频系数和重装载值与时钟频率的关系
399 0
STM32 通过外部时钟输入模式测量频率,串口打印
SQLALchemy是Python中的一款优秀的ORM框架,它可以作用于任何第三方Web框架,如flask,tornado等框架。
357 0