Tại sao nhóm tại LMAX sử dụng Java và thiết kế kiến ​​trúc để tránh GC bằng mọi giá?


24

Tại sao nhóm tại LMAX thiết kế Trình phân tích LMAX trong Java nhưng tất cả các điểm thiết kế của họ để giảm thiểu việc sử dụng GC? Nếu một người không muốn chạy GC thì tại sao lại sử dụng ngôn ngữ được thu gom rác?

Tối ưu hóa của họ, mức độ kiến ​​thức phần cứng và suy nghĩ họ đặt ra chỉ là tuyệt vời nhưng tại sao Java?

Tôi không chống lại Java hay bất cứ điều gì, nhưng tại sao lại là ngôn ngữ GC? Tại sao không sử dụng một cái gì đó như D hoặc bất kỳ ngôn ngữ nào khác mà không có GC nhưng cho phép mã hiệu quả? Có phải nhóm đã quen thuộc nhất với Java hay Java có một số lợi thế duy nhất mà tôi không thấy?

Nói rằng họ phát triển nó bằng cách sử dụng D với quản lý bộ nhớ thủ công, điều gì sẽ là sự khác biệt? Họ sẽ phải nghĩ mức độ thấp (mà họ đã có), nhưng họ có thể đạt được hiệu suất tốt nhất trong hệ thống như bản địa của nó.


6
Tôi biết rất ít về dự án này, nhưng có vẻ như đó là một loại khung mà người khác có thể xây dựng. Và nếu bạn quản lý để viết điều đó bằng Java (và cho phép người khác viết mã bằng Java và gặt hái những lợi ích), thì bạn sẽ có một "cơ sở khách hàng" lớn hơn nhiều so với việc bạn đã viết nó trong D.
Joachim Sauer

6
@kadaj: không thực sự quan trọng nếu người tiêu dùng là công khai hoặc nội bộ: nếu bạn làm cho nó có thể truy cập bằng ngôn ngữ được biết đến rộng rãi, nó sẽ hữu ích hơn, ngay cả đối với phát triển nội bộ. Nếu bạn bắt đầu cuộc tranh luận (giả thuyết) của mình bằng: "Giả sử rằng mọi người đều biết D cũng như họ biết Java, ...", thì có lẽ bạn đang thiếu một cái gì đó.
Joachim Sauer

6
Một số người thích sử dụng búa cho tất cả các loại vấn đề. Có một cạnh thô mà bạn muốn lập kế hoạch, bash nó với búa của bạn cho đến khi nó trơn tru. Có một con ốc vít bạn cần lái vào, đập nó bằng búa cho đến khi nó vào. Có một vật trang trí tinh tế bạn cần chà nhám, đập nó bằng búa và sau đó đổ lỗi cho vật trang trí để "mút". C hoặc C ++ sẽ là lựa chọn tốt hơn D, nếu chỉ dành cho nền tảng kiến ​​thức hiện có. Không chắc chắn tại sao bạn thậm chí đã đưa lên D làm ví dụ TBH.
gbjbaanb

2
@gbjbaanb Tôi đã đề cập đến D vì nó cung cấp bộ sưu tập rác (trong trường hợp cần trừu tượng hóa mức độ cao và thay đổi bộ nhớ quá khó đối với não bộ) nhưng cũng cho phép quản lý bộ nhớ thủ công với malloc kiểu C và miễn phí. D giống như Objective-C với ARC (không có GC thực sự) nhưng tốt hơn thế. Nhưng vâng, C / C ++ sẽ phù hợp với hóa đơn.

4
@kadaj Tôi thấy bạn đã nhận được một số lời quảng cáo ở đây để đưa lên D nhưng tôi muốn nói rằng tôi thất vọng về giọng điệu mà người khác đang sử dụng và đặt ra lý do tại sao tôi nghĩ D là trung tâm của câu hỏi. Mặc dù D thực sự không được sử dụng rộng rãi, D cung cấp một số cấu trúc mức cao mà tôi có thể mong đợi tìm thấy trong Java hoặc C # nhưng không phải trong (ít nhất là kiểu cũ) C ++. Nó vẫn cung cấp cho việc trộn được quản lý và không được quản lý - đó chỉ là ngôn ngữ duy nhất tôi biết để làm điều đó! Vì vậy, D không chỉ là một lựa chọn thú cưng, mà là một mục tiêu có các mục tiêu trùng khớp với các câu hỏi ban đầu xung quanh GC.
J Trana

Câu trả lời:


20

Bởi vì có một sự khác biệt rất lớn giữa tối ưu hóa hiệu suấttắt hoàn toàn an toàn

