プロジェクトのgithubアドレス:bitcarmanlee easy-algorithm-interview-and-practice
誰もがスターを付け、メッセージを残し、一緒に学び、進歩することを歓迎します
1.発生した問題
実際のデータ分析プロセスでは、統計のために直近の年のデータを取得する必要があり、1年のデータは日ごとに分割されます。
val ymdSet = TimeUtils.genYmdSet(beginYmd, endYmd) // 获取过去一年时间的日期
var rdd = SparkIo.readThriftParquetFile(spark.sparkContext, pathxxx, classOf[xxx])
for(eachYmd <- ymdSet) {
val tmppath = PathUtils.xxx + eachYmd
val tmprdd = SparkIo.readThriftParquetFile(spark.sparkContext, tmppath, classOf[xxx])
rdd = rdd.union(tmprdd)
}
rdd
上記のコードロジックは比較的明確です。日次データに従って一時的なrddを生成し、次にrddを元のrddに継続的に結合して、最終年のデータを取得します。
過去7日間のデータのみを分析対象として選択した場合、上記のコードは問題なく正常に実行できます。コードによって読み取られたデータが過去1年になると、例外がスローされます
ERROR executor.Executor: Exception in task 28.0 in stage 0.0 (TID 28)
java.lang.StackOverflowError
at java.lang.Exception.<init>(Exception.java:102)
at java.lang.ReflectiveOperationException.<init>(ReflectiveOperationException.java:89)
at java.lang.reflect.InvocationTargetException.<init>(InvocationTargetException.java:72)
at sun.reflect.GeneratedSerializationConstructorAccessor13.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at java.io.ObjectStreamClass.newInstance(ObjectStreamClass.java:967)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1782)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1706)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1344)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
......
2.理由分析
例外的な観点からは、java.io.ObjectInputStreamシリアル化を使用する場合の無限ループが原因です。
前の現象を組み合わせると、データが7日であれば問題ありませんが、1年間のデータファイル数が多すぎてスタック容量が不足するなどの理由で、1年間のデータが異常になります。継続的な結合プロセスにより、rddの系統が長くなりすぎ、最終的にスタックスペースが不足しました。和集合演算が実行されるたびに、系統のステップサイズが1ずつ増加するためです。
3.解決策
問題が特定されたので、解決策が出てきます。2つの方法しかありません
。1。スタックスペースを増やします。
2.系統の長さを減らします。
スタックスペースを増やすことは症状の解決策ですが、根本的な原因ではありません。クラスターのリソースは常に限られており、一度に処理するデータが多すぎることは常に隠れた危険であるため、2番目の解決策が最終的に採用されました。系統の長さを減らします。
特定の実装も比較的簡単です
def genrdd(startYmd: String, endYmd: String) = {
val ymdSet = TimeUtils.genYmdSet(beginYmd, endYmd) // 获取过去一段时间的日期
var rdd = SparkIo.readThriftParquetFile(spark.sparkContext, pathxxx, classOf[xxx])
for(eachYmd <- ymdSet) {
val tmppath = PathUtils.xxx + eachYmd
val tmprdd = SparkIo.readThriftParquetFile(spark.sparkContext,tmppath,classOf[xxx])
rdd = rdd.union(tmprdd)
}
rdd
}
まず、rddを生成するロジックをメソッドにカプセル化します。メソッドのパラメーターは、開始時間と終了時間です。
次に、たとえば1年の期間をそれぞれ3か月の4つのセグメントに分割し、それぞれ開始時刻と終了時刻を取得します。
最後に、メソッドを4回呼び出し、最後に結合すると、1年間のデータを正常にマージできます。