클린코드 5장(객체와 자료구조), 6장 (오류처리)

JAVA/클린코드|2020. 6. 29. 11:25

 

객체와 자료구조


  • 객체에서 자료를 세세하게 공개하는 것 보다 추상화를 통해 표현하는 것이 더 좋다.
  • 객체는 동작을 공개하고 자료를 숨긴다.
  • 복잡한 시스템을 짜다보면 새로운 함수가 아니라 새로운 자료타입이 필요한 경우가 발생하는데 이 때는 클래스와 객체 지향 기법이 적합하다. 하지만 새로운 함수가 필요하다면 절차지향 코드와 자료구조 형태가 더 적합한 코드이다.

 

 

 

 

오류처리


 

  • 오류를 일일히 처리하는 것보다 차라리 예외를 던저버리는게 더 깔끔하다.
  • 확인된 예외를 처리하기 위해서 하위 메소드에서 throws를 하게되면 상위 메소드에서 이 예외에 대한 명시가 되어야 하기 때문에 하위의 예외 때문에 상위 메소드가 수정되어야 하는 불상사가 발생하기 때문에 수정에 닫혀 있어야 하다는 OCP규칙을 위반한 것이다.
  • 예외에 의미있는 내용을 함께 던져서 의미 파악에 도움이 되게 하라.
  • 에러가 발생하였을 때 null을 반환하는 코드는 일거리를 늘릴 뿐만 아니라 호출자에게 일감을 더 주게 되는 문제가 있다.
  • 에러를 모두 한 곳에서 처리하게 되면 아래와 같이 귀찮게 된다. 이를 매번 open()을 사용하는 곳에서 처리하게 되면 엄청나게 귀찮게 되고 의존성이 있어 하나의 오류가 늘어나게 되면 모든 사용하는 곳에서 처리를 해줘야 한다. 그래서 이를 별도의 클래스를 만들어서 클래스 내부에서 innerPort.open()을 실행시키게 해서 그 곳에서만 에러 내용을 처리해주고 정재된 Exception만 다시 던지게 하는 것도 방법이다.
// 문제
public void open() {
	try { 
		innerPort.open();
	} catch (DeviceResponseException e) {
		...
  } catch (NetworkErrorException e) { 
		...
  } catch (BindingException e) {
    ....
  } catch ....

} 


// 감싸기 클래스 사용
public class LocalPort {

  private ACMEPort innerPort;

  public void open() {
		try { 
			innerPort.open();
		} catch (DeviceResponseException e) {
			// 내부에서 약속된 하나의 에러 패턴을 사용.
			throw new PortDeviceFailuer(e);
	  } catch (NetworkErrorException e) { 
			throw new PortDeviceFailuer(e);
	  } catch (BindingException e) {
			throw new PortDeviceFailuer(e);
	  } catch ....
	  }
	}
}

 

 

 

 

결론

에러처리를 잘못하면 코드가 굉장히 더러워진다. 실제로 많이 경험해봤고 아직도 어렵다. 중요한건 내부에서 발생한 에러로 인해 상위에서 호출하는 함수의 코드가 변해야 하는 OCP 위반 사항을 발생시키지 않도록 하는 것 같다.

댓글()

클린코드 3장 (함수), 4장 (주석)

JAVA/클린코드|2020. 6. 20. 23:04

 

함수


- 함수를 만드는 기본 규칙은 작게 만드는 것!

 

- 함수 내부에 if 문 등의 1단이나 2단 그 이상의 중첩 구조가 발생되면 안된다.

 

- 함수의 활동은 한가지 그 이상을 하지마라.

 

- switch문에 다음과 같이 한가지 작업만 해야한다는 SRP 이론과 코드의 변경이 있으면 안된다는 OCP 규칙을 위반한다. 이를 해결하기 위해서는 다형성을 이용해서 해결해야 한다.

// 문제 코드
public int calEmployeePay(Employee e) {
	switch (e.type) {
		case SALARIED:
			return calculateSalariedPay();
		case HOURLY:
			return calculateHourlyPay();
		case .....
	}
}