Bằng cách giảm số lượng GC, khung của họ phản ứng nhanh hơn và có thể chạy (có lẽ) nhanh hơn. Bây giờ, tối ưu hóa cho trình thu gom rác không có nghĩa là họ không bao giờ thực hiện việc thu gom rác. Nó chỉ có nghĩa là họ làm điều đó ít thường xuyên hơn, và khi họ làm điều đó, nó chạy rất nhanh. Những loại tối ưu hóa bao gồm:

  1. Giảm thiểu số lượng vật thể di chuyển đến một không gian sống sót (nghĩa là đã sống sót ít nhất một bộ sưu tập rác) bằng cách sử dụng các vật thể vứt bỏ nhỏ. Đối tượng di chuyển đến không gian sống sót khó thu thập hơn và bộ sưu tập rác ở đây đôi khi ngụ ý đóng băng toàn bộ JVM.
  2. Đừng phân bổ quá nhiều đối tượng để bắt đầu. Điều này có thể gây tác dụng ngược nếu bạn không cẩn thận, vì các đối tượng thế hệ trẻ có giá siêu rẻ để phân bổ và thu thập.
  3. Đảm bảo rằng đối tượng mới trỏ đến đối tượng cũ (chứ không phải ngược lại) để đối tượng trẻ dễ thu thập, vì không có tham chiếu nào đến chúng sẽ khiến chúng bị giữ

Khi bạn điều chỉnh hiệu suất, bạn thường điều chỉnh một số "điểm nóng" rất cụ thể trong khi bỏ qua mã không chạy thường xuyên. Nếu bạn làm điều đó trong Java, bạn có thể để trình thu gom rác vẫn xử lý các góc tối đó (vì nó sẽ không tạo ra nhiều khác biệt) trong khi tối ưu hóa rất cẩn thận cho khu vực chạy trong một vòng lặp chặt chẽ. Vì vậy, bạn có thể chọn nơi bạn tối ưu hóa và nơi bạn không, và do đó bạn có thể tập trung nỗ lực của mình vào nơi quan trọng.


Bây giờ, nếu bạn tắt bộ sưu tập rác hoàn toàn, thì bạn không thể chọn. Bạn phải vứt bỏ thủ công mọi đối tượng, bao giờ hết. Phương pháp đó được gọi nhiều nhất một lần mỗi ngày? Trong Java, bạn có thể để nó như vậy, vì tác động hiệu năng của nó là không đáng kể (có thể ổn khi để cho một GC đầy đủ xảy ra mỗi tháng). Trong C ++, bạn vẫn đang rò rỉ tài nguyên, vì vậy bạn phải cẩn thận ngay cả phương thức tối nghĩa đó. Vì vậy, bạn phải trả giá cho việc quản lý tài nguyên trong mọi phần, một phần của ứng dụng của bạn, trong khi ở Java, bạn có thể tập trung.


Nhưng nó trở nên tồi tệ hơn.

Điều gì nếu bạn có một lỗi, giả sử trong một góc tối của ứng dụng của bạn chỉ được truy cập vào thứ Hai vào một ngày trăng tròn? Java có đảm bảo an toàn mạnh mẽ. Có rất ít hoặc không có "hành vi không xác định". Nếu bạn sử dụng sai, một ngoại lệ sẽ bị ném, chương trình của bạn dừng lại và không xảy ra hỏng dữ liệu. Vì vậy, bạn khá chắc chắn rằng không có gì sai có thể xảy ra mà bạn không nhận ra.

Nhưng trong một cái gì đó như D, bạn có thể có quyền truy cập con trỏ xấu hoặc tràn bộ đệm và bạn có thể làm hỏng bộ nhớ của mình, nhưng chương trình của bạn sẽ không biết (bạn đã tắt an toàn, nhớ không?) Và sẽ tiếp tục chạy không đúng dữ liệu, và làm một số điều khá khó chịu và làm hỏng dữ liệu của bạn, và bạn không biết, và khi càng nhiều tham nhũng xảy ra, dữ liệu của bạn càng ngày càng sai, và sau đó đột nhiên nó bị hỏng, và đó là một ứng dụng quan trọng trong cuộc sống, và Một số lỗi đã xảy ra trong tính toán của một tên lửa, và do đó nó không hoạt động, và tên lửa phát nổ, và ai đó chết, và công ty của bạn ở trên trang nhất của mỗi tờ báo và ông chủ của bạn chỉ tay bạn nói rằng "Bạn kỹ sư gợi ý chúng tôi sử dụng D để tối ưu hóa hiệu suất, tại sao bạn không nghĩ đến sự an toàn?"Và đó là lỗi của bạn. Bạn đã giết những người đó bằng nỗ lực ngu ngốc của mình trong hiệu suất.


