본문 바로가기

java

맵리듀스에서 RDBMS로 인서트 시 GC overhead limit exceeded Issue

맵리듀스에서 리듀스 출력결과를 RDBMS로 저장 시 GC overhead limit exceeded Issue가 발생한다.

해당 Issue는 리듀스 출력결과가 즉 RDBMS로 저장되어야 하는 데이터가 많은 경우 발생하게 된다.


맵리듀스에서 RDBMS로 Insert하기 위해 org.apache.hadoop.mapreduce.lib.db.DBOutputFormat(링크)를 

사용한다. 해당 소스를 까보면 리듀스 출력결과로 Insert문자열을 생성하여 addBatch()로 보관 후 DB Connection이 close될때 executeBatch()가 실행되고 commit()이 실행된다. 즉 대량의 데이터가 한번에 Insert되는 것이다.

해당 Issue와 관련해서 Cloudera블로그에도 관련 글이 존재한다. (링크)


이 문제를 해결하기 위해 DBOutputFormat을 상속받아 삽질을 했으나 해결방법은 의외로 간단하다.


    public static final int batchSize = 5000;
    public static int count = 0;

    public static class DBOutputWritable implements Writable, DBWritable {
        String col1, col2;

        public DBOutputWritable(String col1, String col2) {
            this.col1 = col1;
            this.col2 = col2;
        }

        public void readFields(DataInput in) throws IOException {}

        public void readFields(ResultSet rs) throws SQLException {
            col1 = rs.getString(1);
            col2 = rs.getString(2);
        }

        public void write(DataOutput out) throws IOException {}

        public void write(PreparedStatement ps) throws SQLException {
            ps.setString(1,col1);
            ps.setString(2,col1);
            
            if(++count % batchSize == 0) {
                ps.executeBatch();
                count=0;
            }
           
        }
    }
DBOutputWritable에서 write메소드에서 데이터 단위를 나누어 주면된다. 

끝.