Spark java.lang.OutOfMemoryError: không gian heap Java


228

Cụm của tôi: 1 chủ, 11 nô lệ, mỗi nút có bộ nhớ 6 GB.

Cài đặt của tôi:

spark.executor.memory=4g, Dspark.akka.frameSize=512

Đây là vấn đề:

Đầu tiên , tôi đọc một số dữ liệu (2,19 GB) từ HDFS sang RDD:

val imageBundleRDD = sc.newAPIHadoopFile(...)

Thứ hai , làm một cái gì đó trên RDD này:

val res = imageBundleRDD.map(data => {
                               val desPoints = threeDReconstruction(data._2, bg)
                                 (data._1, desPoints)
                             })

Cuối cùng , xuất ra HDFS:

res.saveAsNewAPIHadoopFile(...)

Khi tôi chạy chương trình của mình, nó hiển thị:

.....
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:24 as TID 33 on executor 9: Salve7.Hadoop (NODE_LOCAL)
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:24 as 30618515 bytes in 210 ms
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:36 as TID 34 on executor 2: Salve11.Hadoop (NODE_LOCAL)
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:36 as 30618515 bytes in 449 ms
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Starting task 1.0:32 as TID 35 on executor 7: Salve4.Hadoop (NODE_LOCAL)
Uncaught error from thread [spark-akka.actor.default-dispatcher-3] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[spark]
java.lang.OutOfMemoryError: Java heap space

Có quá nhiều nhiệm vụ?

PS : Mọi thứ đều ổn khi dữ liệu đầu vào khoảng 225 MB.

Làm thế nào tôi có thể giải quyết vấn đề này?


Làm thế nào để chạy tia lửa? Có phải từ bàn điều khiển? hoặc bạn sử dụng tập lệnh triển khai nào?
Tombart

Tôi sử dụng sbt để biên dịch và chạy ứng dụng của mình. Gói sbt sau đó chạy sbt. Tôi đã thực hiện cùng một chương trình trên hadoop một tháng trước và tôi đã gặp cùng một vấn đề của OutOfMemoryError, nhưng trong hadoop có thể dễ dàng giải quyết bằng cách tăng giá trị của mapred.child.java.opts từ Xmx200m lên Xmx400m. Spark có bất kỳ cài đặt jvm nào cho các tác vụ của nó không? Tôi tự hỏi liệu spark.executor.memory có cùng ý nghĩa như mapred.child.java.opts trong hadoop không. Trong chương trình của tôi, spark.executor.memory đã được giải quyết tới 4g lớn hơn nhiều so với Xmx400m trong hadoop. Cảm ơn bạn ~
hequn8128

Là ba bước bạn đề cập đến những người duy nhất bạn làm? Kích thước của dữ liệu được tạo bởi (data._1, desPoints) - điều này sẽ phù hợp với bộ nhớ đặc biệt nếu dữ liệu này sau đó được chuyển sang giai đoạn khác
Arnon Rotem-Gal-Oz

1
Cấu hình bộ nhớ cho trình điều khiển là gì? Kiểm tra máy chủ nào nhận được lỗi bộ nhớ. Đây có phải là trình điều khiển hoặc một trong những người thực hiện.
RanP

Xem ở đây tất cả các thuộc tính cấu hình: spark.apache.org/docs/2.1.0/configuration.html
Naramsim

Câu trả lời:


364

