Văn hóa dân gian của lập trình viên và kỹ sư (phần 1)

Văn hóa dân gian của lập trình viên và kỹ sư (phần 1)

Đây là tuyển tập các câu chuyện trên Internet về việc đôi khi các lỗi có những biểu hiện hoàn toàn khó tin. Có lẽ bạn cũng có điều gì đó muốn nói.

Xe bị dị ứng với kem vani

Câu chuyện dành cho những kỹ sư hiểu rằng điều hiển nhiên không phải lúc nào cũng là câu trả lời và rằng dù sự thật có khó tin đến đâu thì chúng vẫn là sự thật. Bộ phận Pontiac của General Motors Corporation đã nhận được đơn khiếu nại:

Đây là lần thứ hai tôi viết thư cho bạn, và tôi không trách bạn đã không trả lời, vì nghe có vẻ điên rồ. Gia đình chúng tôi có truyền thống ăn kem mỗi tối sau bữa tối. Các loại kem mỗi lần thay đổi, sau bữa tối, cả nhà chọn mua loại kem nào, sau đó tôi đi đến cửa hàng. Gần đây tôi đã mua một chiếc Pontiac mới và kể từ đó việc đi mua kem của tôi đã trở thành một vấn đề. Bạn thấy đấy, mỗi lần tôi mua kem vani và từ cửa hàng về, xe không nổ máy. Nếu tôi mang theo bất kỳ loại kem nào khác, xe sẽ khởi động mà không gặp vấn đề gì. Tôi muốn hỏi một câu hỏi nghiêm túc, cho dù nó nghe có vẻ ngu ngốc đến mức nào: “Điều gì ở chiếc Pontiac khiến nó không khởi động khi tôi mang theo kem vani nhưng lại dễ dàng khởi động khi tôi mang đến một hương vị kem khác?”

Như bạn có thể tưởng tượng, vị chủ tịch bộ phận tỏ ra nghi ngờ về bức thư. Tuy nhiên, để đề phòng, tôi đã cử một kỹ sư đến kiểm tra. Anh rất ngạc nhiên khi gặp một người đàn ông giàu có, học thức tốt sống ở một khu vực xinh đẹp. Họ đồng ý gặp nhau ngay sau bữa tối để hai người có thể đến cửa hàng ăn kem. Tối hôm đó là mùi vani, và khi họ quay lại xe thì xe không nổ máy.

Người kỹ sư đến thêm ba buổi tối nữa. Lần đầu tiên kem là sô cô la. Chiếc xe khởi động. Lần thứ hai có kem dâu. Chiếc xe khởi động. Vào buổi tối thứ ba, anh ấy yêu cầu uống vani. Chiếc xe không khởi động.

Lý luận một cách hợp lý, người kỹ sư không chịu tin rằng chiếc xe bị dị ứng với kem vani. Vì vậy, tôi đã đồng ý với chủ xe rằng anh ta sẽ tiếp tục đến thăm cho đến khi tìm ra giải pháp cho vấn đề. Và trên đường đi, anh bắt đầu ghi chép: anh ghi lại tất cả thông tin, thời gian trong ngày, loại xăng, thời gian đến và về từ cửa hàng, v.v.

Người kỹ sư sớm nhận ra rằng chủ xe dành ít thời gian hơn để mua kem vani. Nguyên nhân là do cách sắp xếp hàng hóa trong cửa hàng. Kem vani là loại phổ biến nhất và được bảo quản trong tủ đông riêng phía trước cửa hàng để dễ tìm hơn. Và tất cả các loại khác đều ở phía sau cửa hàng, và phải mất nhiều thời gian hơn để tìm được loại phù hợp và thanh toán.

Bây giờ câu hỏi dành cho người kỹ sư: tại sao ô tô không nổ máy nếu thời gian trôi qua ít hơn kể từ thời điểm tắt động cơ? Vì vấn đề nằm ở thời gian chứ không phải kem vani nên người kỹ sư nhanh chóng tìm ra câu trả lời: đó là do khóa gas. Nó xảy ra vào mỗi buổi tối, nhưng khi chủ xe dành nhiều thời gian hơn để tìm kem, động cơ đã đủ nguội và khởi động dễ dàng. Và khi người đàn ông mua kem vani, động cơ vẫn còn quá nóng và khóa ga chưa kịp mở.

Bài học: Ngay cả những vấn đề hoàn toàn điên rồ đôi khi cũng có thật.

crash Bandicoot

Thật đau đớn khi trải nghiệm điều này. Là một lập trình viên, bạn quen với việc đổ lỗi cho mã của mình thứ nhất, thứ hai, thứ ba... và đâu đó ở vị trí thứ mười nghìn, bạn đổ lỗi cho trình biên dịch. Và xa hơn nữa trong danh sách bạn đã đổ lỗi cho thiết bị.

Đây là câu chuyện của tôi về lỗi phần cứng.

Đối với game Crash Bandicoot mình viết code để tải và lưu vào thẻ nhớ. Đối với một nhà phát triển trò chơi tự mãn như vậy, nó giống như một cuộc dạo chơi trong công viên: Tôi nghĩ công việc sẽ mất vài ngày. Tuy nhiên, cuối cùng tôi đã gỡ lỗi mã trong sáu tuần. Trong quá trình thực hiện, tôi đã giải quyết được các vấn đề khác, nhưng cứ sau vài ngày tôi lại quay lại mã này trong vài giờ. Thật là đau đớn.

Triệu chứng trông như thế này: khi bạn lưu quá trình chơi hiện tại của trò chơi và truy cập vào thẻ nhớ, mọi thứ hầu như luôn ổn... Nhưng đôi khi thao tác đọc hoặc ghi bị hết thời gian chờ mà không có lý do rõ ràng. Ghi âm ngắn thường làm hỏng thẻ nhớ. Khi người chơi cố gắng cứu, anh ta không những không cứu được mà còn phá hủy bản đồ. Tệ thật.

Sau một thời gian, nhà sản xuất của chúng tôi tại Sony, Connie Bus, bắt đầu lo lắng. Chúng tôi không thể phát hành trò chơi với lỗi này và sáu tuần sau, tôi không hiểu nguyên nhân gây ra sự cố. Thông qua Connie, chúng tôi đã liên hệ với các nhà phát triển PS1 khác: có ai gặp phải điều gì tương tự không? KHÔNG. Không ai gặp vấn đề với thẻ nhớ.

Khi bạn không có ý tưởng nào để gỡ lỗi, cách tiếp cận duy nhất còn lại là “phân chia và chinh phục”: xóa ngày càng nhiều mã khỏi chương trình bị lỗi cho đến khi còn lại một đoạn tương đối nhỏ vẫn gây ra sự cố. Tức là bạn cắt bỏ từng phần chương trình cho đến khi phần còn lại chứa lỗi.

Nhưng vấn đề là rất khó để cắt bớt các phần ra khỏi trò chơi điện tử. Làm cách nào để chạy nó nếu bạn loại bỏ mã mô phỏng trọng lực? Hoặc vẽ nhân vật?

Vì vậy, chúng ta phải thay thế toàn bộ mô-đun bằng các sơ khai giả vờ làm điều gì đó hữu ích nhưng thực tế lại làm một việc rất đơn giản và không thể chứa lỗi. Chúng tôi phải viết những chiếc nạng như vậy để trò chơi ít nhất có thể hoạt động. Đây là một quá trình chậm chạp và đau đớn.

Nói tóm lại, tôi đã làm được. Tôi đã loại bỏ ngày càng nhiều đoạn mã cho đến khi chỉ còn lại đoạn mã ban đầu để cấu hình hệ thống để chạy trò chơi, khởi tạo phần cứng kết xuất, v.v. Tất nhiên, ở giai đoạn này tôi không thể tạo menu lưu và tải vì tôi sẽ phải tạo một đoạn sơ khai cho tất cả mã đồ họa. Nhưng tôi có thể giả vờ là người dùng sử dụng màn hình lưu và tải (ẩn) và yêu cầu lưu rồi ghi vào thẻ nhớ.

Điều này để lại cho tôi một đoạn mã nhỏ vẫn gặp sự cố trên - nhưng nó vẫn xảy ra ngẫu nhiên! Hầu hết mọi thứ đều hoạt động tốt, nhưng đôi khi vẫn có trục trặc. Tôi đã xóa gần hết mã trò chơi nhưng lỗi vẫn còn tồn tại. Điều này thật khó hiểu: đoạn mã còn lại thực sự không làm gì cả.

Vào một lúc nào đó, có lẽ vào khoảng ba giờ sáng, tôi chợt nảy ra một ý nghĩ. Hoạt động đọc và ghi (đầu vào/đầu ra) đòi hỏi thời gian thực hiện chính xác. Khi bạn làm việc với ổ cứng, thẻ nhớ hoặc mô-đun Bluetooth, mã cấp thấp chịu trách nhiệm đọc và ghi sẽ thực hiện việc đó theo xung đồng hồ.