// 변경 내용
public interface Employee {
	int calPay();
}


public SalaryEmployee implements Employee {
		
		@Override
		public int calPay() {
				...
		}
}

public int calEmployeePay(Employee e) {
	return e.calPay();
}

- 함수 이름이 길어지더라도 서술적으로 한방에 이해가 가능한 이름이 오히려 더 깔끔하고 좋은 코드다.

  ex) includeSetupAndTeardownPages..

 

- 함수의 인수는 기본적으로 3개 까지가 사실 마지노선이라고 생각하고 그 이상은 절대 오지 않도록 해라. 인수가 있으면 함수 자체를 이해하는데 더 어려움을 겪게 된다.

 

- 인수가 늘어난다면 별도의 인수 객체를 만들어서 묶어서 보내는 게 더 낫다.

  ex) int x, int y ⇒ Point point

 

- 함수의 이름과 인자가 한꺼번에 이해가 가능한 이름에 가장 좋다.

  ex) write(name), assertExpectedEqualsActual(expected, actual)

 

- 함수의 이름과 다른 행위를 함수안에 실행 시키지 마라 ex) checkPassword() 함수내에서 사용자 세션을 초기화 한다거나 하는 행위는 자칫하면 엄청 큰 버그를 일으킬 가능성이 크다.

 

- 에러 코드를 사용하는 것보다는 try catch를 이용해서 에러 코드를 분리하는 것이 좋고, try catch블록은 모든 영역이 아닌 별도 함수내에서 처리하도록 하는 것이 좋다.

 

- 중복된 코드를 계속 양산하지 마라.

- 모든 함수와 함수 내 모든 블록에 입구와 출구는 하나만 존재해야 한다.

 

 

 

 

주석


- 잘 작성된 주석은 이해가 되지만 경솔하고 근거없는 주석은 코드를 더 이해하기 어렵게 만든다.

 

- 주석은 코드로 의도를 표현하지 못해서 실패를 만회하기 위해 적은 코드이다. 그러므로 주석을 달고 있다면 코드를 잘 못 작성한 건 아니지 잘 생각해봐라.

 

- 주석은 언제나 코드를 따라가지 못하기 때문에 언젠가 주석은 코드와 분리되어 고아가 되어버리는 순간이 오기 때문에 조심해야 한다.

 

- 저작권 등의 정보를 알리거나 외부 라이브러리 등의 사용이나 내부 규약으로 인해 어쩔수 없이 사용하는 인자 등의 부분에 대해서 명료한 설명을 위한 주석 또는 결과 값에 대한 결과에 대한 주석 정도는 괜찮다.

 

- 누군가의 공을 달거나 HTML 주석을 위해 사용하거나 근처 코드가 아닌 다른 코드에 대한 주석 등을 다는 이런 코드들은 코드 개선에 시간을 들이는 게 더 낫고 클래스 파일에 바이트나 낭비하지 말아라.

 

 

 

결론

함수

함수는 당연히 나도 의미가 있도록 사용하기 위해서 네이밍에 많은 고민을 하고 있고 같이 일하시는 분들이 잘 이해할 수 있도록 간결하게 만들려고 노력은 하고 있다. 근데 사실 프로젝트가 커지고 하다보면 쉽지 많은 않다. 흑

 

주석

주석은 15년도에 일을 시작했을 때만해도 선배들이나 주변 개발 컨벤션에서 보면 항상 주석을 달라고 되어 있었고 오픈소스로 나와있는 라이브러리들에도 자세한 설명이 기재되어 있었다. 그래서 따라하는 습관을 들였는데 주석이 말한 그대로 코드를 따라가기 어려웠고 어느순간부터는 주석이 도움이 되는게 아니라 오히려 방해가 된다는 생각을 나 또한 들게 되어 지금은 주석대신 코드를 더 명확하게 짜기 위해서 노력하고 있다.

 

 

