Java 性能検証（簡易ETL編）

### 本記事の目的
[Amazon Athena性能検証（簡易ETL編）](https://qiita.com/thashi/items/cbbc33b03608be2da2d9)
[Amazon Redshift Serverless性能検証（簡易ETL編）](https://qiita.com/thashi/items/56f180b89c4a8afb8f37?fbclid=IwAR1Yv7qJbVwAfB2FouuJw10O24EKAyq-Uu0HUyCjpE5v62nNY-LuzMspVGk)

の続編として仮に自作Javaアプリだとどれくらい性能がでるのかを試した。

自作Javaアプリは下記のとおり、AthenaやRedshiftの検証で利用したCSVファイルと同じファイルを読み込み、各カラムデータをtrimやlpadや日付変換やconcatでの列結合等を実装してCSVファイルを出力する。
※本当はこのCSVからS3へのデータコピーまでをトータル時間で評価するのが公正な評価だがここでは省略している。なのでこの結果は自作Javaアプリに有意な数値として理解するのが正しい。

```
public class ConvertData {

    static String delimiter = ",";
    static String inputFile = "data.csv";
    static String outputFile = "data_converted.csv";

    public static void main(String[] args) throws Exception {
        long pid = ProcessHandle.current().pid();
        outputFile = outputFile + "_" + pid;

        long startTime = System.currentTimeMillis();

        File f = new File(inputFile);
        File out = new File(outputFile);

        BufferedReader br = new BufferedReader(new FileReader(f));
        BufferedWriter bw = new BufferedWriter(new FileWriter(out));

        String lineData = br.readLine();
        while (lineData != null) {
            String data[] = lineData.split(delimiter);
            String output = trim(data[0]) + delimiter + dateconvert(data[1]) + delimiter + dateconvert(data[2]) + delimiter
                    + dateconvert(data[3]) + delimiter + data[4] + delimiter + concat(lpad(data[5], 7, "0"), lpad(data[6], 7, "0"));

            try {
                bw.write(output);
                bw.newLine();
            } catch(Exception ex) {
                ex.printStackTrace();
            }
            lineData = br.readLine();
        }
        br.close();
        bw.close();

        long endTime = System.currentTimeMillis();
        System.out.println("実行時間：" + (endTime - startTime) + "msec");
    }

    public static String trim(String input) {
        return input.trim();
    }

    public static String concat(String input1, String input2) {
        return input1 + input2;
    }

    public static String lpad(String input, int length, String padding) {
        int paddingLength;
        String output = "";
        if (input.length() < length) {
            paddingLength = length - input.length();
            for (int i = 0; i < paddingLength; i++) {
                output = padding + output;
            }
            output = output + input;
        } else {
            // no padding.
            output = input;
        }
        return output;
    }

    public static String dateconvert(String input) {
        if (input == null || input.equals("") || input.length() != 8) {
            return "0001-01-01";
        } else if (input.equals("99999999")) {
            return "9999-12-31";
        } else {
            if (!isDate(input)) {
                return "0001-01-01";
            } else {
                return input.substring(0, 4) + "-" + input.substring(4, 6) + "-" + input.substring(6);
            }
        }
    }

    /**
     * 日付チェック.
     * 
     * 
     * @param value 検証対象の値
     * @return 結果（true：日付、false：日付ではない）
     */
    public static boolean isDate(String value) {
        boolean result = false;
        try {

            if (value != null) {
                String checkDate = value.replace("-", "").replace("/", "");
                DateTimeFormatter.ofPattern("uuuuMMdd").withResolverStyle(ResolverStyle.STRICT).parse(checkDate,
                        LocalDate::from);
                result = true;
            }
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

}
```

### 実行結果
- 動作検証環境はC5.4xlarge。
- java-17-amazon-corretto.x86_64
- 16vcpu、32GBメモリ、ネットの最大10GBps　ディスク4,750MB/sec

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325048/e531fa90-05c0-87e0-74b7-3a37994bbd8e.png)

Javaの作りについては、行データ読み込み⇒行データ変換⇒行データ書き込みをシーケンシャル実行しているため改善の余地はあるものの、Athena(S3)の多重実行環境下でのスループットの伸びが際立つ結果となった。Athenaについては、緩和申請でアカウント単位での同時実行数を最大にしてどこまでスループットが伸びるのかを実案件の中で評価したい。
Java(XFS)についてはOS⇒S3処理が加わることによる性能劣化を加味したうえでサイジングが必要。おそらく578MB/sec程度の性能を出すためにはC5.4xlargeを4台並べる必要があり、ノード間でのタスク分散とインスタンス障害発生時のタスクコントロールも含めて設計・実装が必要になる。
バッチウィンドウサイズ的に多案比較で最も悪く（平均時間が最も悪い）、経費観点においても高いインスタンスで経費を垂れ流すため避けるべき案として評価。