Với sự trợ giúp của đồng hồ, một thiết bị không được kết nối trực tiếp với bộ xử lý sẽ được đồng bộ hóa với mã thực thi trên bộ xử lý. Đồng hồ xác định tốc độ baud—tốc độ truyền dữ liệu. Nếu có sự nhầm lẫn về thời gian thì phần cứng hoặc phần mềm hoặc cả hai cũng bị nhầm lẫn. Và điều này rất tệ, vì dữ liệu có thể bị hỏng.

Điều gì sẽ xảy ra nếu có điều gì đó trong mã của chúng ta gây nhầm lẫn về thời gian? Tôi đã kiểm tra mọi thứ liên quan đến điều này trong mã chương trình thử nghiệm và nhận thấy rằng chúng tôi đặt bộ hẹn giờ có thể lập trình trong PS1 thành 1 kHz (1000 tích tắc mỗi giây). Con số này khá nhiều; theo mặc định, khi bảng điều khiển khởi động, nó chạy ở tần số 100 Hz. Và hầu hết các trò chơi đều sử dụng tần số này.

Andy, nhà phát triển trò chơi, đặt bộ hẹn giờ ở mức 1 kHz để các chuyển động được tính toán chính xác hơn. Andy có xu hướng đi quá đà, và nếu chúng ta mô phỏng trọng lực, chúng ta sẽ làm điều đó một cách chính xác nhất có thể!

Nhưng điều gì sẽ xảy ra nếu việc tăng tốc bộ hẹn giờ bằng cách nào đó ảnh hưởng đến thời gian chung của chương trình và do đó ảnh hưởng đến đồng hồ điều chỉnh tốc độ truyền cho thẻ nhớ?

Tôi đã nhận xét mã hẹn giờ. Lỗi đã không xảy ra nữa. Nhưng điều này không có nghĩa là chúng tôi đã sửa nó vì lỗi xảy ra ngẫu nhiên. Nếu tôi chỉ may mắn thì sao?

Vài ngày sau tôi lại thử nghiệm chương trình thử nghiệm. Lỗi không tái diễn. Tôi quay lại cơ sở mã trò chơi đầy đủ và sửa đổi mã lưu và tải để bộ hẹn giờ có thể lập trình đặt lại về giá trị ban đầu (100Hz) trước khi truy cập vào thẻ nhớ, sau đó đặt lại về 1kHz. Không còn tai nạn nào nữa.

Nhưng tại sao điều này lại xảy ra?

Tôi quay trở lại chương trình thử nghiệm một lần nữa. Tôi đã cố gắng tìm một số kiểu xảy ra lỗi với bộ định thời 1 kHz. Cuối cùng, tôi nhận thấy lỗi xảy ra khi ai đó chơi bằng bộ điều khiển PS1. Vì tôi hiếm khi tự mình làm điều này - tại sao tôi lại cần bộ điều khiển khi kiểm tra mã lưu và tải? - Tôi thậm chí còn không nhận thấy sự phụ thuộc này. Nhưng một ngày nọ, một trong những nghệ sĩ của chúng tôi đang đợi tôi thử nghiệm xong - có lẽ lúc đó tôi đang chửi rủa - và lo lắng xoay chiếc điều khiển trên tay. Một lỗi đã xảy ra. “Đợi đã, cái gì cơ?!” Được rồi, làm lại lần nữa đi!”

Khi nhận ra hai sự kiện này có mối liên hệ với nhau, tôi có thể dễ dàng tái hiện lỗi: Tôi bắt đầu ghi vào thẻ nhớ, di chuyển bộ điều khiển và làm hỏng thẻ nhớ. Đối với tôi nó trông giống như một lỗi phần cứng.

Tôi đến gặp Connie và kể cho cô ấy nghe về khám phá của mình. Cô chuyển thông tin cho một trong những kỹ sư đã thiết kế PS1. “Không thể,” anh ấy trả lời, “Đó không thể là vấn đề về phần cứng.” Tôi nhờ Connie sắp xếp một cuộc trò chuyện cho chúng tôi.

Người kỹ sư đã gọi cho tôi và chúng tôi tranh luận bằng tiếng Anh không chuẩn của anh ấy và tiếng Nhật (cực kỳ) không tốt của tôi. Cuối cùng tôi nói: “Hãy để tôi gửi chương trình kiểm tra 30 dòng của mình trong đó việc di chuyển bộ điều khiển sẽ gây ra lỗi”. Anh ấy đồng ý. Nói rằng đó là một sự lãng phí thời gian và rằng anh ấy đang cực kỳ bận rộn với một dự án mới, nhưng sẽ nhượng bộ vì chúng tôi là một nhà phát triển rất quan trọng đối với Sony. Tôi đã dọn dẹp chương trình thử nghiệm của mình và gửi nó cho anh ấy.

Tối hôm sau (chúng tôi ở Los Angeles và anh ấy ở Tokyo), anh ấy gọi cho tôi và ngượng ngùng xin lỗi. Đó là một vấn đề phần cứng.

Tôi không biết chính xác lỗi là gì, nhưng theo những gì tôi nghe được ở trụ sở Sony, nếu bạn đặt bộ hẹn giờ ở giá trị đủ cao, nó sẽ ảnh hưởng đến các thành phần trên bo mạch chủ ở gần tinh thể hẹn giờ. Một trong số đó là bộ điều khiển tốc độ truyền cho thẻ nhớ, bộ điều khiển này cũng đặt tốc độ truyền cho bộ điều khiển. Tôi không phải là kỹ sư nên có thể tôi đã làm hỏng điều gì đó.

Nhưng điểm mấu chốt là đã có sự can thiệp giữa các thành phần trên bo mạch chủ. Và khi truyền dữ liệu đồng thời qua cổng điều khiển và cổng thẻ nhớ với bộ đếm thời gian chạy ở tần số 1 kHz thì bị mất bit, mất dữ liệu và thẻ bị hỏng.

Bò xấu

Vào những năm 1980, người cố vấn của tôi, Sergei đã viết phần mềm cho SM-1800, một bản sao PDP-11 của Liên Xô. Chiếc máy vi tính này vừa được lắp đặt tại một nhà ga gần Sverdlovsk, một trung tâm giao thông quan trọng ở Liên Xô. Hệ thống mới được thiết kế để định tuyến các toa xe và vận chuyển hàng hóa. Nhưng nó chứa một lỗi khó chịu dẫn đến sự cố và sự cố ngẫu nhiên. Ngã luôn xảy ra khi ai đó về nhà vào buổi tối. Nhưng dù đã điều tra kỹ lưỡng vào ngày hôm sau, máy tính vẫn hoạt động bình thường trong tất cả các bài kiểm tra thủ công và tự động. Điều này thường chỉ ra tình trạng cuộc đua hoặc một số lỗi cạnh tranh khác xảy ra trong một số điều kiện nhất định. Mệt mỏi với những cuộc gọi vào đêm khuya, Sergei quyết định đi sâu vào vấn đề và trước hết, tìm hiểu xem điều kiện nào ở bãi tập kết đã dẫn đến sự cố máy tính.

Đầu tiên, ông thu thập số liệu thống kê về tất cả những cú ngã không giải thích được và tạo ra một biểu đồ theo ngày và giờ. Mô hình đã rõ ràng. Sau khi quan sát thêm vài ngày, Sergei nhận ra rằng anh có thể dễ dàng dự đoán thời điểm xảy ra lỗi hệ thống trong tương lai.

Anh sớm biết rằng sự gián đoạn chỉ xảy ra khi nhà ga đang phân loại các chuyến tàu chở gia súc từ miền bắc Ukraine và miền tây nước Nga hướng đến một lò mổ gần đó. Bản thân điều này thật kỳ lạ, bởi vì lò mổ được cung cấp bởi các trang trại nằm gần hơn nhiều ở Kazakhstan.

Nhà máy điện hạt nhân Chernobyl phát nổ vào năm 1986 và bụi phóng xạ khiến các khu vực xung quanh không thể ở được. Các khu vực rộng lớn ở miền bắc Ukraine, Belarus và miền tây nước Nga đã bị ô nhiễm. Nghi ngờ mức độ phóng xạ cao trong các toa xe đang đến, Sergei đã phát triển một phương pháp để kiểm tra lý thuyết này. Người dân bị cấm sử dụng liều kế, vì vậy Sergei đã đăng ký với một số quân nhân tại nhà ga. Sau vài ly vodka, anh ta đã thuyết phục được một người lính đo mức độ phóng xạ ở một trong những toa tàu khả nghi. Hóa ra mức này cao hơn nhiều lần so với giá trị bình thường.

Gia súc không chỉ thải ra nhiều phóng xạ mà mức độ của nó còn cao đến mức dẫn đến tình trạng mất ngẫu nhiên các bit trong bộ nhớ của SM-1800, đặt trong một tòa nhà cạnh nhà ga.

