2013-11-03 17 views
5

Như:Leap thứ hai xử lý trong cơ sở dữ liệu

The Unix time number is zero at the Unix epoch, and increases by exactly 86400 
per day since the epoch. So it cannot represent leap seconds. The OS will slow 
down the clock to accomodate for this. 

Vì vậy, nếu tôi lưu trữ Unix kỷ nguyên (ví dụ ts) trong DB (độ chính xác milli-giây), làm thế nào để xử lý các trường hợp sau đây?

  1. Làm thế nào để đảm bảo các ts luôn tăng và không lùi?
  2. Làm thế nào để chọn chính xác khoảng 100 giây từ db có tính đến bước nhảy vọt thứ hai?

ví dụ:

SELECT * FROM events WHERE ts >= T1 and ts < T1 + 100 

SQL ở trên sẽ trở lại sự kiện đó xảy ra tại T1, T1 + 1, T1 + 2, ..up để T1 + 99, nhưng vì do nhảy giây, kết quả có thể là sai bằng cách bao gồm các bước nhảy vọt thời gian của 1s, làm thế nào để đưa tài khoản vào điều này?

Trả lời

4

Tôi sẽ bắt đầu bằng cách nói rằng tôi đã không được đối mặt với một vấn đề như vậy trong cuộc sống thực vì vậy tôi sẽ chỉ đoán nhưng nó sẽ là một giáo dục đoán. Theo số http://en.wikipedia.org/wiki/Unix_time#Encoding_time_as_a_number khi số giây nhảy vọt được chèn vào vấn đề là 2 lần (ví dụ: 1998-12-31T23: 59: 60.00 và 1999-01-01T00: 00: 00.00) có cùng thời gian Unix (915.148.800.000). Khi một giây nhảy vọt bị xóa thì không có vấn đề gì.

Theo Lưu ý # 2 trên cùng một giây nhảy vọt trên trang Wikipedia không thể dự đoán được, bạn sẽ có 2 lựa chọn: một giải pháp chung (giả sử bạn có bảng được chỉ mục bởi các dấu thời gian này) luôn có thể chèn mục nhập và thời điểm mục nhập xảy ra trước mục nhập chèn cuối cùng (có thể trong vòng một giây) bạn có thể bắt đầu quá trình 'bôi nhọ', về cơ bản là thêm một số mili giây vào mục nhập để đảm bảo nó rơi ra khỏi phạm vi bước nhảy vọt thứ hai. Quá trình có thể dừng lại thời điểm mục nhập được chèn lại sẽ có giá trị lớn hơn mục nhập được chèn trước đó. Tôi gọi đây là 'bôi nhọ' bởi vì nó bằng cách nào đó lấy cảm hứng từ "Leap Smear" kỹ thuật của Google (mặc dù không hoàn toàn giống nhau): http://googleblog.blogspot.in/2011/09/time-technology-and-leaping-seconds.html Cách tôi nhìn thấy nó mặc dù điều này có thể đặt một số căng thẳng cho cơ sở dữ liệu của bạn và truy vấn chèn sẽ chỉ là về là một các truy vấn phức tạp nhất mà tôi đã thấy (nếu thậm chí có thể trong SQL một mình).

Một giải pháp khác có thể (tôi giả sử bạn đang sử dụng Java) mà bạn tự kiểm tra xem dấu thời gian nằm trong một bước nhảy vọt thứ hai hay không. Nếu có, chỉ cần chặn bất kỳ quyền truy cập nào vào cơ sở dữ liệu và chèn các mục nhập vào hàng đợi. Khi bước nhảy vọt thứ hai kết thúc, chỉ cần chèn hàng đợi theo cách FIFO vào cơ sở dữ liệu để đảm bảo thứ tự bạn quan tâm (tương tự như giải pháp ở trên nhưng hoàn toàn bằng Java, vì vậy trước khi nó chạm vào lớp DB). Bạn có thể tối ưu hóa điều này một chút bằng cách loại bỏ hàng đợi và chèn trực tiếp vào DB - chỉ cần 'bôi nhọ' các mục trong một giây như trên. Tất nhiên có nhược điểm là bạn hy sinh một chút chính xác trong bước nhảy vọt thứ hai (không phải là một sự hy sinh lớn xem xét giây nhuận là rất hiếm) nhưng cộng thêm là nó đơn giản và trật tự của bạn được đảm bảo.

Nếu bạn hay bất cứ ai tìm thấy giải pháp tốt hơn xin vui lòng chia sẻ ở đây, chủ đề này là khá thú vị :)

Cập nhật: i đã viết mã giả cho một giải pháp thứ 3 (hoàn toàn trong truy vấn SQL) mà dựa trên một kiểm tra hardcoded cho một bước nhảy vọt thứ hai (nhanh hơn so với một giải pháp chung chung).Nó có lẽ có thể được tối ưu hóa rất nhiều nhưng chỉ để chứng minh quan điểm của tôi:

if (newTime is in a leap second){ 
    read smearCount from db; 
    if (smearCount <= 0) { 
     smearCount = 1000; // making sure we land outside the leap second 
     update smearCount in db; 
    } 
    newTime += smearCount; 
    insert newTime into db; 
} else { // gradually reducing smearCount by 1 millisecond over the following 1000 insertions 
    read smearCount from db; 
    if (smearCount > 0){ 
     smearCount -= 1; 
     update smearCount in db; 
     newTime += smearCount; 
    } 
    insert newTime into db; 
} 
+1

+1 nhưng thực hiện điều này trên lớp db có thể dễ dàng hơn (suy nghĩ của ORA-04091 nổi tiếng: bảng XXXX bị tắt, kích hoạt/chức năng có thể không nhìn thấy nó) –

+0

Hãy nghĩ về nó có thể nó thực sự đơn giản hơn tôi nghĩ. Việc kiểm tra bước nhảy vọt thứ hai cũng có thể được mã hóa cứng trong mã chèn SQL. Vấn đề duy nhất (mà không phải là một vấn đề ở tất cả) sẽ được đọc (và tăng trong cơ sở dữ liệu chính nó) một số 'smear' (số mili giây bạn giả tạo thêm). – Sandman

+0

@ HAL9000: lỗi "kích hoạt đột biến" thường phát sinh khi mọi người không hiểu rằng Oracle có trình kích hoạt cấp hàng không cần bất kỳ DML nào trên bảng được kích hoạt.Và mã trên có thể thay đổi thời gian cho một hàng duy nhất mà không gặp bất kỳ vấn đề nào (mặc dù tôi sẽ không sử dụng trình kích hoạt - một quy trình xử lý mọi thứ sẽ là lựa chọn tốt hơn) –

3

Từ Joda Time FAQ:

có giây nhuận được hỗ trợ?

Thời gian Joda không hỗ trợ giây nhảy vọt. Các giây nhuận có thể được hỗ trợ bằng cách viết một niên đại chuyên ngành mới, hoặc bằng cách thực hiện một vài cải tiến cho lớp hiện tại ZonedChronology . Trong cả hai trường hợp, các phiên bản Joda-Time trong tương lai sẽ không cho phép các giây nhảy vọt theo mặc định. Hầu hết các ứng dụng không cần thiết và có thể có thêm chi phí hiệu suất.

Từ IANA/Olson TZDB file on leap seconds:

Mặc dù định nghĩa cũng bao gồm khả năng thả giây ("tiêu cực" giây nhuận), điều này chưa bao giờ được thực hiện và dường như không cần thiết trong tương lai gần.

câu hỏi đầu tiên của bạn:

Làm thế nào để đảm bảo rằng các ts luôn tăng và không lạc hậu?

Một bước nhảy vọt thứ hai tiêu cực sẽ để lại cho bạn tại timestamp cùng (một giá trị cho hai giây trôi qua), do đó bạn có thể không thực sự đi lùi mà ko hai giây nhuận tiêu cực. Vì nó không xuất hiện có khả năng là sẽ có một giây nhảy vọt tiêu cực, tôi muốn nói đây là một vấn đề bạn sẽ không bao giờ thực sự gặp phải.

Cập nhật: Cách duy nhất tôi có thể hình dung dấu thời gian quay trở lại là nếu bạn sử dụng chính xác mili giây và hành vi gặp phải # 3 bên dưới.

câu hỏi thứ hai của bạn:

Làm thế nào để chọn chính xác khoảng 100 từ db mà lấy tài khoản vào những bước nhảy vọt thứ hai?

Vì thời gian ghi của bạn bằng UTC, giá trị của bạn đã bao gồm số giây nhảy vọt. Tôi biết rằng âm thanh có thể phản trực giác, vì khi bạn mô tả chính xác là 86400 giây (86400000 mili giây) trong một ngày theo thang điểm này. Nhưng họ thực sự ở đó. Nếu không - thì chúng tôi sẽ đồng bộ hóa với TAI chứ không phải là UTC. Vì vậy, làm thế nào có thể được? Vâng, có một vài điều khác nhau có thể xảy ra khi một bước nhảy vọt thứ hai xảy ra:

  1. Nếu giây nhuận được hỗ trợ bởi cả hai hệ điều hành và các mã ứng dụng, sau đó nó có thể thực hiện một show giây như :60 hoặc :61. Nhưng hầu như không có triển khai thực sự nào về điều này bởi vì các ngôn ngữ lập trình thường chỉ cho phép giây trôi qua là :59.

  2. Hệ điều hành có thể "đóng băng" trong một giây, cho cùng một giá trị trong một giây.

  3. Hệ điều hành có thể tiến lên :59.999 và sau đó nhảy trở lại :59.000 để lặp lại khoảng thời gian được bao phủ bởi bước nhảy vọt thứ hai. (nhờ @Teo)

  4. Hệ điều hành có thể "trôi" hoặc "bôi nhọ" một lúc, từ từ thêm vài phần nghìn giây vào đồng hồ hệ thống, cho đến khi nó hoàn toàn bắt kịp giây thứ hai.

  5. Hệ điều hành có thể bỏ qua ngay và không làm gì cả. Đồng hồ của bạn sẽ không đồng bộ hóa cho đến lần đồng bộ hóa tiếp theo qua NTP. Và nếu nó xảy ra để đồng bộ ngay tại thời điểm bước nhảy vọt thứ hai, nó có lẽ sẽ chỉ cần đặt thời gian để :59 hoặc :00 và một lần nữa được ra khỏi đồng bộ cho một lúc.