OK, ok, hầu hết thời gian nó ít kịch tính hơn thế. Nhưng ngay cả một ứng dụng quan trọng trong kinh doanh hoặc chỉ là một ứng dụng GPS hoặc giả sử, một trang web chăm sóc sức khỏe của chính phủ có thể mang lại một số hậu quả khá tiêu cực nếu bạn gặp lỗi. Sử dụng một ngôn ngữ ngăn chặn chúng hoàn toàn hoặc thất bại nhanh khi chúng xảy ra thường là một ý tưởng rất tốt.

Có một chi phí để tắt một sự an toàn. Về bản địa không phải lúc nào cũng có ý nghĩa. Đôi khi nó đơn giản và an toàn hơn nhiều khi chỉ cần tối ưu hóa một chút ngôn ngữ an toàn để sử dụng tất cả ngôn ngữ mà bạn có thể tự bắn vào chân mình. Tính chính xác và an toàn trong rất nhiều trường hợp là một vài nano giây mà bạn đã loại bỏ bằng cách loại bỏ hoàn toàn GC. Disruptor có thể được sử dụng trong những tình huống đó, vì vậy tôi nghĩ LMAX-Exchange đã thực hiện cuộc gọi đúng.

Nhưng những gì về D nói riêng? Bạn có một GC nếu bạn muốn cho các góc tối và tập hợp con SafeD (mà tôi không biết trước khi chỉnh sửa) xóa hành vi không xác định (nếu bạn nhớ sử dụng nó!).

Vâng, trong trường hợp đó là một câu hỏi đơn giản về sự trưởng thành. Hệ sinh thái Java có đầy đủ các công cụ được viết tốt và các thư viện trưởng thành (tốt hơn để phát triển). Nhiều nhà phát triển biết Java hơn D (tốt hơn để bảo trì). Tìm kiếm một ngôn ngữ mới và không phổ biến cho một thứ quan trọng như ứng dụng tài chính sẽ không phải là một ý tưởng hay. Với ngôn ngữ ít được biết đến, nếu bạn gặp vấn đề, ít người có thể giúp bạn và các thư viện bạn tìm thấy có xu hướng có nhiều lỗi hơn do chúng tiếp xúc với ít người hơn.

Vì vậy, điểm cuối cùng của tôi vẫn là: nếu bạn muốn tránh các vấn đề với hậu quả thảm khốc, hãy kiên trì với các lựa chọn an toàn. Tại thời điểm này trong cuộc đời của D, khách hàng của nó là những người khởi nghiệp nhỏ sẵn sàng chấp nhận rủi ro điên rồ. Nếu một vấn đề có thể tốn hàng triệu đô la, tốt hơn hết bạn nên tiếp tục theo đường cong chuông đổi mới .


2
Bài đăng gốc đặc biệt gọi ra D. Thực sự có một sự khác biệt khá lớn giữa C ++ và D liên quan đến độ chi tiết của sự lựa chọn. Ngay cả khi bạn chọn quản lý toàn bộ trong tập hợp con SafeD, tôi nghĩ bạn sẽ kiểm soát được một chút về các khía cạnh nhất định của việc thu thập và thời gian (bật / tắt, thu thập, thu nhỏ). Kiểm tra chiến lược của Mars Mars để quản lý bộ nhớ!
J Trana

2
Lmax cố tình bước bên một số an toàn mà Java cung cấp
James

Đây sẽ là một câu trả lời tuyệt vời, ngoại trừ Java không được cấp phép cho phần mềm quan trọng. Nếu bạn có lò phản ứng hạt nhân, nó sẽ được viết bằng C ++ chứ không phải Java, loại này sẽ loại bỏ toàn bộ khía cạnh "an toàn".
gbjbaanb

@gbjbaanb, [cần dẫn nguồn]. Các tiêu chuẩn / hướng dẫn về độ tin cậy mà tôi đã thấy trước tiên nên tránh sử dụng C / C ++ để ưu tiên các ngôn ngữ khác; và nếu đi sâu vào chúng, sau đó sử dụng các phiên bản ngôn ngữ bị hạn chế cao (MISRA, v.v.). Và một khi bạn chấp nhận các hạn chế, tôi không hiểu tại sao bạn không thể làm như vậy với bất kỳ ngôn ngữ nào khác. Nếu bạn đang suy nghĩ về việc Java Licence đề cập đến "không dành cho các cơ sở hạt nhân" trong phần GIỚI HẠN, có vẻ như điều đó đã thay đổi một thời gian trước đây và bây giờ thay vào đó chỉ nói điều gì đó giống như "hãy cẩn thận, không phải trách nhiệm của chúng tôi". Tuy nhiên, tôi giả sử (...)
hmijail