Ở Liên Xô xảy ra tình trạng thiếu lương thực và chính quyền đã quyết định trộn thịt Chernobyl với thịt từ các vùng khác của đất nước. Điều này giúp có thể giảm mức độ phóng xạ tổng thể mà không làm mất đi nguồn tài nguyên quý giá. Biết được điều này, Sergei lập tức điền giấy tờ để di cư. Và những sự cố máy tính tự dừng lại khi mức độ phóng xạ giảm dần theo thời gian.

Thông qua các đường ống

Ngày xửa ngày xưa, Movietech Solutions đã tạo ra phần mềm dành cho rạp chiếu phim, được thiết kế cho mục đích kế toán, bán vé và quản lý chung. Phiên bản DOS của ứng dụng hàng đầu này khá phổ biến trong các chuỗi rạp chiếu phim vừa và nhỏ ở Bắc Mỹ. Vì vậy, không có gì đáng ngạc nhiên khi một phiên bản Windows 95 được công bố, được tích hợp với màn hình cảm ứng và ki-ốt tự phục vụ mới nhất cũng như được trang bị đủ loại công cụ báo cáo, nó cũng nhanh chóng trở nên phổ biến. Thông thường, bản cập nhật diễn ra mà không gặp vấn đề gì. Nhân viên CNTT địa phương đã cài đặt thiết bị mới, di chuyển dữ liệu và hoạt động kinh doanh vẫn tiếp tục. Ngoại trừ khi nó không kéo dài. Khi điều này xảy ra, công ty sẽ phái James, biệt danh là "Người dọn dẹp".

Mặc dù biệt danh gợi ý một loại bất chính, nhưng trình dọn dẹp chỉ là sự kết hợp giữa người hướng dẫn, người cài đặt và người làm đủ mọi nghề. James sẽ dành vài ngày ở cơ sở của khách hàng để lắp ráp tất cả các thành phần lại với nhau, sau đó dành vài ngày nữa để dạy nhân viên cách sử dụng hệ thống mới, giải quyết mọi vấn đề phần cứng phát sinh và về cơ bản giúp phần mềm vượt qua giai đoạn sơ khai.

Vì vậy, không có gì đáng ngạc nhiên khi trong khoảng thời gian bận rộn này, James đến văn phòng vào buổi sáng và trước khi kịp đến bàn làm việc, anh đã được người quản lý chào đón, trong người chứa đầy caffeine hơn bình thường.

“Tôi e rằng bạn cần phải đến Annapolis, Nova Scotia càng sớm càng tốt.” Toàn bộ hệ thống của họ đã ngừng hoạt động và sau một đêm làm việc với các kỹ sư của họ, chúng tôi không thể hiểu được chuyện gì đã xảy ra. Có vẻ như mạng đã bị lỗi trên máy chủ. Nhưng chỉ sau khi hệ thống đã chạy được vài phút.

— Họ không quay lại hệ thống cũ? - James trả lời hoàn toàn nghiêm túc, mặc dù trong thâm tâm anh vẫn mở to mắt ngạc nhiên.

— Chính xác: chuyên gia CNTT của họ “đã thay đổi mức độ ưu tiên” và quyết định rời đi với máy chủ cũ của họ. James, họ đã cài đặt hệ thống tại sáu địa điểm và chỉ trả tiền cho dịch vụ hỗ trợ cao cấp, và hoạt động kinh doanh của họ hiện vẫn hoạt động như những năm 1950.

James hơi đứng thẳng lên.

- Đó là chuyện khác. Được rồi, hãy bắt đầu.

Khi đến Annapolis, điều đầu tiên anh làm là tìm ra rạp chiếu phim đầu tiên của khách hàng có vấn đề. Trên bản đồ chụp tại sân bay, mọi thứ đều ổn, nhưng khu vực xung quanh địa chỉ mong muốn có vẻ đáng ngờ. Không phải khu ổ chuột, nhưng gợi nhớ đến phim noir. Khi James đậu xe ở lề đường trung tâm thành phố, một cô gái điếm tiến đến gần anh. Với quy mô của Annapolis, rất có thể đây là nơi duy nhất trong toàn thành phố. Sự xuất hiện của cô ngay lập tức khiến người ta nhớ đến nhân vật nổi tiếng bán dâm lấy tiền trên màn ảnh rộng. Không, không phải về Julia Roberts, mà là về Jon Voight [ám chỉ đến bộ phim "Cao bồi nửa đêm" - khoảng. làn đường].

Sau khi tiễn cô gái điếm lên đường, James đi xem phim. Khu vực xung quanh đã tốt hơn nhưng vẫn mang lại cảm giác bị xuống cấp. Không phải James quá lo lắng. Anh ấy đã từng đến những nơi khốn khổ trước đây. Và đây là Canada, nơi ngay cả những kẻ cướp cũng đủ lịch sự để nói “cảm ơn” sau khi lấy ví của bạn.

Lối vào rạp chiếu phim nằm trong một con hẻm ẩm ướt. James bước tới cửa và gõ. Chẳng mấy chốc nó kêu cọt kẹt và mở ra một chút.

-Anh là người dọn dẹp à? - một giọng nói khàn khàn phát ra từ bên trong.

- Vâng, là tôi... Tôi đến để sửa chữa mọi thứ.

James bước vào sảnh rạp chiếu phim. Dường như không còn lựa chọn nào khác, nhân viên bắt đầu phát vé giấy cho du khách. Điều này làm cho việc báo cáo tài chính trở nên khó khăn chứ đừng nói đến việc có thêm nhiều chi tiết thú vị. Nhưng các nhân viên chào đón James một cách nhẹ nhõm và ngay lập tức đưa anh vào phòng máy chủ.

Thoạt nhìn, mọi thứ đều ổn. James đăng nhập vào máy chủ và kiểm tra những nơi đáng ngờ thông thường. Không có gì. Tuy nhiên, để hết sức thận trọng, James đã tắt máy chủ, thay card mạng và khôi phục hệ thống. Cô ấy ngay lập tức bắt tay vào làm việc đầy đủ. Nhân viên lại bắt đầu bán vé.

James gọi cho Mark và thông báo tình hình cho anh ấy. Không khó để tưởng tượng rằng James có thể muốn ở lại xem có điều gì bất ngờ xảy ra không. Anh ta đi xuống cầu thang và bắt đầu hỏi các nhân viên chuyện gì đã xảy ra. Rõ ràng là hệ thống đã ngừng hoạt động. Họ tắt đi bật lại, mọi thứ đều hoạt động. Nhưng sau 10 phút hệ thống đã ngừng hoạt động.

Đúng lúc này một chuyện tương tự đã xảy ra. Đột nhiên, hệ thống bán vé bắt đầu có lỗi. Các nhân viên thở dài và chộp lấy những tấm vé giấy, James vội vã đi đến phòng máy chủ. Mọi thứ đều ổn với máy chủ.

Sau đó một nhân viên bước vào.

- Hệ thống đã hoạt động trở lại.

James bối rối vì anh ấy chưa làm gì cả. Chính xác hơn là không có gì có thể khiến hệ thống hoạt động được. Anh đăng xuất, nhấc điện thoại lên và gọi đến đường dây hỗ trợ của công ty. Ngay sau đó, nhân viên đó bước vào phòng máy chủ.

- Hệ thống đang xuống.

James liếc nhìn máy chủ. Một mô hình thú vị và quen thuộc gồm các hình dạng nhiều màu sắc nhảy múa trên màn hình - những đường ống quằn quại và đan xen một cách hỗn loạn. Tất cả chúng ta đều đã từng nhìn thấy trình bảo vệ màn hình này. Nó được thể hiện rất đẹp và có tính thôi miên theo đúng nghĩa đen.


James nhấn một nút và hình mẫu biến mất. Anh vội vã đến phòng vé và trên đường gặp một nhân viên đang quay lại với anh.

- Hệ thống đã hoạt động trở lại.

Nếu bạn có thể thực hiện động tác xoa mặt, đó chính xác là điều James đã làm. Bảo vệ màn hình. Nó sử dụng OpenGL. Và do đó, trong quá trình hoạt động, nó tiêu tốn toàn bộ tài nguyên của bộ xử lý máy chủ. Kết quả là mỗi cuộc gọi đến máy chủ đều kết thúc sau một khoảng thời gian chờ.

James quay trở lại phòng máy chủ, đăng nhập và thay thế trình bảo vệ màn hình bằng những đường ống tuyệt đẹp bằng một màn hình trống. Nghĩa là, thay vì một trình bảo vệ màn hình tiêu tốn 100% tài nguyên bộ xử lý, tôi đã cài đặt một trình bảo vệ màn hình khác không tiêu tốn tài nguyên. Sau đó tôi đợi 10 phút để kiểm tra dự đoán của mình.

Khi James đến rạp chiếu phim tiếp theo, anh đang băn khoăn không biết phải giải thích thế nào với người quản lý rằng anh vừa bay 800 km để tắt chế độ bảo vệ màn hình.