댓글()

클린코드 1장(깨끗한 코드), 2장 (의미있는 이름)

JAVA/클린코드|2020. 6. 17. 20:39

 

깨끗한 코드


태도

  • 나쁜 코드는 생산성을 떨어트리고 갈수록 생산성 0로 수렴하게 만든다.
  • 일정에 쫓겨서 만든 나쁜 코드를 나중에 고치려는 습관은 버려라. 르블랑의 법칙 대로 나중은 결코 오지 않는다.
  • 핑계될 것 없다 모두 개발자 탓이다.
  • 시간이 없어서 만든 잘못된 코드는 결국 일정을 빠르게 앞당기는 것이 아니라 결국 그 잘못된 코드로 일정을 지연시킨다.

깨끗한 코드란?

  • 논리가 간단해야 한다.
  • 의존성이 줄어 유지보수가 쉬워야 한다.
  • 성능이 최적화 되어 있어야 한다.
  • 오류는 확힐 하게 처리해야 한다.
  • 많은 일을 하지말고 한가지 잘하는 일을 잘하는 코드를 만들어라.
  • 테스트 케이스가 없는 코드는 깨끗한 코드가 아니다.
  • 중복이 없다.
  • 코드를 최대한 줄인다.
  • 지속적으로 나빠지는 코드를 개선한다.

결론

  • 백날 좋은 코드에 대한 이론만 공부해서는 도움이 되지 않는다. 남의 코드를 지켜보고 개선하면서 꾸준히 연습하자.

 

 

의미 있는 이름


  • 의미있는 이름을 지어라.
  • 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많다.
  • 약어를 사용하지 말고 명확한 이름을 기재하라. 비슷한 이름을 사용하지마라. ex) studentAccont, studentAccountNum 두 개 의미가 어떤건지 모호해진다.
  • Info, Data는 a, an과 같은 불용어로써 불분명하니 사용하지 마라.
  • 불용어를 계속 사용하면 중복을 만들게 된다. ex) AccountInfo는 Account와 헷갈리고 BankAccoutData는 BankAccount와 헷갈리게 된다.
  • 단축시키려 하지말고 읽기 좋게 명확하게 코드를 작성하라 ex) genymdhms → generationTimestamp;
  • 상수는 변수로 선언해서 의미를 부여하라.
  • 인터페이스에 I 접두어를 붙이지 말아라. ex ) IShapeFactory → ShapeFactory, 구현 클래스 ShapeFactoryImpl
  • 클래스 이름은 명사나 명사구가 좋고 Data, Info 같은 명사구는 피하고 동사는 사용하지 마라
  • 메소드 이름은 동사나 동사구를 사용하라
  • 의도를 분명하게 솔직한 이름을 사용하라
  • 하나의 개념에 단어는 하나의 이름을 사용하라ex) fetch, retrieve, get 필요 시 마다 제각각 다른 단어를 선택 하지말고 하나로 통일해서 사용하라.
  • 행동이 다르다면 굳이 동일한 이름을 사용하지 말고 다른 이름을 사용하라
  • 클래스이름으로 너무 범용적인 이름을 사용하게 된다면 동일한 기능을 하는 다른 클래스가 생길 때 이름을 정하기 어려워진다. ex) CustomerAddress를 고객 주소관리 클래스로 썼다면 고객 주소가 하나 더 늘거나 관리 데이터가 변경된다면?

 

결론

개발하다보면 진짜 어려운게 이름 규칙이다. 근데 하다보면 위에 써있는 대로 동일한 이름의 클래스들이 많이 만들어진다. 중복되는 불용어들을 줄이고 명확한 의미가 있는 클래스를 만들 수 있도록 노력해보자. 말 그대로 이름을 짓는 시간보다 잘못된 이름을 만들어 드는 시간이 더 크다는 걸 잊지말자.

댓글()

[토이프로젝트] TimeLine 개선

IT 지식/IT 지식|2020. 6. 14. 19:58