(...) Từ ngữ ban đầu giống như giấy phép của gcc và clang: không đảm bảo cho bất kỳ mục đích cụ thể nào. Vì vậy, bạn sẽ không sử dụng chúng cho một cái gì đó cần độ tin cậy, và thay vào đó bạn cần sử dụng một số trình biên dịch được chứng nhận, nếu không đi đến một số ngôn ngữ cụ thể cho công việc (Ada?).
hmijail

4

Có vẻ như lý do nó được viết bằng Java là vì họ có chuyên môn về Java và có lẽ nó đã được viết (mặc dù nó vẫn đang được phát triển tích cực) trước khi C ++ có hành động cùng với C ++ 0x / 11.

Mã của họ thực sự chỉ là Java theo tên, họ sử dụng sun.misc.Unsafe khá nhiều loại đánh bại quan điểm của Java và sự an toàn được cho là mang lại. Tôi đã viết một cổng C ++ của Disruptor và nó vượt trội hơn mã Java mà họ gửi (Tôi không mất nhiều thời gian để điều chỉnh JVM).

Điều đó nói rằng, các nguyên tắc mà người gây rối tuân theo không phải là ngôn ngữ cụ thể, ví dụ: Đừng mong đợi mã C ++ có độ trễ thấp mà allocs hoặc giải phóng khỏi heap.


Bạn có thể chỉ ra thực hiện của bạn? Tôi đã thấy một vài lần thực hiện như vậy so với yêu cầu hiệu suất cao hơn, nhưng cả hai đều bị lừa với sự đơn giản hóa: ví dụ, làm khó 1 nhà sản xuất + 1 người tiêu dùng thay vì đa nhà sản xuất / người tiêu dùng có khả năng như Disruptor ban đầu. Bản thân tác giả của Disruptor đã đề cập trong một chủ đề của Google Groups rằng hiệu suất có thể được cải thiện nhờ các tham số cứng trong phiên bản Java.
hmijail

4

Câu hỏi này nêu một tiền đề không chính xác là thực tế, sau đó đưa ra lập luận về tiền đề không chính xác đó.

Hãy đi sâu vào vấn đề này .. "tất cả các điểm thiết kế của họ để giảm thiểu việc sử dụng GC" - đơn giản là không đúng. Sự đổi mới trong kẻ gây rối không liên quan nhiều đến GC. Kẻ gây rối thực hiện vì thiết kế của nó khéo léo xem xét cách thức các máy tính hiện đại hoạt động - thứ ít phổ biến hơn nhiều so với người ta tưởng. Xem bài nói chuyện của Cliff Click http://www.azulsystems.com/events/javaone_2009/session/2009_J1_HardwareCrashCference.pdf để thảo luận.

LMax là khách hàng của Azul. Tôi biết trước rằng với Azul GCs chỉ đơn giản là không phát hành - thậm chí với hàng đống 175GB.


Có một hạt của sự thật này. Họ khởi động lại VM mỗi đêm để tránh một bộ sưu tập lớn. Dù sao đó cũng là những gì Martin Fowler đã viết và anh ta không hề ngớ ngẩn: "Giống như phần còn lại của hệ thống, những kẻ gây rối bị trả lại qua đêm. Việc trả lại này chủ yếu được thực hiện để xóa bộ nhớ để ít xảy ra sự kiện thu gom rác đắt tiền trong quá trình giao dịch." martinfowler.com/articles/lmax.html
JimmyJames

2
Không hẳn. Chúng tôi đã từng kích hoạt một GC thủ công mỗi đêm trong khoảng cách giao dịch 5 phút và điều chỉnh để đó sẽ là GC chính duy nhất trong một ngày. Điều đó trở nên dư thừa với Azul Zing. (Nguồn: Tôi đã làm việc tại LMAX cho đến gần đây)
Tom Johnson

@TomJohnson Tình yêu nhận được tin sốt dẻo. Bạn đang nói rằng mô tả của Martin Fowler là sai? Có thể giải pháp phát triển theo thời gian?
JimmyJames

2
Tôi đang nói anh ấy không chính xác về một số chi tiết nhỏ. Chúng tôi không bao giờ trả lại hệ thống của chúng tôi hàng ngày, nhưng chúng tôi đã làm một số công việc dọn dẹp cuối ngày.
Tom Johnson

3