Sự cố trong một giai đoạn nhất định của mặt trăng

Câu chuyện có thật. Một ngày nọ, một lỗi phần mềm phát sinh phụ thuộc vào chu kỳ của mặt trăng. Có một quy trình nhỏ thường được sử dụng trong các chương trình khác nhau của MIT để tính toán gần đúng với pha thực sự của Mặt trăng. GLS đã xây dựng quy trình này thành một chương trình LISP, khi ghi một tệp, sẽ xuất ra một dòng có dấu thời gian dài gần 80 ký tự. Rất hiếm khi dòng đầu tiên của tin nhắn quá dài và dẫn đến dòng tiếp theo. Và sau đó khi chương trình đọc tập tin này, nó sẽ bị nguyền rủa. Độ dài của dòng đầu tiên phụ thuộc vào ngày và giờ chính xác, cũng như độ dài của thông số pha tại thời điểm dấu thời gian được in. Đó là, lỗi thực sự phụ thuộc vào giai đoạn của mặt trăng!

Ấn bản giấy đầu tiên Tệp biệt ngữ (Steele-1983) có một ví dụ về một dòng như vậy dẫn đến lỗi được mô tả, nhưng người sắp chữ đã “sửa” nó. Điều này kể từ đó được mô tả là "lỗi giai đoạn mặt trăng".

Tuy nhiên, hãy cẩn thận với các giả định. Vài năm trước, các kỹ sư từ CERN (Trung tâm Nghiên cứu Hạt nhân Châu Âu) đã gặp phải sai sót trong các thí nghiệm được thực hiện tại Máy Va chạm Electron-Positron Lớn. Vì máy tính chủ động xử lý lượng dữ liệu khổng lồ do thiết bị này tạo ra trước khi hiển thị kết quả cho các nhà khoa học nên nhiều người suy đoán rằng phần mềm này bằng cách nào đó nhạy cảm với pha của mặt trăng. Một số kỹ sư tuyệt vọng đã tìm ra được sự thật. Lỗi phát sinh do một sự thay đổi nhỏ về hình dạng của vòng tròn dài 27 km do sự biến dạng của Trái đất trong quá trình Mặt trăng đi qua! Câu chuyện này đã đi vào văn hóa vật lý dân gian với cái tên “Sự trả thù của Newton đối với Vật lý hạt” và là một ví dụ về mối liên hệ giữa các định luật vật lý đơn giản và lâu đời nhất với các khái niệm khoa học tiên tiến nhất.

Xả bồn cầu khiến tàu dừng lại

Lỗi phần cứng lớn nhất mà tôi từng nghe là trên tàu cao tốc ở Pháp. Lỗi này đã khiến tàu phải phanh khẩn cấp nhưng chỉ khi có hành khách trên tàu. Trong mỗi trường hợp như vậy, đoàn tàu đều được ngừng hoạt động, kiểm tra nhưng không tìm thấy gì. Sau đó, anh ta được đưa trở lại hàng và ngay lập tức dừng lại.

Trong một lần kiểm tra, một kỹ sư đi trên tàu đã đi vệ sinh. Anh ấy nhanh chóng bị cuốn đi, BÙM! Dừng khẩn cấp.

Người kỹ sư liên lạc với tài xế và hỏi:

- Bạn đã làm gì ngay trước khi phanh xe?

- À, tôi xuống dốc chậm lại...

Điều này thật kỳ lạ, vì trong quá trình hoạt động bình thường, tàu giảm tốc độ hàng chục lần khi xuống dốc. Tàu tiếp tục di chuyển và ở lần xuống dốc tiếp theo, người lái tàu cảnh báo:

- Tôi sẽ đi chậm lại.

Không có chuyện gì xảy ra.

- Bạn đã làm gì trong lần phanh vừa qua? - người lái xe hỏi.

- À... tôi đang ở trong nhà vệ sinh...

- Vậy thì đi vệ sinh và làm những gì bạn đã làm khi chúng ta đi xuống lần nữa!

Người kỹ sư đi vào nhà vệ sinh, khi tài xế cảnh báo: “Tôi đi chậm lại”, anh ta xả nước. Tất nhiên, tàu dừng ngay lập tức.

Bây giờ họ có thể tái tạo vấn đề và cần tìm ra nguyên nhân.

Sau hai phút, họ nhận thấy cáp điều khiển từ xa phanh động cơ (tàu có một đầu máy ở mỗi đầu) bị ngắt khỏi thành tủ điện và nằm trên rơle điều khiển phích cắm điện từ của bồn cầu... Khi rơ le được bật, nó sẽ tạo ra nhiễu trong cáp phanh và việc bảo vệ hệ thống khỏi các sự cố chỉ đơn giản bao gồm phanh khẩn cấp.

Cánh cổng ghét FORTRAN

Một vài tháng trước, chúng tôi nhận thấy rằng các kết nối mạng trên đất liền [đây là ở Hawaii] đang trở nên rất chậm. Hiện tượng này có thể kéo dài khoảng 10-15 phút rồi đột ngột tái diễn. Sau một thời gian, đồng nghiệp của tôi phàn nàn với tôi rằng kết nối mạng trên đất liền nói chung không hoạt động. Anh ta có một số mã FORTRAN cần được sao chép vào một máy trên đất liền, nhưng không thể vì "mạng không trụ đủ lâu để quá trình tải lên FTP hoàn tất."

Có, hóa ra lỗi mạng đã xảy ra khi một đồng nghiệp cố gắng FTP một tệp có mã nguồn trong FORTRAN tới một máy trên đất liền. Chúng tôi đã cố gắng lưu trữ tệp: sau đó nó được sao chép trơn tru (nhưng máy mục tiêu không có trình giải nén nên vấn đề không được giải quyết). Cuối cùng, chúng tôi "chia" mã FORTRAN thành nhiều phần rất nhỏ và gửi từng phần một. Hầu hết các đoạn được sao chép mà không gặp vấn đề gì, nhưng một số đoạn không vượt qua được hoặc bị chuyển tiếp sau đó. nhiều những nỗ lực.

Khi kiểm tra các đoạn văn có vấn đề, chúng tôi phát hiện ra rằng chúng có điểm chung: chúng đều chứa các khối nhận xét bắt đầu và kết thúc bằng các dòng bao gồm chữ C viết hoa (như một đồng nghiệp thích nhận xét trong FORTRAN). Chúng tôi đã gửi email cho các chuyên gia mạng ở đại lục và yêu cầu trợ giúp. Tất nhiên, họ muốn xem các mẫu tệp không thể chuyển qua FTP của chúng tôi... nhưng thư của chúng tôi không đến được tay họ. Cuối cùng chúng tôi đã nghĩ ra một cách đơn giản diễn tảcác tập tin không thể chuyển giao trông như thế nào. Nó đã hoạt động :) [Tôi có dám thêm ví dụ về một trong những nhận xét FORTRAN có vấn đề vào đây không? Có lẽ không đáng!]

Cuối cùng chúng tôi đã tìm ra được nó. Một cổng mới gần đây đã được lắp đặt giữa khu vực khuôn viên trường của chúng tôi và mạng lưới đất liền. Nó gặp khó khăn rất lớn khi truyền các gói chứa các bit chữ hoa C lặp đi lặp lại! Chỉ một vài gói trong số này có thể chiếm hết tài nguyên cổng và ngăn hầu hết các gói khác đi qua. Chúng tôi đã khiếu nại với nhà sản xuất cổng... và họ trả lời: “Ồ, vâng, bạn đang gặp phải lỗi C lặp đi lặp lại! Chúng tôi đã biết về anh ấy rồi.” Cuối cùng, chúng tôi đã giải quyết được vấn đề bằng cách mua một cổng mới từ một nhà sản xuất khác (để bảo vệ nhà cung cấp trước đây, việc không thể chuyển các chương trình FORTRAN có thể là một lợi thế đối với một số người!).

Thời gian khó khăn

Vài năm trước, khi nghiên cứu tạo hệ thống ETL trong Perl để giảm chi phí cho các thử nghiệm lâm sàng giai đoạn 40, tôi cần xử lý khoảng 000 ngày tháng. Hai người trong số họ đã không vượt qua được bài kiểm tra. Điều này không làm tôi bận tâm lắm vì những ngày tháng này được lấy từ dữ liệu do khách hàng cung cấp, điều này thường gây ngạc nhiên. Nhưng khi kiểm tra dữ liệu gốc thì hóa ra những ngày này là ngày 1 tháng 2011 năm 1 và ngày 2007 tháng 30 năm XNUMX. Tôi tưởng lỗi nằm ở chương trình tôi vừa viết nhưng hóa ra nó đã XNUMX tuổi rồi. . Điều này nghe có vẻ bí ẩn đối với những người chưa quen với hệ sinh thái phần mềm. Vì quyết định kiếm tiền lâu dài của một công ty khác, khách hàng của tôi đã trả tiền cho tôi để sửa một lỗi mà một công ty vô tình đưa ra còn công ty kia là cố ý. Để bạn hiểu những gì tôi đang nói, tôi cần nói về công ty đã thêm tính năng nhưng cuối cùng lại trở thành một lỗi, cũng như một số sự kiện thú vị khác góp phần tạo ra lỗi bí ẩn mà tôi đã sửa.