Tôi có một vài gợi ý:

  • Nếu các nút của bạn được cấu hình để có tối đa 6g cho Spark (và để lại một chút cho các quy trình khác), thì hãy sử dụng 6g thay vì 4g , spark.executor.memory=6g. Đảm bảo bạn đang sử dụng càng nhiều bộ nhớ càng tốt bằng cách kiểm tra UI (nó sẽ cho biết bạn đang sử dụng bao nhiêu mem)
  • Hãy thử sử dụng nhiều phân vùng hơn, bạn nên có 2 - 4 cho mỗi CPU. IME tăng số lượng phân vùng thường là cách dễ nhất để làm cho chương trình ổn định hơn (và thường nhanh hơn). Đối với lượng dữ liệu khổng lồ bạn có thể cần nhiều hơn 4 cho mỗi CPU, tôi đã phải sử dụng 8000 phân vùng trong một số trường hợp!
  • Giảm tỷ lệ bộ nhớ dành riêng cho bộ nhớ đệm , sử dụng spark.storage.memoryFraction. Nếu bạn không sử dụng cache()hoặc persisttrong mã của mình, thì đây cũng có thể là 0. Mặc định là 0,6, có nghĩa là bạn chỉ nhận được 0,4 * 4g bộ nhớ cho heap của mình. IME giảm mem frac thường làm cho các OOM biến mất. CẬP NHẬT: Từ spark 1.6 rõ ràng chúng ta sẽ không còn cần phải chơi với các giá trị này, spark sẽ tự động xác định chúng.
  • Tương tự như trên nhưng phân đoạn bộ nhớ xáo trộn . Nếu công việc của bạn không cần nhiều bộ nhớ xáo trộn thì hãy đặt nó ở giá trị thấp hơn (điều này có thể khiến các xáo trộn của bạn tràn ra đĩa có thể ảnh hưởng nghiêm trọng đến tốc độ). Đôi khi, khi hoạt động xáo trộn đó là OOMing, bạn cần phải làm ngược lại, tức là đặt nó thành một cái gì đó lớn, như 0,8 hoặc đảm bảo rằng bạn cho phép các xáo trộn của mình tràn vào đĩa (đó là mặc định kể từ 1.0.0).
  • Cảnh giác với rò rỉ bộ nhớ , những điều này thường xảy ra do vô tình đóng cửa các đối tượng bạn không cần trong lambdas của bạn. Cách chẩn đoán là tìm ra "tác vụ được tuần tự hóa dưới dạng byte byte" trong nhật ký, nếu XXX lớn hơn vài k hoặc nhiều hơn MB, bạn có thể bị rò rỉ bộ nhớ. Xem https://stackoverflow.com/a/25270600/1586965
  • Liên quan đến ở trên; sử dụng các biến quảng bá nếu bạn thực sự cần các đối tượng lớn.
  • Nếu bạn đang lưu trữ các RDD lớn và có thể hy sinh một số thời gian truy cập, hãy xem xét việc tuần tự hóa RDD http://spark.apache.org/docs/latest/tuning.html#serialized-rdd-st Storage . Hoặc thậm chí lưu trữ chúng trên đĩa (đôi khi điều đó không tệ nếu sử dụng SSD).
  • ( Nâng cao ) Liên quan đến ở trên, tránh Stringvà các cấu trúc lồng nhau nặng nề ( Mapcác lớp trường hợp thích và lồng nhau). Nếu có thể hãy cố gắng chỉ sử dụng các kiểu nguyên thủy và lập chỉ mục cho tất cả các kiểu không nguyên thủy, đặc biệt nếu bạn mong đợi rất nhiều bản sao. Chọn WrappedArraycác cấu trúc lồng nhau bất cứ khi nào có thể. Hoặc thậm chí triển khai tuần tự hóa của riêng bạn - BẠN sẽ có nhiều thông tin nhất về cách sao lưu dữ liệu của bạn thành byte một cách hiệu quả, SỬ DỤNG CNTT !
  • ( bit hacky ) Một lần nữa khi lưu vào bộ đệm, hãy xem xét sử dụng a Datasetđể lưu cấu trúc của bạn vì nó sẽ sử dụng tuần tự hóa hiệu quả hơn. Điều này nên được coi là một hack khi so sánh với các gạch đầu dòng trước đó. Xây dựng kiến ​​thức tên miền của bạn thành algo / serialization của bạn có thể giảm thiểu bộ nhớ / bộ nhớ cache khoảng 100 lần hoặc 1000 lần, trong khi tất cả những gì Datasetcó thể sẽ cung cấp là 2x - 5x trong bộ nhớ và 10 lần nén (sàn gỗ) trên đĩa.