Hãy xem xét một ví dụ thực tế. Giá trị 1341100800000 đại diện cho ngày 1 tháng 7 năm 2012 chính xác vào nửa đêm UTC. (Bạn có thể kiểm tra nó trên this web site, hoặc trong mã Java hoặc Joda của bạn để xác minh.) Nếu chúng tôi chia cho 86400000, chúng tôi sẽ nhận được chính xác 15522 ngày đã trôi qua kể từ 1/1/1970 UTC.

Giá trị này là bao gồm trong số 35 giây nhảy vọt, bao gồm giây đã xảy ra chỉ một giây trước khi kết thúc vào ngày 30 tháng 6 năm 2012. Giống như giây nhảy vọt không bao giờ xảy ra chút nào.

Vì vậy, hầu hết thời gian, bạn không cần phải lo lắng về giây nhảy vọt. Giả vờ họ không tồn tại. Hãy để hệ điều hành của bạn xử lý chúng theo bất kỳ cách nào nó muốn.

Nếu bạn yêu cầu phép đo thời gian cực chính xác, có lẽ trong ngữ cảnh khoa học, thì bạn không nên sử dụng đồng hồ hệ thống của máy tính. Bên cạnh thực tế là bước nhảy vọt thứ hai có thể được tổ chức, kéo dài, hoặc bỏ qua, nó chỉ không được thiết kế để được rằng chính xác của một bộ đếm thời gian. Thay vào đó, bạn có lẽ nên làm việc với một số phần cứng chấm công rất chuyên dụng, chẳng hạn như phần cứng được cung cấp bởi this vendor.

Cập nhật: Nơi bạn có thể cần giải quyết giây nhảy là nếu bạn ghi nhanh sự kiện (nhiều sự kiện mỗi giây) và nếu hệ điều hành của bạn có hành vi được mô tả trong # 3 ở trên. Trong trường hợp đó, đề xuất của tôi sẽ không sắp xếp theo dấu thời gian, mà thay vào đó, hãy cân nhắc việc giữ một số thứ tự tăng dần đơn điệu riêng của bạn và sắp xếp theo thứ tự đó.

Ví dụ: bạn có thể đã có ID số nguyên gia tăng tự động trong cơ sở dữ liệu của mình. Bạn vẫn có thể lọc theo dấu thời gian trong mệnh đề where để nhận dữ liệu cho một ngày cụ thể nhưng sau đó bạn sẽ đặt hàng theo ID để các sự kiện trong chuỗi ngay cả khi dấu thời gian không.

Để có các đề xuất khác, hãy xem Teo's answer.

+0

Điều gì sẽ xảy ra nếu bạn muốn đồng bộ hóa trên các lục địa bạn đang xử lý các dấu thời gian của Unix như được lấy từ các vị trí khác nhau? Nếu thứ tự dấu thời gian là quan trọng đối với bất kỳ lý do gì tôi nghĩ bạn không thể bỏ qua nó. – Sandman

+0

@Teo - Dấu thời gian Unix * luôn * trong UTC. Khi giây nhảy * làm * xảy ra, chúng xảy ra tất cả cùng thời gian UTC chính xác trên toàn thế giới. Vì vậy, nếu bạn đang kinh doanh Unix timestamps (hoặc bất kỳ hương vị khác của UTC hoặc GMT), thì vị trí là không liên quan. –

+1

Có nhưng nếu bạn cần đồng bộ hóa giữa nhiều vị trí này thì sao? Một vị trí có thể gửi dấu thời gian cho x mili giây để chèn vào cơ sở dữ liệu và dấu thời gian khác gửi x + 500. Tuy nhiên, nếu bạn đang ở trong bước nhảy vọt thứ hai đó có thể không phải là x + 500 xảy ra trước khi x? Điều này được mô tả ở đây: http://en.wikipedia.org/wiki/Unix_time#Encoding_time_as_a_number – Sandman

Các vấn đề liên quan