Ngày xưa, máy tính Apple đôi khi tự động đặt lại ngày về ngày 1 tháng 1904 năm 1. Lý do rất đơn giản: nó sử dụng “đồng hồ hệ thống” chạy bằng pin để theo dõi ngày giờ. Điều gì đã xảy ra khi pin chết? Máy tính bắt đầu theo dõi ngày theo số giây kể từ khi bắt đầu một kỷ nguyên. Theo kỷ nguyên, chúng tôi muốn nói đến ngày ban đầu tham chiếu và đối với Macintosh, đó là ngày 1904 tháng XNUMX năm XNUMX. Và sau khi hết pin, ngày hiện tại được đặt lại về ngày đã chỉ định. Nhưng tại sao điều này lại xảy ra?

Trước đây, Apple sử dụng 32 bit để lưu trữ số giây kể từ ngày ban đầu. Một bit có thể lưu trữ một trong hai giá trị - 1 hoặc 0. Hai bit có thể lưu trữ một trong bốn giá trị: 00, 01, 10, 11. Ba bit - một giá trị trong số tám: 000, 001, 010, 011, 100 , 101, 110, 111, v.v. Và 32 có thể lưu trữ một trong 232 giá trị, tức là 4 giây. Đối với ngày của Apple, điều này tương đương với khoảng 294 năm, vì vậy các máy Mac cũ hơn không thể xử lý ngày sau năm 967. Và nếu pin hệ thống chết, ngày sẽ được đặt lại về 296 giây kể từ khi bắt đầu kỷ nguyên và bạn phải đặt ngày theo cách thủ công mỗi khi bật máy tính (hoặc cho đến khi bạn mua pin mới).

Tuy nhiên, quyết định của Apple lưu trữ ngày dưới dạng giây kể từ kỷ nguyên có nghĩa là chúng ta không thể xử lý ngày trước kỷ nguyên, điều này gây ra những hậu quả sâu rộng, như chúng ta sẽ thấy. Apple giới thiệu một tính năng, không phải một lỗi. Trong số những điều khác, điều này có nghĩa là hệ điều hành Macintosh miễn nhiễm với “lỗi thiên niên kỷ” (không thể nói về nhiều ứng dụng Mac có hệ thống ngày tháng riêng để tránh các hạn chế).

Hãy tiếp tục. Chúng tôi sử dụng Lotus 1-2-3, "ứng dụng sát thủ" của IBM đã giúp khởi động cuộc cách mạng PC, mặc dù máy tính Apple có VisiCalc, thứ đã tạo nên thành công cho máy tính cá nhân. Công bằng mà nói, nếu 1-2-3 không xuất hiện thì PC khó có thể cất cánh, và lịch sử máy tính cá nhân có thể đã phát triển rất khác. Lotus 1-2-3 coi năm 1900 là năm nhuận một cách không chính xác. Khi Microsoft phát hành bảng tính đầu tiên, Multiplan, hãng đã chiếm được một thị phần nhỏ trên thị trường. Và khi khởi động dự án Excel, họ quyết định không chỉ sao chép cách đặt tên hàng và cột từ Lotus 1-2-3 mà còn đảm bảo khả năng tương thích với lỗi bằng cách cố tình coi năm 1900 là năm nhuận. Vấn đề này vẫn tồn tại cho đến ngày nay. Nghĩa là, trong 1-2-3, đây là một lỗi, nhưng trong Excel, đó là một quyết định sáng suốt nhằm đảm bảo rằng tất cả người dùng 1-2-3 có thể nhập bảng của họ vào Excel mà không thay đổi dữ liệu, ngay cả khi dữ liệu đó không chính xác.

Nhưng có một vấn đề khác. Đầu tiên, Microsoft phát hành Excel cho Macintosh, không nhận dạng ngày trước ngày 1 tháng 1904 năm 1. Và trong Excel, ngày 1900 tháng XNUMX năm XNUMX được coi là sự khởi đầu của kỷ nguyên. Do đó, các nhà phát triển đã thực hiện một sự thay đổi để chương trình của họ nhận dạng loại thời đại và lưu trữ dữ liệu bên trong nó phù hợp với thời đại mong muốn. Microsoft thậm chí còn viết một bài giải thích về điều này. Và quyết định này đã dẫn đến lỗi của tôi.

Hệ thống ETL của tôi đã nhận được bảng tính Excel từ khách hàng được tạo trên Windows nhưng cũng có thể được tạo trên máy Mac. Do đó, thời điểm bắt đầu kỷ nguyên trong bảng có thể là ngày 1 tháng 1900 năm 1 hoặc ngày 1904 tháng XNUMX năm XNUMX. Làm thế nào để tìm hiểu? Định dạng tệp Excel hiển thị thông tin cần thiết, nhưng trình phân tích cú pháp tôi đã sử dụng không hiển thị thông tin đó (hiện tại đã hiển thị) và giả định rằng bạn biết kỷ nguyên của một bảng cụ thể. Lẽ ra tôi có thể dành nhiều thời gian hơn để tìm hiểu định dạng nhị phân của Excel và gửi bản vá cho tác giả trình phân tích cú pháp, nhưng tôi còn nhiều việc phải làm cho khách hàng, vì vậy tôi đã nhanh chóng viết một phương pháp phỏng đoán để xác định kỷ nguyên. Cô ấy rất đơn giản.

Trong Excel, ngày 5 tháng 1998 năm 07 có thể được biểu diễn dưới dạng "05-98-5" (hệ thống vô dụng của Mỹ), "98 tháng 5 năm 1998", "5 tháng 98 năm 8601", "35981-Jul-1900" hoặc một số định dạng khác, một định dạng vô dụng khác (trớ trêu thay, một trong những định dạng mà phiên bản Excel của tôi không cung cấp lại là ISO 34519). Tuy nhiên, trong bảng, ngày chưa được định dạng được lưu dưới dạng "1904" cho kỷ nguyên-4 hoặc "1904" cho kỷ nguyên-XNUMX (các con số biểu thị số ngày kể từ kỷ nguyên đó). Tôi chỉ cần sử dụng một trình phân tích cú pháp đơn giản để trích xuất năm từ ngày được định dạng, sau đó sử dụng trình phân tích cú pháp Excel để trích xuất năm từ ngày chưa được định dạng. Nếu cả hai giá trị chênh lệch XNUMX năm thì tôi biết rằng tôi đang sử dụng hệ thống có kỷ nguyên-XNUMX.

Tại sao tôi không sử dụng ngày được định dạng? Bởi vì ngày 5 tháng 1998 năm 98 có thể được định dạng là "Tháng XNUMX, XNUMX" với ngày trong tháng bị mất. Chúng tôi đã nhận được các bảng từ rất nhiều công ty đã tạo ra chúng theo nhiều cách khác nhau đến mức chúng tôi (trong trường hợp này là tôi) phải tìm ra ngày tháng. Ngoài ra, nếu Excel làm đúng thì chúng ta cũng nên làm như vậy!

Cùng lúc đó, tôi gặp phải 39082. Hãy để tôi nhắc bạn rằng Lotus 1-2-3 coi năm 1900 là năm nhuận và điều này đã được lặp lại một cách trung thực trong Excel. Và vì điều này đã thêm một ngày vào năm 1900 nên nhiều hàm tính ngày có thể sai cho chính ngày đó. Nghĩa là, 39082 có thể là ngày 1 tháng 2011 năm 31 (trên máy Mac) hoặc ngày 2006 tháng 2011 năm 1900 (trên Windows). Nếu “trình phân tích cú pháp năm” của tôi trích xuất năm 2006 từ giá trị được định dạng thì mọi thứ đều ổn. Nhưng vì trình phân tích cú pháp Excel không biết kỷ nguyên nào đang được sử dụng nên nó mặc định là kỷ nguyên-5, trả về năm XNUMX. Ứng dụng của tôi nhận thấy sự khác biệt là XNUMX năm, coi đó là lỗi, ghi lại và trả về giá trị chưa được định dạng.

Để giải quyết vấn đề này, tôi đã viết cái này (mã giả):

diff = formatted_year - parsed_year
if 0 == diff
    assume 1900 date system
if 4 == diff
    assume 1904 date system
if 5 == diff and month is December and day is 31
    assume 1904 date system

Và sau đó tất cả 40 ngày đều được phân tích cú pháp chính xác.

Ở giữa công việc in ấn lớn

Vào đầu những năm 1980, cha tôi làm việc tại Công nghệ Lưu trữ, một bộ phận hiện đã giải thể chuyên tạo ra các ổ băng và hệ thống khí nén để nạp băng tốc độ cao.