http://spark.apache.org/docs/1.2.1/configuration.html

EDIT: (Vì vậy tôi có thể tự google dễ dàng hơn) Sau đây cũng là dấu hiệu của vấn đề này:

java.lang.OutOfMemoryError : GC overhead limit exceeded

Cảm ơn lời đề nghị của bạn ~ Nếu tôi đặt spark.executor.memory = 6g, spark sẽ gặp vấn đề: "kiểm tra giao diện người dùng cụm của bạn để đảm bảo rằng các công nhân đã được đăng ký và có đủ bộ nhớ". Đặt spark.st Storage.memoryFraction thành 0,1 cũng không thể giải quyết vấn đề. Có lẽ vấn đề nằm ở mã của tôi. Cảm ơn bạn!
hequn8128

2
@samthebest Đây là một câu trả lời tuyệt vời. Tôi thực sự đánh giá cao sự giúp đỡ đăng nhập để tìm rò rỉ bộ nhớ.
Myles Baker

1
Xin chào @samthebest, bạn đã chỉ định 8000 phân vùng như thế nào? Vì tôi đang sử dụng Spark sql, tôi chỉ có thể chỉ định phân vùng bằng spark.sql.shuffle.partitions, giá trị mặc định là 200 nên tôi đã đặt nó thành 1000, tôi đã cố gắng đặt nó thành 1000 nhưng không giúp nhận được OOM, bạn có biết điều gì là tối ưu không giá trị phân vùng Tôi có dữ liệu sai lệch 1 TB để xử lý và nó liên quan đến nhóm bằng các truy vấn trung tâm. Xin hướng dẫn.
Umesh K

2
Xin chào @ user449355 xin vui lòng bạn có thể hỏi một câu hỏi mới? Vì sợ bắt đầu một chuỗi nhận xét dài :) Nếu bạn gặp vấn đề, rất có thể người khác đang gặp phải, và một câu hỏi sẽ giúp bạn dễ dàng tìm thấy hơn cho tất cả.
samthebest

1
Đến điểm đầu tiên của bạn, @samthebest, bạn không nên sử dụng TẤT CẢ bộ nhớ spark.executor.memoryvì bạn chắc chắn cần một lượng bộ nhớ cho chi phí I / O. Nếu bạn sử dụng tất cả, nó sẽ làm chậm chương trình của bạn. Ngoại lệ cho điều này có thể là Unix, trong trường hợp bạn có không gian hoán đổi.
Hunle

58

Để thêm một trường hợp sử dụng để điều này mà thường không được thảo luận, tôi sẽ đặt ra một giải pháp khi nộp một Sparkứng dụng thông qua spark-submittại địa phương chế độ.

Theo cuốn sách về Làm chủ Apache Spark của Jacek Laskowski :

Bạn có thể chạy Spark ở chế độ cục bộ. Trong chế độ triển khai JVM đơn không phân tán này, Spark sinh ra tất cả các thành phần thực thi - trình điều khiển, trình thực thi, phụ trợ và chủ - trong cùng một JVM. Đây là chế độ duy nhất mà trình điều khiển được sử dụng để thực thi.

Vì vậy, nếu bạn đang gặp OOMlỗi với heap, nó đủ để điều chỉnh driver-memorythay vì executor-memory.

Đây là một ví dụ:

spark-1.6.1/bin/spark-submit
  --class "MyClass"
  --driver-memory 12g
  --master local[*] 
  target/scala-2.10/simple-project_2.10-1.0.jar 

Bao nhiêu phần trăm chúng ta nên xem xét cho bộ nhớ trình điều khiển trong chế độ độc lập.
Yashwanth Kambala

