[TIL - 1020] 병렬처리 API, MySQL 엔진/스토리지 엔진, replication 개념, 롤백하려면 어디에 저장?

java

병렬로 연산하기

  • ExecutorService API
    • 쓰레드풀에 일정 개수의 쓰레드를 만들어두고 처리하는 방식의 API : limit 개수만큼 동시에 처리함
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Future<String>> results = new ArrayList<>();
for (int i = 0; i < 30; i++) {
    results.add(executor.submit() -> {
        Thread.sleep(5000);
        return Thread.getCurrrentName() + ", end time : " + LocalDateTime.now();
    });    
}

for (Future<String> result : results) {
    System.out.println(result.get());
}

executor.shutdown();
  • Stream API(java8)
    • 하나의 task를 여러개 task로 쪼개고, 처리한 후 하나로 합치는 형태로 처리 : ForkJoin Framework(Pool) - ForkJoinPool은 ExecutorService 구현체
    • 노는 CPU가 없도록 하는 알고리즘이 적용되어있음 : 각각이 내부적으로 queue가 생성되고 task를 처리함, 자신의 task가 모두 처리된 경우 다른 task를 가지고 올 수 있음
Stream.iterate(1L, i -> i + 1)
        .limit(limit)
        .parallel()
        .reduce(0L, Long::sum);

병렬처리와 순차처리 비교, 주의해야할 점

  1. task가 독립적이지 않다면 오히려 성능 저하될 가능성(각각이 서로에 영향을 미치는 경우) : 아래의 예의 경우 전 연산이 현재 연산 결과에 영향을 미칠 수 있음(연관된)
  2. 특정 메소드를 사용할 때만 사용할 것 : iterate()의 경우 boxing 객체 생성(primitive -> object) -> 연산을 위해 unboxing() 해야
    • 아래의 예제코드의 iterate가 순차처리 메소드 : 하나씩 어떤 처리를 하는 것(무한스트림 생성)
    • Boxing된 객체를 unboxing해서 연산하도록 처리하는 것이 비효율적이라는 것도 알아갑니다! : iterate가 아닌 IntStream/LongStream과 같은 API 사용하기
  3. 내부적으로 queue를 만들어내서 task를 처리 : 그만큼 비용이 든다는 이야기 같음 - 무작정 사용하는 것이 사용해서 얻는 성능 이점보다 잃는 것이 많을 수 있다는 위험
long start = System.currentTimeMillis();
long result = Stream.iterate(1L, i -> i + 1)
        .limit(limit)
        //parallel()
        .reduce(0L, Long::sum);

System.out.println(((System.currentTimeMillis() - start) / 1000) + "초");
return result;

병렬처리 : 20초
순차처리 : 1초

mysql

용어 정리

  • 데이터베이스(schema) : 테이블 컨테이너(단지 담는 역할)
    • MySQL에서는 schema와 database는 동의어 : MsSQL(sql-server)에서는 schema가 database 보다 하위 컨테이너
  • 쿼리 종류
    1. DDL : 데이터베이스/테이블/스토어드 프로시져 생성, 변경 작업 쿼리(CREATE, ALTER)
    2. DML : 데이터 조작 쿼리 - SELECT, UPDATE, DELETE, INSERT
    3. DCL : 권한 관련 - GRANT

엔진

  • MySQL 엔진 : 연결을 맞이하고 파싱된 쿼리를 최적의 방법으로 실행되기위해 계획하는 역할(하나의 종류 밖에 없음)
    • 생각하는 담당
  • 스토리지 엔진(핸들러) : 데이터를 저장하고 저장된 데이터를 찾아오는 역할(여러개를 동시에 사용할 수 있고 여러 종류가 있으며, INNODB가 기본 스토리지 엔진)
    • SELECT, INSERT, UPDATE, DELETE 실질적인 데이터 관련 작업은 여기서 담당
    • InnoDB : PK를 기준으로 데이터 클러스터링(저장) - 순서대로 저장, PK를 기준으로 검색은 빠름(클러스터링 인덱스 - 그래서 이런 이름이었군…)
# 테이블 생성 시 스토리지 엔진 지정 가능
> CREATE TABLE test (....) ENGINE=INNODB;

# 기본 스토리지 엔진 조회
> SELECT engine, support FROM information_schema.engines WHERE support='DEFAULT';
+---------+
| support |
+---------+
| InnoDB  |
+---------+
1 row in set (0.00 sec)

replication

  • 시스템 안정성을 위한 복제 작업을 뜻함 : 메인으로 사용하고 있는 master 데이터베이스가 장애를 일으켰을 때 서비스가 중단되는 것을 막기위해 미리 복제해두었다가 서비스를 계속할 수 있도록 하는 것

  • 역할에 따른 권한 제한
    1. master : insert, update, delete
    2. slave : read-only
  • 운영 : 물론 정해져 있는대로 구성하는 것은 아니라 운영 상황에 맞게 조금씩 변형시킬 수 있음
    1. active-active : master 만을 가지고 서비스를 할 수도 있지만 active-active 상태로 만들어 읽기 작업은 slave 데이터베이스에 수정 및 삭제 작업은 master가 하도록 하여 부하 분산(전제 조건은 sync 되어야 한다는 것)
    2. active-stand by : slave 데이터베이스를 오로지 백업용으로만 사용
  • 구축 어떻게 되지? : 바이너리 로그를 활성화해두면 DML(데이터 변경 쿼리), DDL(스키마 변경 쿼리)을 남기고 slave에서 로그를 참조하여 replication 작업을 수행함
    • slave 데이터베이스는 master에 접속하여 로그를 요청하고 받아온 로그를 기록한 후 복제(실행)
    • 로그를 쓰는 것도 자원 소모입니다
  • 구축해보기 : AWS 환경에서 해보기

트랜잭션 roll-back

  • 롤백이 되면 트랜잭션 처리 이전의 상태로 돌아가야하는데, InnoDB는 메모리영역에 UPDATE, DELETE 되기 전의 상태를 저장해둠 : UNDO 로그 영역(메모리)