Họ đã thiết kế lại các ổ đĩa để có thể có một ổ đĩa “A” trung tâm được kết nối với bảy ổ đĩa “B” và hệ điều hành nhỏ trong RAM điều khiển ổ đĩa “A” có thể ủy quyền các hoạt động đọc và ghi cho tất cả các ổ đĩa “B”.

Mỗi lần ổ đĩa “A” được khởi động, cần phải đưa một đĩa mềm vào ổ đĩa ngoại vi được kết nối với “A” để tải hệ điều hành vào bộ nhớ của nó. Nó cực kỳ thô sơ: sức mạnh tính toán được cung cấp bởi bộ vi điều khiển 8 bit.

Đối tượng mục tiêu của thiết bị như vậy là các công ty có kho dữ liệu rất lớn - ngân hàng, chuỗi bán lẻ, v.v. - cần in nhiều nhãn địa chỉ hoặc bảng sao kê ngân hàng.

Một khách hàng đã gặp vấn đề. Khi đang thực hiện lệnh in, một ổ đĩa “A” có thể ngừng hoạt động, khiến toàn bộ lệnh in bị đình trệ. Để khôi phục hoạt động của ổ đĩa, nhân viên đã phải khởi động lại mọi thứ. Và nếu điều này xảy ra giữa một nhiệm vụ kéo dài sáu giờ, thì một lượng lớn thời gian đắt tiền trên máy tính sẽ bị mất và lịch trình của toàn bộ hoạt động sẽ bị gián đoạn.

Kỹ thuật viên được phái đến từ Storage Technologies. Nhưng bất chấp những nỗ lực tốt nhất, họ không thể tái tạo lại lỗi trong điều kiện thử nghiệm: nó dường như xảy ra khi đang thực hiện các lệnh in lớn. Vấn đề không phải là phần cứng, họ đã thay thế mọi thứ có thể: RAM, bộ vi điều khiển, ổ đĩa mềm, mọi bộ phận có thể tưởng tượng được của ổ băng từ - vấn đề vẫn tiếp diễn.

Sau đó các kỹ thuật viên gọi đến trụ sở chính và gọi Chuyên gia.

Chuyên gia lấy một chiếc ghế và một tách cà phê, ngồi trong phòng máy tính – thời đó có những phòng dành riêng cho máy tính – và quan sát các nhân viên xếp hàng chờ in một bản in lớn. Chuyên gia đang chờ đợi một thất bại xảy ra - và nó đã xảy ra. Mọi người đều nhìn Chuyên gia, nhưng anh ta không biết tại sao điều này lại xảy ra. Thế là ông ra lệnh xếp hàng lại công việc, toàn bộ nhân viên, kỹ thuật viên đều quay trở lại làm việc.

Chuyên gia lại ngồi xuống ghế và bắt đầu chờ đợi thất bại. Khoảng sáu giờ trôi qua và sự cố xảy ra. Chuyên gia lại không có ý kiến ​​gì, ngoại trừ mọi việc diễn ra trong một căn phòng chật kín người. Anh ta ra lệnh bắt đầu lại nhiệm vụ, ngồi xuống và chờ đợi.

Đến lần thất bại thứ ba, Expert nhận thấy điều gì đó. Lỗi xảy ra khi nhân viên thay băng trong ổ đĩa nước ngoài. Hơn nữa, sự cố xảy ra ngay khi một trong những nhân viên đi qua một viên gạch nào đó trên sàn.

Sàn nâng được làm bằng gạch nhôm đặt ở độ cao từ 6 đến 8 inch. Vô số dây dẫn từ máy tính chạy dưới sàn nâng để ngăn chặn bất kỳ ai vô tình giẫm phải một dây cáp quan trọng. Các viên gạch được lát rất chặt để ngăn các mảnh vụn rơi xuống dưới sàn nâng.

Chuyên gia nhận ra rằng một trong những viên gạch đã bị biến dạng. Khi một nhân viên bước vào góc của nó, các cạnh của viên gạch sẽ cọ xát với những viên gạch liền kề. Các bộ phận bằng nhựa kết nối các viên gạch cũng cọ xát với chúng, gây ra hiện tượng phóng điện vi tĩnh tạo ra nhiễu tần số vô tuyến.

Ngày nay, RAM được bảo vệ tốt hơn nhiều khỏi nhiễu tần số vô tuyến. Nhưng trong những năm đó, điều này không xảy ra. Chuyên gia nhận ra rằng sự can thiệp này đã làm gián đoạn bộ nhớ và kéo theo đó là hoạt động của hệ điều hành. Anh ấy đã gọi cho dịch vụ hỗ trợ, đặt mua gạch mới, tự lắp đặt và vấn đề đã biến mất.

Thủy triều lên rồi!

Câu chuyện xảy ra trong một phòng máy chủ, trên tầng bốn hoặc năm của một văn phòng ở Portsmouth (tôi nghĩ vậy), trong khu vực bến tàu.

Một ngày nọ, máy chủ Unix với cơ sở dữ liệu chính bị lỗi. Họ khởi động lại anh ta, nhưng anh ta vui vẻ tiếp tục ngã xuống nhiều lần. Chúng tôi quyết định gọi cho ai đó từ dịch vụ hỗ trợ.

Người hỗ trợ... Tôi nghĩ tên anh ấy là Mark, nhưng điều đó không quan trọng... Tôi không nghĩ là tôi biết anh ấy. Nó không quan trọng, thực sự. Hãy ở bên Mark nhé, được chứ? Tuyệt vời.

Vì vậy, vài giờ sau, Mark đến (bạn biết đấy, từ Leeds đến Portsmouth không xa lắm), bật máy chủ và mọi thứ hoạt động bình thường. Hỗ trợ chết tiệt điển hình, khách hàng rất khó chịu về điều này. Mark xem qua các tệp nhật ký và không tìm thấy điều gì đáng lo ngại. Vì vậy, Mark quay trở lại tàu (hoặc bất kỳ phương tiện giao thông nào anh ấy đã đến, theo những gì tôi biết thì đó có thể là một con bò què... dù sao thì điều đó không thành vấn đề, được chứ?) và quay trở lại Leeds, lãng phí ngày.

Tối hôm đó máy chủ lại gặp sự cố. Câu chuyện cũng tương tự... máy chủ không hoạt động. Mark cố gắng trợ giúp từ xa nhưng máy khách không thể khởi động máy chủ.

Một chuyến tàu, xe buýt, bánh trứng đường chanh hay thứ gì đó tào lao khác, và Mark đã quay lại Portsmouth. Hãy nhìn xem, máy chủ khởi động mà không gặp vấn đề gì! Phép màu. Mark dành vài giờ để kiểm tra xem mọi thứ có ổn với hệ điều hành hoặc phần mềm hay không rồi lên đường đến Leeds.

Vào khoảng giữa ngày, máy chủ gặp sự cố (bình tĩnh nào!). Lần này có vẻ hợp lý khi đưa người hỗ trợ phần cứng đến thay thế máy chủ. Nhưng không, sau khoảng 10 tiếng nó cũng rơi xuống.

Tình trạng này cứ lặp đi lặp lại trong vài ngày. Máy chủ hoạt động, gặp sự cố sau khoảng 10 giờ và không khởi động trong 2 giờ tiếp theo. Họ đã kiểm tra hệ thống làm mát, rò rỉ bộ nhớ, họ kiểm tra mọi thứ nhưng không tìm thấy gì. Sau đó, tai nạn dừng lại.

Một tuần trôi qua vô tư... ai cũng vui vẻ. Hạnh phúc cho đến khi tất cả bắt đầu lại. Hình ảnh là như nhau. 10 giờ làm việc, 2-3 giờ ngừng hoạt động...

Và rồi ai đó (tôi nghĩ họ đã nói với tôi rằng người này không liên quan gì đến CNTT) nói:

"Đó là thủy triều!"

Câu cảm thán nhận được từ những cái nhìn trống rỗng, và có lẽ bàn tay của ai đó đã do dự trước nút gọi bảo vệ.

“Nó ngừng hoạt động theo thủy triều.”

Đây dường như là một khái niệm hoàn toàn xa lạ đối với những nhân viên hỗ trợ CNTT, những người khó có thể đọc Kỷ yếu Tide khi đang ngồi uống cà phê. Họ giải thích rằng điều này không thể liên quan đến thủy triều dưới bất kỳ hình thức nào vì máy chủ đã hoạt động được một tuần mà không gặp sự cố.

“Tuần trước thủy triều xuống nhưng tuần này thủy triều lên cao.”