@Brian, Ở chế độ cục bộ, bộ nhớ trình điều khiển có cần lớn hơn kích thước dữ liệu đầu vào không? Có thể chỉ định số lượng phân vùng cho tập dữ liệu đầu vào, vì vậy công việc Spark có thể xử lý tập dữ liệu lớn hơn nhiều so với RAM có sẵn?
fuyi

19

Bạn nên cấu hình cài đặt bộ nhớ offHeap như hiển thị bên dưới:

val spark = SparkSession
     .builder()
     .master("local[*]")
     .config("spark.executor.memory", "70g")
     .config("spark.driver.memory", "50g")
     .config("spark.memory.offHeap.enabled",true)
     .config("spark.memory.offHeap.size","16g")   
     .appName("sampleCodeForReference")
     .getOrCreate()

Cung cấp bộ nhớ trình điều khiển và bộ nhớ thực thi theo khả năng RAM máy của bạn. Bạn có thể tăng kích thước offHeap nếu bạn vẫn gặp phải vấn đề OutofMemory .


Đã thêm cài đặt offHeap giúp
kennyut

2
thiết lập bộ nhớ trình điều khiển trong mã của bạn sẽ không hoạt động, hãy đọc tài liệu về tia lửa cho việc này: Các thuộc tính của Spark chủ yếu có thể được chia thành hai loại: một loại có liên quan đến việc triển khai, như là Spark spark.driver.memory,, spark spark.executor.instances tựa, loại thuộc tính này có thể không bị ảnh hưởng khi cài đặt lập trình thông qua SparkConf trong thời gian chạy hoặc hành vi phụ thuộc vào trình quản lý cụm và chế độ triển khai mà bạn chọn, do đó sẽ được đề xuất để đặt qua tệp cấu hình hoặc tùy chọn dòng lệnh tia lửa.
Abdulhafeth Sartawi

1
TRẢ LỜI TỐT NHẤT! Vấn đề của tôi là Spark không được cài đặt tại nút chính, tôi chỉ sử dụng PySpark để kết nối với HDFS và gặp lỗi tương tự. Sử dụng configgiải quyết vấn đề.
Mikhail_Sam

Tôi vừa thêm các cấu hình bằng lệnh spark-submit để khắc phục vấn đề kích thước heap. Cảm ơn.
Pritam Sadhukhan

16

Bạn nên tăng bộ nhớ trình điều khiển. Trong thư mục $ SPARK_HOME / conf của bạn, bạn nên tìm tệp spark-defaults.conf, chỉnh sửa và đặt spark.driver.memory 4000mtùy thuộc vào bộ nhớ trên chủ của bạn, tôi nghĩ vậy. Đây là những gì đã khắc phục vấn đề cho tôi và mọi thứ chạy trơn tru


Có bao nhiêu phần trăm mem được phân bổ, độc lập
Yashwanth Kambala

14

Hãy xem các tập lệnh khởi động, kích thước heap Java được đặt ở đó, có vẻ như bạn không cài đặt tập lệnh này trước khi chạy Spark worker.

# Set SPARK_MEM if it isn't already set since we also use it for this process
SPARK_MEM=${SPARK_MEM:-512m}
export SPARK_MEM

# Set JAVA_OPTS to be able to load native libraries and to set heap size
JAVA_OPTS="$OUR_JAVA_OPTS"
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$SPARK_LIBRARY_PATH"
JAVA_OPTS="$JAVA_OPTS -Xms$SPARK_MEM -Xmx$SPARK_MEM"

Bạn có thể tìm tài liệu để triển khai các tập lệnh ở đây .


Cảm ơn bạn ~ tôi sẽ thử sau. Từ spark ui, nó hiển thị bộ nhớ của mỗi người thực thi là 4096. Vì vậy, cài đặt đã được bật, phải không?
hequn8128

Xem câu trả lời của bạn trong khi tôi đang đối mặt với vấn đề tương tự ( stackoverflow.com/questions/34762432/ săn ). Nhìn vào liên kết bạn cung cấp có vẻ như cài đặt Xms / Xmx không còn nữa, bạn có thể cho biết tại sao không?
Seffy