Họ sẽ phải suy nghĩ cấp thấp

Ở trên làm cho một nửa câu trả lời bạn đang tìm kiếm. Bạn có thể tìm thấy một nửa khác để hoàn thành lý do không xa hơn trong blog LMAX :

Mặc dù rất hiệu quả, nó có thể dẫn đến một số lỗi vì nó rất dễ bị hỏng ...

Theo thừa nhận của các nhà phát triển LMAX, mã như thế có thể khá khó để phát triển, hiểu và gỡ lỗi - ngay cả trong Java. Đi xuống cấp độ thấp hơn nhiều so với nơi họ đang ở hiện tại sẽ chỉ làm trầm trọng thêm vấn đề này, như được chỉ ra trong bài viết trên Wikipedia về các ngôn ngữ lập trình cấp thấp :

Một chương trình được viết bằng ngôn ngữ cấp thấp có thể được thực hiện để chạy rất nhanh và với dung lượng bộ nhớ rất nhỏ; một chương trình tương đương trong một ngôn ngữ cấp cao sẽ nặng hơn. Các ngôn ngữ cấp thấp rất đơn giản, nhưng được coi là khó sử dụng, do nhiều chi tiết kỹ thuật phải được ghi nhớ .

Khi so sánh, một ngôn ngữ lập trình cấp cao tách biệt ngữ nghĩa thực thi của kiến ​​trúc máy tính khỏi đặc tả của chương trình, giúp đơn giản hóa việc phát triển ...


3

Nếu bạn sử dụng Java như một ngôn ngữ cú pháp và tránh các thư viện JDK của nó, nó có thể nhanh như một ngôn ngữ không được biên dịch. GC không phù hợp với các hệ thống thời gian thực, nhưng có thể phát triển các hệ thống trong Java mà không để lại bất kỳ rác nào. Kết quả là GC không bao giờ kích hoạt.

Chúng tôi tin rằng ngôn ngữ và nền tảng Java có nhiều lợi thế so với C / C ++ và chúng tôi đã phát triển và đánh giá một số thành phần Java có độ trễ cực thấp để chứng minh điều đó. Chúng ta nói về các kỹ thuật để làm như vậy trong bài viết này: Phát triển Java mà không cần GC .


2
Có người thu gom rác phù hợp với hệ thống thời gian thực. Trình thu thập mặc định của JVM có thể không, nhưng điều đó không có nghĩa là nói chung, GC không phù hợp với thời gian thực. Nhưng đồng bằng malloc/freekhông phù hợp với thời gian thực vì thời gian phân bổ không bị ràng buộc do phân mảnh.
Doval

1
Chúng tôi ủng hộ việc sử dụng nhóm đối tượng nhanh cho mọi thứ để không xảy ra phân bổ sau khi khởi động.
rdalmeida

2

LMAX là một Thư viện nhắn tin liên chủ đề hiệu suất cao.

Để có ích, người khác phải viết mã để nhận từng luồng để thực hiện công việc hữu ích. Cho rằng mã rất có thể là bằng Java hoặc C # và sau đó có rất ít lựa chọn ngôn ngữ có giao diện tốt với chúng.

Sử dụng C hoặc C ++ không phải là một lựa chọn tốt trừ khi bạn muốn giới hạn người dùng của mình trong một HĐH duy nhất, vì không có mô hình luồng nào được xác định trong chúng.

Java là tiêu chuẩn cho rất nhiều sự phát triển phần mềm ngày nay, vì vậy trừ khi bạn có lý do chính đáng khác, nó có xu hướng là lựa chọn tốt nhất. (Khi ở Rôma, hãy làm như người Rôma…)

Viết phần mềm hiệu suất cao bằng Java (hoặc C #) thường được thực hiện để chứng minh một điểm điểm


1
Chuẩn C ++ 11 mới hỗ trợ đa luồng ...
Casey

@Casey, và có bao nhiêu trình biên dịch C ++ trong thế giới thực sử dụng nó? Và những trình biên dịch này có giá bao nhiêu. Có thể trong 20 năm nữa, nó sẽ hữu ích, cho đến lúc đó bạn không thể phụ thuộc vào nó.
Ian

Disruptor sử dụng sun.misc.Unsafe khá một chút cho thấy rằng bạn thực sự không thể viết mã có độ trễ thấp trong Java mà không nhúng ngón chân vào vùng đất C
James

3
Gcc hỗ trợ các luồng C ++ và nó miễn phí
James

@Ian: 2 năm sau và tất cả các trình biên dịch được sử dụng chung đều hỗ trợ nó;). Ngay cả những người miễn phí.
Rutix
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.