Một chút thuật ngữ dành cho những người không có giấy phép lái du thuyền. Thủy triều phụ thuộc vào chu kỳ mặt trăng. Và khi Trái đất quay, cứ sau 12,5 giờ lực hấp dẫn của Mặt trời và Mặt trăng sẽ tạo ra một đợt thủy triều. Vào đầu chu kỳ 12,5 giờ có thủy triều lên, ở giữa chu kỳ có nước rút và cuối chu kỳ lại có thủy triều cao. Nhưng khi quỹ đạo của mặt trăng thay đổi, sự khác biệt giữa thủy triều thấp và cao cũng thay đổi theo. Khi Mặt trăng nằm giữa Mặt trời và Trái đất hoặc ở phía đối diện Trái đất (trăng tròn hoặc không có trăng), chúng ta có thủy triều Syzygyn - thủy triều cao nhất và thủy triều thấp nhất. Vào lúc nửa vầng trăng, chúng ta có thủy triều cầu phương - thủy triều thấp nhất. Sự khác biệt giữa hai thái cực giảm đi rất nhiều. Chu kỳ mặt trăng kéo dài 28 ngày: syzygian - cầu phương - syzygian - cầu phương.

Khi các kỹ thuật viên được giải thích về bản chất của lực thủy triều, họ nghĩ ngay rằng cần phải gọi cảnh sát. Và khá logic. Nhưng hóa ra anh chàng đã đúng. Hai tuần trước, một tàu khu trục neo đậu cách văn phòng không xa. Mỗi khi thủy triều nâng nó lên một độ cao nhất định, trạm radar của con tàu lại ngang với sàn phòng máy chủ. Và radar (hoặc thiết bị tác chiến điện tử, hoặc một số đồ chơi quân sự khác) đã tạo ra sự hỗn loạn trong máy tính.

Nhiệm vụ bay cho tên lửa

Tôi được giao nhiệm vụ chuyển một hệ thống giám sát và điều khiển phóng tên lửa lớn (khoảng 400 nghìn dòng) sang các phiên bản mới của hệ điều hành, trình biên dịch và ngôn ngữ. Chính xác hơn, từ Solaris 2.5.1 đến Solaris 7 và từ Hệ thống phát triển Verdix Ada (VADS), được viết bằng Ada 83, đến hệ thống Rational Apex Ada, được viết bằng Ada 95. VADS đã được Rational mua và sản phẩm của nó đã được bán đã lỗi thời, mặc dù Rational đã cố gắng triển khai các phiên bản tương thích của các gói dành riêng cho VADS để dễ dàng chuyển đổi sang trình biên dịch Apex.

Ba người đã giúp tôi biên dịch mã một cách rõ ràng. Phải mất hai tuần. Và sau đó tôi tự mình làm việc để hệ thống hoạt động. Tóm lại, đó là kiến ​​trúc và cách triển khai hệ thống phần mềm tồi tệ nhất mà tôi từng gặp phải, vì vậy phải mất thêm hai tháng nữa để hoàn thành bản port. Hệ thống sau đó đã được đưa đi thử nghiệm và mất thêm vài tháng nữa. Tôi đã sửa ngay các lỗi phát hiện được trong quá trình thử nghiệm, nhưng số lượng của chúng giảm nhanh chóng (mã nguồn là một hệ thống sản xuất nên chức năng của nó hoạt động khá đáng tin cậy, tôi chỉ cần loại bỏ các lỗi phát sinh trong quá trình thích ứng với trình biên dịch mới). Cuối cùng, khi mọi thứ đã ổn thỏa thì tôi được chuyển sang một dự án khác.

Và vào thứ Sáu trước Lễ Tạ ơn, điện thoại reo.

Vụ phóng tên lửa dự kiến ​​sẽ được thử nghiệm trong khoảng ba tuần, và trong quá trình thử nghiệm đếm ngược trong phòng thí nghiệm, chuỗi lệnh đã bị chặn. Trong thực tế, điều này sẽ hủy bỏ cuộc thử nghiệm và nếu tắc nghẽn xảy ra trong vòng vài giây kể từ khi khởi động động cơ, một số hành động không thể đảo ngược sẽ xảy ra trong các hệ thống phụ trợ, đòi hỏi tên lửa phải sẵn sàng lâu dài - và tốn kém. Nó sẽ không bắt đầu, nhưng rất nhiều người sẽ rất buồn vì mất thời gian và rất nhiều tiền. Đừng để bất cứ ai nói với bạn rằng Bộ Quốc phòng tiêu tiền một cách liều lĩnh—Tôi chưa bao giờ gặp một người quản lý hợp đồng nào không đặt ngân sách lên hàng đầu hoặc thứ hai, sau đó là tiến độ.

Trong những tháng trước, thử thách đếm ngược này đã được thực hiện hàng trăm lần với nhiều biến thể, chỉ có một vài trục trặc nhỏ. Vì vậy, khả năng xảy ra điều này là rất thấp nhưng hậu quả của nó lại rất đáng kể. Nhân cả hai yếu tố này lên, bạn sẽ hiểu rằng tin tức này dự đoán một tuần nghỉ lễ sẽ bị hủy hoại đối với tôi và hàng chục kỹ sư, nhà quản lý.

Và người ta chú ý đến tôi với tư cách là người chuyển hệ thống.

Giống như hầu hết các hệ thống quan trọng về bảo mật, rất nhiều tham số đã được ghi lại, do đó, khá dễ dàng để xác định một số dòng mã đã được thực thi trước khi hệ thống gặp sự cố. Và tất nhiên, chúng hoàn toàn không có gì bất thường; những biểu thức tương tự đã được thực hiện thành công hàng nghìn lần trong cùng một lần chạy.

Chúng tôi đã gọi những người từ Apex đến Rational vì họ là những người đã phát triển trình biên dịch và một số quy trình họ phát triển có tên trong mã đáng ngờ. Họ (và tất cả những người khác) rất ấn tượng rằng cần phải tìm ra gốc rễ của một vấn đề có tầm quan trọng quốc gia theo đúng nghĩa đen.

Vì không có gì thú vị trong các tạp chí nên chúng tôi quyết định thử tái tạo lại vấn đề trong phòng thí nghiệm địa phương. Đây không phải là một nhiệm vụ dễ dàng vì sự kiện này xảy ra khoảng một lần trên 1000 lần chạy. Một lý do bị nghi ngờ là lệnh gọi tới chức năng mutex do nhà cung cấp phát triển (một phần của gói di chuyển VADS) Unlock không dẫn đến việc mở khóa. Luồng xử lý gọi hàm này đã xử lý các thông báo nhịp tim, thường đến mỗi giây. Chúng tôi tăng tần số lên 10 Hz, tức là 10 lần mỗi giây và bắt đầu chạy. Khoảng một giờ sau hệ thống tự khóa. Trong nhật ký, chúng tôi thấy rằng trình tự các thông báo được ghi lại giống như trong lần kiểm tra thất bại. Chúng tôi đã thực hiện thêm vài lần chạy nữa, hệ thống liên tục bị chặn 45-90 phút sau khi bắt đầu và mỗi lần nhật ký đều chứa cùng một tuyến đường. Mặc dù về mặt kỹ thuật chúng tôi đang chạy mã khác nhau - tần suất thông báo khác nhau - hoạt động của hệ thống vẫn giống nhau, vì vậy chúng tôi tin rằng kịch bản tải này đang gây ra cùng một vấn đề.

Bây giờ chúng tôi cần tìm ra chính xác vị trí xảy ra việc chặn trong chuỗi biểu thức.

Việc triển khai hệ thống này đã sử dụng hệ thống nhiệm vụ Ada và sử dụng nó cực kỳ kém. Nhiệm vụ là một cấu trúc có thể thực thi đồng thời ở cấp độ cao trong Ada, giống như các luồng thực thi, chỉ được tích hợp trong chính ngôn ngữ đó. Khi hai tác vụ cần liên lạc, chúng "đặt điểm hẹn", trao đổi dữ liệu cần thiết, sau đó dừng điểm hẹn và quay lại thực hiện độc lập. Tuy nhiên, hệ thống đã được thực hiện khác nhau. Sau khi một nhiệm vụ mục tiêu được điểm hẹn, nhiệm vụ mục tiêu đó sẽ gặp một nhiệm vụ khác, nhiệm vụ này sau đó lại gặp nhiệm vụ thứ ba, v.v. cho đến khi một số quá trình xử lý được hoàn thành. Sau đó, tất cả các điểm hẹn này đã hoàn thành và mỗi nhiệm vụ phải quay lại thực hiện. Tức là chúng ta đang xử lý hệ thống gọi hàm đắt nhất thế giới, hệ thống này đã dừng toàn bộ quá trình “đa nhiệm” trong khi nó xử lý một phần dữ liệu đầu vào. Và trước đó điều này không chỉ dẫn đến vấn đề vì thông lượng rất thấp.

Tôi đã mô tả cơ chế nhiệm vụ này vì khi một điểm hẹn được yêu cầu hoặc dự kiến ​​hoàn thành thì "chuyển đổi nhiệm vụ" có thể xảy ra. Nghĩa là, bộ xử lý có thể bắt đầu xử lý một tác vụ khác đã sẵn sàng để thực thi. Hóa ra là khi một nhiệm vụ sẵn sàng gặp một nhiệm vụ khác, một nhiệm vụ hoàn toàn khác có thể bắt đầu thực thi và cuối cùng quyền điều khiển sẽ quay trở lại điểm hẹn đầu tiên. Và các sự kiện khác có thể xảy ra khiến nhiệm vụ phải chuyển đổi; một sự kiện như vậy là lệnh gọi tới một chức năng hệ thống, chẳng hạn như in hoặc thực thi một mutex.