Nội dung tại tập lệnh được liên kết đến bởi start up scriptskhông may thay đổi. Không có lựa chọn nào như vậy tồn tại kể từ 2019-12-19
David Groomes

7

Tôi đã chịu đựng vấn đề này rất nhiều, chúng tôi sử dụng phân bổ tài nguyên động và tôi nghĩ rằng nó sẽ sử dụng tài nguyên cụm của tôi để phù hợp nhất với ứng dụng.

Nhưng sự thật là, phân bổ tài nguyên động không đặt bộ nhớ trình điều khiển và nó giữ cho giá trị mặc định là 1g.

Tôi đã giải quyết nó bằng cách đặt spark.driver.memory thành một số phù hợp với bộ nhớ trình điều khiển của tôi (đối với ram 32gb tôi đặt nó thành 18gb)

bạn có thể thiết lập nó bằng lệnh spark submit như sau:

spark-submit --conf spark.driver.memory=18gb ....cont

Lưu ý rất quan trọng, thuộc tính này sẽ không được xem xét nếu bạn đặt nó từ mã, theo tài liệu tia lửa:

Các thuộc tính của Spark chủ yếu có thể được chia thành hai loại: một loại có liên quan đến việc triển khai, như là Spark spark.driver.memory,, spark spark.executor.instances, loại tài sản này có thể không bị ảnh hưởng khi cài đặt lập trình thông qua SparkConf trong thời gian chạy, hoặc hành vi phụ thuộc vào trình quản lý cụm và chế độ triển khai mà bạn chọn, do đó, sẽ được đề xuất đặt qua tệp cấu hình hoặc tùy chọn dòng lệnh spark-submit; một cái khác chủ yếu liên quan đến điều khiển thời gian chạy Spark, như là Spark spark.task.maxFailures, loại tài sản này có thể được thiết lập theo bất kỳ cách nào.


2
Bạn nên sử dụng --conf spark.driver.memory = 18g
merenptah 29/03/19

5

Nói rộng hơn, bộ nhớ JVM của Executor có thể được chia thành hai phần. Bộ nhớ Spark và bộ nhớ người dùng. Điều này được kiểm soát bởi thuộc tính spark.memory.fraction- giá trị nằm trong khoảng từ 0 đến 1. Khi làm việc với hình ảnh hoặc xử lý nhiều bộ nhớ trong các ứng dụng tia lửa, hãy xem xét giảm spark.memory.fraction. Điều này sẽ làm cho nhiều bộ nhớ hơn có sẵn cho ứng dụng của bạn hoạt động. Spark có thể tràn ra, vì vậy nó vẫn sẽ hoạt động với ít bộ nhớ chia sẻ hơn.

Phần thứ hai của vấn đề là phân chia công việc. Nếu có thể, hãy phân vùng dữ liệu của bạn thành các phần nhỏ hơn. Dữ liệu nhỏ hơn có thể cần ít bộ nhớ hơn. Nhưng nếu điều đó là không thể, bạn đang hy sinh tính toán cho bộ nhớ. Thông thường, một người thực thi sẽ chạy nhiều lõi. Tổng bộ nhớ của người thi hành phải đủ để xử lý các yêu cầu bộ nhớ của tất cả các tác vụ đồng thời. Nếu tăng bộ nhớ thực thi không phải là một tùy chọn, bạn có thể giảm lõi cho mỗi người thực thi để mỗi tác vụ có thêm bộ nhớ để làm việc. Kiểm tra với 1 nhân viên thực thi có bộ nhớ lớn nhất bạn có thể cung cấp và sau đó tiếp tục tăng số lõi cho đến khi bạn tìm thấy số lượng lõi tốt nhất.


5