한동안 잠시 멈췄다가 다시 열면서 내용을 추가 하고 싶었다.

 

타임라인의 목적은 개발에 관련 블로그 내용들과 채용 뉴스등을 한번에 보기 위해서 만든 서비스이다.

사실 내가 한번에 보고 싶은 욕구가 있어서 만들게 되었다.

 

그런데 채용이나 회사 블로그 뉴스등은 넣었는데 

개인 블로그를 볼 수 있는 기능이 없어서 불편했는데 추가했다.

 

개인블로그 추가

 

 

그리고 메인 화면이 없어서 첫 화면을 설정하기가 애매했다.

그래서 메인화면도 summary해서 볼 수 있도록 추가했다.

 

메인화면

 

 

추가하면서 잘못된 @Transaction 어노테이션 사용으로 문제가 많았었다.

에러내용은 아래와 같다.

 

 

org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs)

애를 해결하기 위해서 구글링을 했고 구글링 결과 AssertionFailure가 발생하기 전에 세션 예외가 발생했었다는걸 알 수 있었다. 그래서 잘못 사용한 트랜잭션 애노테이션을 제거하고 중간에 exception이 발생하는 부분을 찾아냈다. 

 

참고 사이트

https://stackoverflow.com/questions/10855542/org-hibernate-assertionfailure-null-id-in-entry-dont-flush-the-session-after

 

org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs)

I have a hibernate and JSF2 application going to the deployment server and suddenly throwing an org.hibernate.AssertionFailure: null id in exception. I will provide the stack trace and code immedia...

stackoverflow.com

 

회사에서 주 업무가 Elasticsearch 위주로 하다보니 rdb에 대한 경험이 많이 부족해지고 있어서 사실 아쉽다. 

그 아쉬움을 달래고 싶어 개인 프로젝트를 통해 경험해 보고 있는데 아직 아쉬움이 크긴 하다.

 

 

더 좋은 방안이 있겠지? ㅋㅋ

 

개선된 내용이 보고싶다면 http://wedul.space에서 확인 가능하다.

 

Timeline

취업, 기술, 뉴스 일간지 Timeline

wedul.space

 

댓글()

자바 성능 튜닝 이야기 책 리뷰

Book Review|2020. 6. 12. 21:46
자바 성능 튜닝 이야기
국내도서
저자 : 이상민
출판 : 인사이트 2013.10.26
상세보기

요새 개발을 하면서 Java GC 튜닝이나 옵션 설정을 효율적으로 하지 못하는거 같아서 책 제목만 보고 자바 튜닝에 대해 공부해보고자 구매하였다.

 

흠... 근데 앞에 있는 대부분의 자료구조 선택 기준이나 String과 같은 자료형 주의사항등에 대한 이야기 대부분들이 대학교 2학년 때 봤었던 남궁성님의 자바의 정석이나 Effective java 책에 비해 많이 부족하고 블로그 글을 읽는다는 느낌을 많이 받았다.

 

 

GC에 대한 내용도 2011년도에 나온 네이버 D2에 글이 더 자세하게 기록되어 있는 거 같다. https://d2.naver.com/helloworld/1329

 

책 구매 후 이렇게 단 기간에 넘기면서 2시간만에 다 본건 처음이었다.

다음 읽을 책은 자바 최적화 인데 이건 조금 더 좋은 내용이 있었으면 좋겠다!!

댓글()

Mysql 인덱스 사용법 및 실행 계획 정리

데이터베이스/mysql|2020. 6. 10. 19:18

mysql 인덱스에 대한 정확한 이해도 없이 사용을 하다보니 조금 개념적으로 헷갈리는게 많이 있었다. 이 부분에 대해 한번 정리하고 넘어가고자 기록해본다.

 

인덱스