Để hiểu dòng mã nào đang gây ra sự cố, tôi cần tìm cách ghi lại tiến trình thông qua một chuỗi câu lệnh mà không kích hoạt chuyển đổi tác vụ, điều này sẽ ngăn xảy ra sự cố. Vì thế tôi không thể tận dụng được Put_Line()để tránh thực hiện các thao tác I/O. Tôi có thể đặt một biến đếm hoặc một biến nào đó tương tự, nhưng làm cách nào tôi có thể thấy giá trị của nó nếu tôi không thể hiển thị nó trên màn hình?

Ngoài ra, khi kiểm tra nhật ký, hóa ra, mặc dù việc xử lý thông báo nhịp tim bị đóng băng, chặn tất cả các hoạt động I/O của quy trình và ngăn không cho quá trình xử lý khác được thực hiện, nhưng các tác vụ độc lập khác vẫn tiếp tục được thực thi. Nghĩa là, công việc không bị chặn hoàn toàn mà chỉ là một chuỗi nhiệm vụ (quan trọng).

Đây là đầu mối cần thiết để đánh giá biểu thức chặn.

Tôi đã tạo một gói Ada chứa một tác vụ, một kiểu liệt kê và một biến toàn cục thuộc loại đó. Vô số chữ được liên kết với các biểu thức cụ thể của chuỗi có vấn đề (ví dụ: Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked), sau đó chèn các biểu thức gán vào đó để gán kiểu liệt kê tương ứng cho một biến toàn cục. Vì mã đối tượng của tất cả những thứ này chỉ được lưu trữ một hằng số trong bộ nhớ nên việc chuyển đổi tác vụ do thực thi nó là cực kỳ khó xảy ra. Chúng tôi chủ yếu nghi ngờ về các biểu thức có thể chuyển đổi tác vụ, vì việc chặn xảy ra khi thực thi thay vì quay trở lại khi chuyển đổi tác vụ trở lại (vì một số lý do).

Nhiệm vụ theo dõi chỉ đơn giản là chạy trong một vòng lặp và kiểm tra định kỳ để xem liệu giá trị của biến toàn cục có thay đổi hay không. Với mỗi thay đổi, giá trị sẽ được lưu vào một tệp. Sau đó chờ một thời gian ngắn và kiểm tra mới. Tôi đã ghi biến vào tệp vì tác vụ chỉ được thực thi khi hệ thống chọn nó để thực thi khi chuyển đổi tác vụ trong vùng có vấn đề. Bất cứ điều gì xảy ra trong nhiệm vụ này sẽ không ảnh hưởng đến các nhiệm vụ bị chặn không liên quan khác.

Dự kiến, khi hệ thống đạt đến điểm thực thi mã có vấn đề, biến toàn cục sẽ được đặt lại khi chuyển sang từng biểu thức tiếp theo. Sau đó, điều gì đó sẽ xảy ra khiến tác vụ chuyển đổi và vì tần số thực thi của nó (10 Hz) thấp hơn tần số của tác vụ giám sát, màn hình có thể nắm bắt giá trị của biến toàn cục và ghi nó. Trong tình huống bình thường, tôi có thể nhận được một chuỗi lặp lại của một tập hợp con các bảng liệt kê: các giá trị cuối cùng của biến tại thời điểm chuyển đổi tác vụ. Khi treo, biến toàn cục sẽ không còn thay đổi và giá trị cuối cùng được ghi sẽ cho biết biểu thức nào chưa hoàn thành.

Tôi đã chạy mã bằng theo dõi. Anh đông cứng lại. Và việc giám sát hoạt động như kim đồng hồ.

Nhật ký chứa trình tự dự kiến, bị gián đoạn bởi một giá trị chỉ ra rằng một mutex đã được gọi Unlockvà nhiệm vụ chưa được hoàn thành - như trường hợp của hàng nghìn cuộc gọi trước đó.

Các kỹ sư của Apex đang sốt sắng phân tích mã của họ vào thời điểm này và tìm thấy một vị trí trong mutex, nơi mà về mặt lý thuyết, có thể xảy ra khóa. Nhưng xác suất của nó là rất thấp, vì chỉ một chuỗi sự kiện nhất định xảy ra tại một thời điểm nhất định mới có thể dẫn đến việc chặn. Định luật Murphy các bạn ạ, đó là Định luật Murphy.

Để bảo vệ đoạn mã tôi cần, tôi đã thay thế các lệnh gọi hàm mutex (được xây dựng dựa trên chức năng mutex của hệ điều hành) bằng gói mutex Ada gốc nhỏ để kiểm soát quyền truy cập mutex vào đoạn mã đó.

Tôi đã chèn nó vào mã và chạy thử nghiệm. Bảy giờ sau, mã vẫn hoạt động.

Mã của tôi đã được gửi tới Rational, nơi họ biên dịch nó, phân tách nó và kiểm tra xem nó có sử dụng cùng một cách tiếp cận đã được sử dụng trong các hàm mutex có vấn đề hay không.

Đây là buổi đánh giá mã đông đúc nhất trong sự nghiệp của tôi 🙂 Có khoảng mười kỹ sư và quản lý trong phòng với tôi, mười người khác đang tham gia một cuộc gọi hội nghị - và tất cả họ đều kiểm tra khoảng 20 dòng mã.

Mã đã được xem xét, các tệp thực thi mới được tập hợp và gửi để kiểm tra hồi quy chính thức. Vài tuần sau, cuộc thử nghiệm đếm ngược thành công và tên lửa đã cất cánh.

Được rồi, mọi chuyện đều ổn, nhưng mục đích của câu chuyện là gì?

Đó là một vấn đề hoàn toàn kinh tởm. Hàng trăm nghìn dòng mã, thực thi song song, hơn chục quy trình tương tác, kiến ​​trúc kém và triển khai kém, giao diện cho hệ thống nhúng và tiêu tốn hàng triệu đô la. Không có áp lực, phải.

Tôi không phải là người duy nhất giải quyết vấn đề này, mặc dù tôi là người được chú ý khi thực hiện việc chuyển mạng. Nhưng dù tôi đã làm được, điều đó không có nghĩa là tôi hiểu hết hàng trăm nghìn dòng mã, hay thậm chí đọc lướt qua chúng. Mã và nhật ký đã được các kỹ sư trên cả nước phân tích nhưng khi họ nói với tôi giả thuyết của họ về nguyên nhân thất bại, tôi chỉ mất nửa phút để bác bỏ chúng. Và khi tôi được yêu cầu phân tích các lý thuyết, tôi sẽ chuyển nó cho người khác, bởi vì đối với tôi rõ ràng là những kỹ sư này đã đi sai hướng. Nghe có vẻ tự phụ? Đúng, điều này đúng, nhưng tôi đã bác bỏ các giả thuyết và yêu cầu vì một lý do khác.

Tôi đã hiểu bản chất của vấn đề. Tôi không biết chính xác chuyện gì đang xảy ra ở đâu và tại sao, nhưng tôi biết chuyện gì đang xảy ra.

Qua nhiều năm, tôi đã tích lũy được rất nhiều kiến ​​thức và kinh nghiệm. Tôi là một trong những người tiên phong sử dụng Ada và hiểu rõ ưu nhược điểm của nó. Tôi biết cách thư viện thời gian chạy Ada xử lý các tác vụ và xử lý việc thực thi song song. Và tôi hiểu lập trình cấp thấp ở cấp độ bộ nhớ, thanh ghi và trình biên dịch mã. Nói cách khác, tôi có kiến ​​thức sâu rộng trong lĩnh vực của mình. Và tôi đã sử dụng chúng để tìm ra nguyên nhân của vấn đề. Tôi không chỉ khắc phục lỗi mà còn hiểu cách tìm ra lỗi đó trong môi trường thời gian chạy rất nhạy cảm.

Những câu chuyện về cuộc đấu tranh với mã như vậy không mấy thú vị đối với những người chưa quen với các tính năng và điều kiện của cuộc đấu tranh như vậy. Nhưng những câu chuyện này giúp chúng ta hiểu được cần phải làm gì để giải quyết những vấn đề thực sự khó khăn.

Để giải quyết những vấn đề thực sự khó khăn, bạn không chỉ cần là một lập trình viên. Bạn cần hiểu “số phận” của mã, cách nó tương tác với môi trường của nó và cách bản thân môi trường hoạt động.

Và rồi bạn sẽ có một tuần nghỉ lễ bị hủy hoại.

Tiếp tục.

Nguồn: www.habr.com

Thêm một lời nhận xét