Hệ Thống Ngân Hàng Nói COBOL: Giải Pháp Tối Ưu Hóa
Tôi đã vượt qua một quá trình di chuyển 5 năm chỉ với 40 dòng C và một mẹo Unix
Trước đây, tôi từng nghĩ rằng "daemon" có nghĩa là quỷ dữ—cho đến đêm qua, khi tôi kết nối một mainframe từ những năm 1960 vào một dashboard React mà không cần khởi động lại bất kỳ tác vụ nào.
Dưới đây là câu chuyện 3 phút (và tệp C 40 dòng) đã giúp tôi rời văn phòng trước nửa đêm.
Vấn Đề Tôi Đối Mặt
Quy trình chuyển tiền chính của chúng tôi vẫn sử dụng JOB card COBOL. Mỗi đêm vào lúc 02:00, nó:
- Đọc một tệp VSAM
- Gọi
DFH$MONEY
(CICS) - In một báo cáo JES dài 400 trang
Yêu cầu mới: Cung cấp nó như một điểm cuối REST để frontend fintech có thể kích hoạt theo yêu cầu.
Giới hạn: Không có thời gian ngừng hoạt động, không thay đổi JCL, không ngân sách.
Nguồn lực: Một thực tập sinh (tôi), một lon Red Bull, một MacBook.
Mẹo Daemon Unix Mà Ít Người Biết
Điều khiến tôi ngạc nhiên là: một daemon không phải là phép thuật—nó chỉ là một tiến trình thực hiện double-fork để terminal có thể ngừng hoạt động mà không làm nó chết.
Khi bạn chạy một chương trình bình thường:
bash
$ ./my-service
# Đóng terminal = dịch vụ chết 💀
Dịch vụ của bạn là con cái của shell. Giết cha, giết con. Đó là di truyền học Unix cơ bản.
Nhưng một daemon? Nó cắt đứt dây rốn:
c
pid_t pid = fork();
if (pid > 0) exit(0); // Cha ra đi
setsid(); // Phiên mới, cuộc sống mới
pid = fork(); // Fork thêm (tin tôi đi)
if (pid > 0) exit(0);
// Giờ chúng ta bất tử 🚀
Tên Lửa 40 Dòng
Thay vì viết lại hàng triệu dòng COBOL, tôi đã xây dựng một cây cầu nhỏ:
c
// main.c – libpolycall-cobol FFI
char *cobol_job_invoke(const char *jcl_path, const char *parm) {
static char reply[65536];
char cmd[1024];
snprintf(cmd, sizeof(cmd),
"tsocmd 'submit %s parm(%s)' 2>&1",
jcl_path, parm ? parm : "");
FILE *fp = popen(cmd, "r");
size_t n = fread(reply, 1, sizeof(reply)-1, fp);
pclose(fp);
reply[n] = '\0';
return reply;
}
Biên dịch → libpolycall-cobol.so
→ thả vào /usr/lib/polycall/
→ hoàn tất.
Không cần quyền root. Không cần biên dịch lại mã nguồn cũ. Không cần mở cổng mới trên mainframe.
Pipeline Một Tệp Makefile
Tôi đã kết hợp tất cả các ngôn ngữ vào một xây dựng duy nhất:
makefile
all: driver cobol go python java lua node
@echo "🚀 Tất cả các bindings đã được biên dịch. DRIVER sẵn sàng trên cổng 3005→8085"
Một lệnh make all
tạo ra:
libpolycall-cobol.so
← người hùng của tối naylibpolycall-go.so
libpolycall-python.so
- Cùng với Java, Node, Lua...
Tất cả đăng ký với cùng một daemon C DRIVER. Một tiến trình, sáu ngôn ngữ, không cần cấu hình thủ công.
Buổi Demo Khiến Mọi Người Im Lặng
- Mở trình duyệt →
http://localhost:8084
- Kéo bất kỳ tệp .jcl nào vào khu vực thả
- Nhấn "Gửi"
- Theo dõi JESMSGLG xuất hiện theo thời gian thực
Sếp: "Chờ đã... đó có phải JOB sản xuất của chúng ta không?"
Tôi: "Đúng, và tôi không hề chạm vào PROC nào."
Sếp: [im lặng bối rối]
Tại Sao Điều Này Quan Trọng
Quá trình "hiện đại hóa" truyền thống có nghĩa là một cuộc viết lại 5 năm, tốn 50 triệu đô kết thúc với sự cố cấp độ Chernobyl.
Chúng tôi vừa side-carred con quái vật:
- Di sản vẫn hoạt động không bị chạm vào
- Tính năng mới được triển khai bằng Go/React/hoặc bất cứ thứ gì
- Quay lại =
pkill -f server.py
Và bởi vì chúng tôi đã daemon hóa cây cầu, terminal có thể đóng, phiên SSH của tôi có thể chết, và DRIVER vẫn sẽ định tuyến các cuộc gọi REST vào JES lúc 02:00.
Không cần giám sát. Không quên nohup
. Không cần gõ &
trong hoảng loạn.
Bài Học Thực Sự Từ Unix
Nếu dịch vụ của bạn chết khi bạn đóng laptop, bạn không có một dịch vụ—bạn có một đứa con shell.
Thêm double-fork. Chuyển hướng stdout. Viết một tệp PID. Để cha thoát một cách thanh lịch.
Đó chính xác là tất cả những gì một daemon là. Không phải phép thuật quỷ. Chỉ là sự nuôi dạy tốt.
Điều Gì Sẽ Xảy Ra Tiếp Theo?
Tối nay, tôi sẽ đổi khu vực thả kéo thành một GraphQL mutation để các bạn React có thể kích hoạt những giao dịch triệu đô với độ an toàn kiểu dữ liệu.
Nhóm vận hành mainframe vẫn nghĩ tôi "chỉ đang chạy thử nghiệm." 😇
Và libpolycall? Nó sẽ có hỗ trợ --detach
đúng nghĩa. Bởi vì việc polling ở chế độ đính kèm là cho những dịch vụ chưa trưởng thành.
Theo dõi tôi để biết thêm những khoảnh khắc "Tôi không thể tin rằng điều này vẫn điều hành thế giới". Hiện tôi đang kết nối các dự án OBINexus để biến các hệ thống di sản thành các chức năng serverless.
Các Thực Hành Tốt Nhất
- Đảm bảo mã nguồn được tối ưu hóa và dễ bảo trì.
- Sử dụng công cụ quản lý phiên bản để theo dõi các thay đổi trong mã.
- Thực hiện kiểm tra tự động để phát hiện lỗi sớm.
Những Cạm Bẫy Thường Gặp
- Không theo dõi trạng thái của daemon có thể dẫn đến thất bại trong việc giám sát dịch vụ.
- Bỏ qua việc ghi log có thể khiến các vấn đề khó phát hiện.
Mẹo Hiệu Suất
- Sử dụng kết nối không đồng bộ để cải thiện hiệu suất của dịch vụ.
- Đảm bảo nguồn tài nguyên hệ thống được phân bổ hợp lý.
Khắc Phục Sự Cố
- Kiểm tra nhật ký để xác định nguyên nhân khi dịch vụ không phản hồi.
- Sử dụng công cụ giám sát để theo dõi hiệu suất của dịch vụ.
Câu Hỏi Thường Gặp (FAQ)
1. Daemon là gì?
Daemon là một tiến trình chạy nền, thường không có giao diện người dùng, thực hiện các tác vụ tự động hoặc theo lịch.
2. Làm thế nào để tạo một daemon trong C?
Bạn có thể sử dụng hàm fork()
và setsid()
để tạo một daemon.
3. Tại sao cần phải daemon hóa một ứng dụng?
Để đảm bảo rằng ứng dụng có thể chạy liên tục mà không bị ảnh hưởng bởi việc đóng terminal hoặc phiên SSH.