인덱스는 빠르게 특별한 컬럼과 함께 값을 찾는데 사용된다. 인덱스가 없으면 Mysql은 처음 행부터 전체 테이블을 읽어 들여서 데이터를 찾는다. 거대한 테이블에서 이런 행동은 비용이 상당히 많이 들어가게 된다. 만약에 테이블이 인덱스를 가지고 있으면 빠르게 접근할 수 있게 된다.

대부분의 Mysql 인덱스 (PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT)는 B-tree안에 저장된다. 예외적으로 spatial 데이터 타입은 R-tree를 사용, 메모리 테이블은 또한 hash index를 지원, InnoDB는 FULLTEXT 인덱스를 위해 inverted list를 사용한다.

 

 

인덱스 동작 방식


- 행을 찾기 위해서 매칭되는 WHERE 구문을 빠르게 찾는다.

 

- 조건으로 부터 불필요 행을 제거한다. 만약에 여러 인덱스가 있는 경우 Mysql은 가장 적은 수의 행을 사용하는 인덱스를 선택한다. (Mysql은 한번에 하나의 인덱스만 사용할 수 있다.)

 

- 만약 테이블이 multiple column 인덱스를 가지고 있으면 인덱스의 가장 왼쪽에 컬럼을 사용하여 옵티마이저를 통해 행을 찾는다. 예를 들어 만약에 (col1, col2, col3)을 사용하는 인덱스가 있는 경우 인덱스는 이 순서로 검색을 진행한다. (col1), (col1, col2), (col1, col2, col3)

 

- 조인이 있는 경우 다른 테이블에서 행을 찾는다. Mysql은 동일한 유형과 사이즈로 되어 있는 열을 index로 사용할 때 더욱 효과적으로 행을 찾는다. VARCHAR, CHAR는 두개를 같은 사이즈로 명시 하였을 경우에 같은 타입으로 고려되어 사용된다. 예를 들어 VARCHAR(10) = CHAR(10)이지만 VARCHAR(10) ≠ CHAR(15)는 같지 않다.

 

- binary가 아닌 문자열 사이를 비교하기 위해서는 동일한 문자열 집합을 사용해야한다. utf8과 latin1열을 비교할 경우 인덱스를 사용할 수 없다.

 

- 타입이 다른 문자열과 숫자 등을 비교하려고 할때도 마찬가지로 인덱스를 탈 수 없다. (묵시적 형변환)

 

- index로 사용되는 key_col에서 min(), max()의 값을 찾기 위해 인덱스에서 key_col 이전에 발생하는 모든 키 파트에서 WHERE key_part_n = const를 사용하는지 여부를 확인하기 위해서 전처리기를 통해서 최적화가 진행된다. 이 경우에서 Mysql은 각 min() 또는 max() 표현식에 대해 단일키 조회를 수행하여 상수를 대체한다. 모든 표현식이 상수로 바뀌고 나면 쿼리가 한번에 반환된다.

SELECT MIN(key_part2),MAX(key_part2)
  FROM tbl_name WHERE key_part1=10;

 

 

실행계획


- 실행계획 필드 정리

  • Id
    • Select 구문 구분 ID
  • select_type
    • SIMPLE : 단순 SELECT
    • DERIVED : 서브 쿼리 중 가장 안쪽에 있는 쿼리 
    • PRIMARY : 서브 쿼리 바깥쪽에 있는 쿼리
    • DEPENDENT SUBQUERY  : 조건절 내부에서 외부 쿼리와 연결된 SELECT 
// PRIMARY
SELECT * FROM ( 
    // DERIVED : 서브 쿼리 중 가장 안쪽에 있는 쿼리
    SELECT * FROM timeline_item ti
) tt;