Bạn đã đổ nhật ký gc chủ của bạn? Vì vậy, tôi đã gặp vấn đề tương tự và tôi thấy SPARK_DRIVER_MEMORY chỉ đặt heap Xmx. Kích thước heap ban đầu vẫn là 1G và kích thước heap không bao giờ mở rộng đến heap Xmx.

Vượt qua "--conf" spark.driver.extraJavaOptions = -Xms20g "giải quyết vấn đề của tôi.

ps phụ | grep java và bạn sẽ thấy nhật ký theo dõi: =

24501 30.7 1.7 41782944 2318184 pts / 0 Sl + 18:49 0:33 / usr / java / mới nhất / bin / java -cp / opt / spark / conf /: / opt / spark / jars / * -Xmx30g -Xms20g


3

Vị trí để đặt kích thước heap bộ nhớ (ít nhất là trong spark-1.0.0) là trong conf / spark-env. Các biến có liên quan là SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY. Nhiều tài liệu hơn trong hướng dẫn triển khai

Ngoài ra, đừng quên sao chép tệp cấu hình vào tất cả các nút nô lệ.


4
Làm thế nào để bạn biết cái nào cần điều chỉnh giữa SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY?
Hunle

13
tức là lỗi nào sẽ bảo bạn tăng SPARK_EXECUTOR_MEMORY, và lỗi nào sẽ bảo bạn tăng SPARK_DRIVER_MEMORY?
Hunle

2

Tôi có một vài lỗi cho các lỗi đã đề cập ở trên.

● Kiểm tra bộ nhớ của người thực thi được chỉ định là người thực thi có thể phải xử lý các phân vùng cần nhiều bộ nhớ hơn so với phân bổ.

● Hãy thử xem có thêm các xáo trộn nào không vì các xáo trộn là các hoạt động đắt tiền vì chúng liên quan đến I / O của đĩa, tuần tự hóa dữ liệu và I / O mạng

● Sử dụng chương trình phát sóng

● Tránh sử dụng groupByKeys và cố gắng thay thế bằng GiảmByKey

● Tránh sử dụng các Đối tượng Java khổng lồ ở bất cứ nơi nào xáo trộn


Xin lỗi để chiếm quyền điều khiển truy vấn của người khác nhưng làm thế nào để sử dụng lessByKey trên groupBy?
Somil Aseeja

1

Theo hiểu biết của tôi về mã được cung cấp ở trên, nó tải tệp và thực hiện thao tác ánh xạ và lưu lại. Không có hoạt động đòi hỏi phải xáo trộn. Ngoài ra, không có thao tác nào yêu cầu dữ liệu được đưa đến trình điều khiển do đó điều chỉnh mọi thứ liên quan đến xáo trộn hoặc trình điều khiển có thể không có tác động. Trình điều khiển có vấn đề khi có quá nhiều nhiệm vụ nhưng điều này chỉ đến phiên bản Spark 2.0.2. Có thể có hai điều đang đi sai.

  • Chỉ có một hoặc một vài người thi hành. Tăng số lượng người thi hành để họ có thể được phân bổ cho các nô lệ khác nhau. Nếu bạn đang sử dụng sợi cần thay đổi cấu hình num-execors hoặc nếu bạn đang sử dụng spark độc lập thì cần điều chỉnh lõi num trên mỗi bộ thực thi và spark max lõi conf. Trong thực thi num độc lập = lõi tối đa / lõi trên mỗi người thực thi.
  • Số lượng phân vùng rất ít hoặc có thể chỉ có một. Vì vậy, nếu mức này thấp ngay cả khi chúng ta có nhiều lõi, thì nhiều bộ thực thi sẽ không giúp ích nhiều vì sự song song phụ thuộc vào số lượng phân vùng. Vì vậy, tăng các phân vùng bằng cách thực hiện imageBundleRDD.repartition (11)

0

Đặt các cấu hình chính xác này đã giúp giải quyết vấn đề.

spark-submit --conf spark.yarn.maxAppAttempts=2 --executor-memory 10g --num-executors 50 --driver-memory 12g
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.