// DEPENDENT SUBQUERY
SELECT * FROM timeline_item t1 WHERE EXISTS ( SELECT * FROM timeline_site t2 WHERE t1.id = t2.id)
  • table

    • 참조하는 테이블 이름
  • type

    • 조인 혹은 조회 타입 (아래로 갈수록 성능 하락)
      1. System : 테이블에 데이터가 하나만 있는 경우
      2. const : SELECT에서 Primary Key 혹은 Unique Key를 상수로 조회하는 경우
      3. eq_ref : 조인할 때 Primary, Unique Key로 매칭하는 경우
      4. ref : 조인할 때 Primary, Unique Key로 매칭하지 않은 경우
      5. ref_or_null : ref와 같지만 NULL이 추가되어 검색된 경우
      6. index_merge : 두개의 인덱스가 병합되어 검색이 된경우
      7. unique_subquery : In절 내부 서브쿼리에서 Primary Key가 있는 경우
      8. index_subquery : In절 내부 서브쿼리에서 Primary Key가 아닌 인덱스가 있는 경우
      9. range : 특정 범위 내에서 인덱스를 사용하여 데이터 추출 하는 경우
      10. index : 인덱스를 처음부터 끝까지 찾아서 검색하는 경우로 일반적인 인덱스 풀스캔
      11. all : 테이블 풀스캔
  • possible_keys

    • 데이터 조회 시 DB에서 사용할 수 있는 인덱스 리스트
  • key

    • 실제로 사용할 인덱스
  • key_len

    • 실제로 사용할 인덱스 길이
  • ref

    • key 안의 인덱스와 비교하는 컬럼(상수)
  • rows

    • 쿼리 실행 시 조사하는 행수
  • extra

    • 추가 정보 (데이터가 많고 Using filesort, Using temporary 상태가 나온다면 무조건 최적화 필요)

      1. Using Index

        커버링 인덱스라고 하며 인덱스 자료구조를 이용하여 데이터를 추출

      2. Using where

        where 조건으로 데이터를 추출 (Type이 All 또는 Index와 같이 표현될 시 성능이 안좋다는 뜻)

      3. Using filesort

        데이터 정렬이 필요한 경우로, 메모리 혹은 디스크 상에서의 정렬을 모두 포함 (데이터 많을 시 성능 하락)

      4. Using Temporary

        쿼리 처리 시 내부적으로 Temporary 테이블이 사용됨

 

 

WHERE 조건문 주의사항


  • 묵시적 형변환에 조심하라
  • 무턱되고 함수를 사용하면 옵티마이저가 데이터 분포도 체크를 하지 못하기에 사용하지 말 것
// 함수 사용
SELECT * FROM timeline_item ti WHERE DATE_FORMAT(modified_at, '%Y%m%d') <= '20200402'

// 대안방안
SELECT * FROM timeline_item ti WHERE modified_at <= '2020-04-02'
  • Like 검색은 % 위치에 따라 다르게 수행 된다. %123, %125%의 경우에는 데이터 풀 스캔이 발생된다. 하지만 12312%와 같은 경우에는 인덱스를 사용해서 진행됨. 하지만 1%등과 같이 데이터 분포도에 비해 너무 추상적으로 %를 사용하게 될 경우에는 옵티마이저가 인덱스 사용과 데이터 풀스캔의 효율성 판단 했을 때 풀스캔이 효율적이다고 생각하고 데이터 풀스캔이 실행된다. 

댓글()

Elasticsearch 7.7 feature와 heap 메모리 사용량의 두드러진 감소량

 


줄어든 heap 사용량

Elasticsearch 사용자들은 Elasticsearch 노드에 저장이 가능한 만큼 데이터를 집어 넣지만, 가끔 disk에 저장되기 전에 heap memory 사용량이 초과되는 것을 경험한다. 이는 비용을 줄이기 위해 가능한 노드당 많은 양의 데이터를 넣고 싶은 사용자들에게 문제를 일으킨다. (실제로 현재 운영중인 es에서도 대량의 데이터 삽입 시 가끔 발생함)

 

왜 Elasticsearch에는 데이터를 저장하기 위해 heap memory 영역이 필요한걸까? 왜 디스크 공간만으로 충분하지 않은걸까?? 거기에는 여러 이유가 존재하지만 가장 중요한 이유는 루씬은 디스크 상에 데이터를 찾을 수 있는 위치를 찾아내기 위해서 일부 정보를 메모리에 저장해야 한다.

 

예를 들어 루씬의 inverted index는 terms 사전(디스크 상에 순서대로 블록 형태로 되어있는 terms group)과 terms index(terms 사전에서 빠르게 조회하기 위해 구성된)로 구성되어 있다. 이 terms index는 디스크상의 블록에 prefix starts 위치를 포함하고 있는 terms를 offset과 함께 terms의 prefix 정보로 도식화 하고 있다. 그런데 이 terms 사전은 disk 상에 존재하지만 terms index는 heap 위에서 존재한다.

 

그럼 얼마나 많은 양의 메모리가 필요로 할까? 전형적으로 인덱스 GB당 작은 MB 만큼이 필요로 한다. 이것은 많지는 않지만 사용자가 노드에 terabyte 상당의 데이터를 디스크에 사용한다면 indicies는 indices에 terabyte만큼의 데이터를 저장하기 위해서 10~20GB상당의 heap memory가 필요로 하게 된다.

 

Elasticsearch에서는 30GB이상의 힙메모리를 올리지 말라고는 하지만 종종 집계와 같은 쿼리 시 다른 consumer를 위한 공간을 남기지 않기 때문에 JVM에서 클러스터 관리 작업을 위한 공간이 충분치 않는 경우가 많아 운영에 어려움을 주는 경우가 있다.

 

실제로 기존에 6.x 버전과 7.x 초기버전의 경우에는 10TB 데이터 저장 시 17기가의 힙 메모리가 필요로 했다. 하지만 7.7버전에서는 2.5기가만 필요로 하도록 개선되었다고 한다.

 

어떻게 이게 가능해진걸까? Jvm에서 디스크로 데이터를 옮기는 구조와 메모리에서 hot bits를 유지하기 위해서 파일시스템을 사용하는 등의 기술들이 루씬 indices의 여러 컴포넌트들에게 시간이 흐름에 따라 동일하게 적용되고 있다. 그리고 이 메모리는 여전히 할당된 곳에서 내용을 읽을 수는 있지만 이 메모리에 상당한 부분은 사용사례에 따라 사용 되지 않는 경우가 많았다.

 

예를 들어 디스크상의 _id field의 terms index의 이동으로 삭제된 terms는 오직 GET API와 정확한 IDS로 document들을 인덱싱 했을 때만 사용된다. 하지만 elasticsearch로 메트릭과 로그를 인덱스하는 사용자의 대부분은 해당 기능을 사용하지 않는다. 이렇게 사용되지 않고 있는 자원들을 활용해서 heap의 사용률을 7.7버전 부터는 더 적게 heap 크기를 사용 할 수 있게 되었다.

 

그 밖에 새로운 feature

이 밖에도 검색 결과를 동기로 기다리지 않고 검색결과를 검색 시 사용한 ID를 이용해서 추후해 결과를 얻을 수 있는 async search와 aggregation시 많은 bucket을 할 당할 경우 발생할 수 있는 OOM을 피하기 위해서 주기적으로 memory circuit breaker를 bucket을 추가 할당 하기 전에 체크하는 기능 등이 추가되었다.

 

 

 

 

출처 및 읽어보면 좋은 링크

 

인덱스와 샤드의 관계

https://www.elastic.co/kr/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

How many shards should I have in my Elasticsearch cluster?

이 블로그는 여러분의 클러스터에 적합한 인덱스와 샤드의 개수와 크기를 어떻게 가져가야 하는지에 대한 실질적인 가이드라인을 제공합니다.

www.elastic.co

https://www.elastic.co/kr/blog/significantly-decrease-your-elasticsearch-heap-memory-usage

Significantly decrease your Elasticsearch heap memory usage

Fitting as much data per Elasticsearch node as possible is often important to reduce costs. Learn more about the improvements coming in Elasticsearch 7.7 to dramatically reduce the amount of heap memory needed per GB of data.

www.elastic.co

 

댓글()