[Routine] 3 주차 시작!

[Routine] 3 주차 시작!

2023년 1월 30일 부터 2월 05일 까지의 나의 루틴.

#목차

나의 루틴을 더 확장하기.

2023-01-30

2023-01-30

  • 어김없이 오늘도 첫 번째 1시간은 독학사를 나머지 1시간을 이것이 자바다를 공부 하였다.
  • 또한 이것이 자바다를 공부한 것을 커밋 하였다.
  • 요새 회사에서 회사 자체 시스템이 vue로 되어있어 vue를 예전에 공부했던 나로서는 완전 생소하지는 않았다.
  • 퇴근 후 독학사 무료 인강 날짜가 몇일 남지 않아 다시 한번 인강을 듣고 공부를 하였다.

2023-01-31

2023-01-31

  • 오늘도 독학사 1시간, 이것이자바다 1시간을 공부하였다.
  • 오늘도 어김없이 이것이자바다 공부한 것을 커밋 하였다.
  • 아직도 이것이 자바다를 정리해야 할게 많이 남은 듯하다.
  • 패키지 별로 나누고 공부한 키워드별로 클래스 파일을 만들고, 코드 작성 후 테스트해 보고…
  • 퇴근 후 오늘도 독학사를 공부하는데 왜 이렇게 머릿속에 내용들이 안 들어 오는 걸까?
  • 우선 꾸준히 외우는 것이 아니라 익숙해져야 할거 같다.

2023-02-01

2023-02-01

  • 아침에 출근해서 항상 나의 행동은 똑같다.
  • 컴퓨터를 키고 맥북을 꺼내고 공부할 내용들을 켜놓고, 커피를 타오고 공부를 시작한다.
  • 오늘도 그렇다. 1시간은 독학사, 1시간은 이것이 자바다를 공부했다.
  • 퇴근 후에도 역시나 독학사와 다음 스터디 발표자료를 준비하였다.

2023-02-02

2023-02-02

  • 오전의 나의 패턴은 항상 똑같다.
  • 출근하면서 영한 님 인강 듣고, 출근해서 공부하고..
  • 그런데 오늘은 회사에서 일을 일찍 마무리하여 이것이자바다를 공부하며 정리 후 커밋 하였다.
  • 꽤 많이 기록하고 정리하여 커밋 하였다.
  • 퇴근 후 역시나 영한 님의 인강을 들으면서 퇴근하고 운동하고 밥 먹고 독학사와 스터디 자료조사를 좀 하였다.

2023-02-03 스터디

2023-02-03

  • 오늘의 오전 일과도 다른 어김없이 같다.
  • 영한 님 인강, 독학사, 이것이자바다.
  • 오늘은 스터디의 다른 조 발표하는 날이라 참석하여 스터디와 함께 스터디 인원과 꽤 많은 소통을 하였다.
  • 스터디를 시작한 지 얼마 되지 않지만 처음보다는 질문도 많아지고 얘기도 많아져서 더 알찬 스터디가 된 거 같아 기분이 좋다.😙
  • 퇴근 역시 영한 님과 함께 하였다. 영한 님은 날 모르지만 난 영한 님이랑 친해지는 느낌이 든다…

왕돼지티라노의 기록 - JPA 시작

  • jpa 만들어 보기
  • 하이버네이트 왜 필요한가
  • H2 DB 사용(설치 필요X, 가볍다, local에서 사용하기 좋음)
  • 매핑정보가 없는 필드는 JPA가 알아서 매핑해준다.
  • persistance.xml의 필수 옵션과 옵션정보 담기.
  • CRUD는 EntityManager가 해주는 것
  • 둘의 가장 큰 차이점은 JPQL은 엔티티 객체를 대상으로 쿼리하고, SQL은 데이터베이스 테이블을 대상으로 쿼리한다.
  • JPQL은 대소문자를 명확하게 구분 함.
  • DB정보와 필드의 정보 또는 갯수가 달라지면 사용하지 않는 필드는 @어노테이션으로 지정해 줄 수 있다.

질문

  • 매핑정보가 없는 필드는 JPA가 알아서 매핑해준다. 단, 조건이 있을듯?
  • 매핑 정보 외 다른 필드가 있을 수 있나? -> 조회 할 때 문제가 생길듯? 실험해보자

알아보기

  • 키 생성 제공 조건

^.^ - 라이브러리 VS 프레임워크

라이브러리(소프트웨어)
  • 응용프로그램 개발을 위해 필요한 기능, 함수들을 모아높은 일련의 데이터 및 코드
  • 코드를 간결하게 사용할 수 있고, 가독성이 좋아진다

  • 독립적-> 모든 라이브러리는 서로 배타적
  • 능동적 -> 응용프로그램이 라이브러리를 능동적으로 호출
  • apache commons (재사용 가능한 컴포넌트 모음)
  • Jquery(자바스크립트 라이브러리)
  • Guava(구글에서 배포한 자바 라이브러리 (유효성 체크, Collection, 날짜, 문자 등등)
  • Lombok(어노테이션 기반의 코드완성)
프레임워크
  • Frame : 틀, 뼈대 / Work : 작업
  • 프레임워크 : 응용프로그램이나 소프트웨어의 솔루션 개발을 수월하게 하기위해 제공된 소프트웨어 환경
  • 건물의 설계도라고 생각하면 이해가 쉽다.

[LBY] 회원가입 구성해보기

  • GET 방식의 회원가입
    • url에 입력한 데이터 모두 노출.
    • QueryString으로 변수명=값 형태로 데이터를 보냄
  • POST 방식의 회원가입
    • POST user/create HTTP/1.1 형식으로 url에 노출되어 개인정보를 숨길 수 있다.
    • HTTP == 무상태성(Stealess)

2023-02-04

  • 오늘은 여자친구와 어머님 직장에서 점심 식사를 한 후 자리를 옮겨 카페 가서 공부를 하였다.
  • 확실히 이동이 많으면 공부가 쉽지 않긴 하다.
  • 그래도 짧은 순간이라도 공부가 아니더라도 자료조사나 발표 준비를 하는 게 나은 거 같다.

2023-02-05

  • 오늘은 친척 동생 결혼식 참석으로 인해 공부를 하지 못했다…
  • 친척 동생과 내가 축의금 받는 걸 했는데 정말 정신이 없고 혼이 다 빠지는 느낌이 든다…
  • 내일 출근을 위해선 오늘 하루는 푹 쉬고 내일 열심히 달리자!😂

Back to [Routine] 2 주차 시작!

Continue with [Routine] 4 주차 시작!

[리팩토링] 무분별한 팝업창 코드 공통 함수로 리팩토링

[리팩토링] 무분별한 팝업창 코드 공통 함수로 리팩토링

#목차

문제

  • 프로젝트 이관 작업 중 유효성 및 팝업창의 코드를 무분별히게 생성하여 중복코드 발생.
  • 사용자가 조회, 등록, 등 작업을 하려는 행위들을 했을 때 사용자에게 안내 팝업창과 저장했으면 저장, 취소했으면 취소하는 행동의 팝업창을 띄워주고 있는데, 그 코드들을 계속 새로 작성하여 중복코드가 상당히 발견되는 상황을 발견하였다.

문제의 재현 코드

// file: "문제의 javascript파일.js"
function processDone(jqXHR, textStatus, errorThrown) {
    // ...
	if (jqXHR.status == 500) {
		Swal.fire({
			title: '알림', 
			text: '내부 시스템 에러', 
			icon: 'error',
			confirmButtonText: '확인', 
		}).then(function (result) {
			if (result.value) {
				alertify.error('내부 시스템 에러');  
			}
		});
	} else if (jqXHR.status == 404) {
		Swal.fire({
			title: '알림', 
			text: '경로가 잘못 되었습니다.',
			icon: 'error',
			confirmButtonText: '확인', 
		}).then(function (result) {
			if (result.value) {
				alertify.error('경로가 잘못 되었습니다.'); 
			}
		});
	} else if (jqXHR.status == 408) {
		Swal.fire({
			title: '알림', 
			text: '잠시 후 다시 시도해 주세요.', 
			icon: 'error',
			confirmButtonText: '확인', 
		}).then(function (result) {
			if (result.value) {
				alertify.error('잠시 후 다시 시도해 주세요.');
			}
		});
	} else if (jqXHR.status == 401) {
		errorAlert('접근 권한이 없습니다.'); 
	} else if (jqXHR.status == 403) {
		Swal.fire({
			title: '알림', 
			text: 'ID 또는 비밀번호를 확인해주세요.',
			icon: 'error',
			confirmButtonText: '확인', 
		}).then(function (result) {
			if (result.value) {
				alertify.error('ID 또는 비밀번호를 확인해주세요.'); 
			}
		});
	}

	if (jqXHR.getResponseHeader("SESSION_EXPIRED") != null ) {
		Swal.fire({
			title: '알림',
			text: '세션이 만료되어 로그인 페이지로 이동합니다.', 
			icon: 'error',
			confirmButtonText: '확인',
		}).then(function (result) {
			if (result.value) {
				location.href = "/login";
			}
		});
		
	}
}

문제의 재현 코드

  • 위 코드를 보게 되면 api 호출 후 응답 결과에 따른 안내 팝업창을 나타내는 코드이다.
  • 위 조건문 안에 Bootstrap의 팝업 기능인 Swal.fire() 부분의 코드들이 중복적으로 계속 발생한다는 것을 알 수 있다.
  • 위 코드처럼 사용하게 되면 만약, 기능들이 추가되거나 사용자에게 팝업 형태의 알림을 보여줘야 할 때 계속 비슷한 코드를 사용해야 한다는 문제가 발생한다.
  • 그것을 방지하고 함수로 정의하여 호출하는 형태로 바꾸어 아래 코드처럼 리팩토링하였다.

리팩토링 재현 코드

// file: "sg.ajax.js"
function processFail(jqXHR, textStatus, errorThrown) {
    // ...
	if (jqXHR.stat표us == 500) {
		notification('내부 시스템 에러', 'error', null);
	} else if (jqXHR.status == 404) {
		notification('경로가 잘못 되었습니다.', 'error', null);
	} else if (jqXHR.status == 408) {
		notification('잠시 후 다시 시도해 주세요.', 'error', null);
	} else if (jqXHR.status == 401) {
		notification('접근 권한이 없습니다.', 'error', null);
	} else if (jqXHR.status == 403) {
		notification('ID 또는 비밀번호를 확인해주세요.', 'error', null);
	}
    // ...
    if (jqXHR.getResponseHeader("SESSION_EXPIRED") != null ) {
        notification('세션이 만료되어 로그인 페이지로 이동합니다.', 'error', () => { location.href = "/login"; });
    }
	// ...
}

리팩토링한 재현 코드

  • 위 코드처럼 리팩토링하여 약 71%의 코드 사용량을 줄였다.
  • 물론 코드가 예제 파일 파일 한 곳에 결과를 반영한 것으로 실제와 다를 순 있다.
  • 하지만, 확실한 건 코드의 사용량이 예제 코드를 통해서만 보아도 많이 줄일 수 있다는 것을 볼 수 있다.

리팩토링 공통 함수 재현 코드

// file: "리팩토링.js"
/**
 * Notification (success/error/warning/question/info alert)
 *
 * @param text      팝업 문구
 * @param type      팝업 종류 : success, error, warning, info
 * @param method   실행 메서드
 * @returns Swal.fire
 */
function notification(text, type, method) {
   // When text and type are not used
   if (text === null || type === null) {
      return Swal.fire({
         title: '알림', 
         text: '시스템 오류가 발생했습니다. 관리자에게 문의해주세요.',
         icon: 'warning',
         confirmButtonText: '확인', 
      });
   }
   // Common Alert
   return Swal.fire({
      title: '알림', // 알림
      text: text,
      icon: type,
      showCancelButton: type === 'question' ? true : false,
      confirmButtonText: '확인', 
      cancelButtonText: '취소', 
   }).then((result) => {
      if (result.isConfirmed) {
         method();
      } else if (result.isDismissed) {
         notification('취소 하였습니다.', 'warning', null);
      }
   });
}

공통 팝업 함수 재현 코드

  • 위 파라미터 text의 경우 공통 팝업 창의 안내 문구를 넣어주는 파라미터이다.
  • type은 팝업창의 아이콘 타입으로 error, warning, success을 통해 공통 팝업창의 아이콘을 설정할 수 있게 된다.
  • method의 경우 공통 팝업 창의 실행 후 추가적인 작업이 이 필요할 때 함수를 넣어주는 파라미터이다.
  • 따라서, 위 공통 함수 코드로 리팩토링하여 사용자에게 필요한 팝업창을 제공하고 싶을 때 호출하여 사용하면 된다.
  • 매번 사용자에게 팝업 알림 창을 보여줘야 하는 코드를 만들어서 보여주는 것보다 그곳에서 해당 공통 함수를 호출하여 제공하면 코드 사용량이 줄어들어 유지 보수에도 편하게 된다.

결론

  • 리팩토링을 통해 코드가 훨씬 간결해졌다.
  • 또한 유지 보수가 편리해졌다는 것을 알 수 있다.
  • 이렇게 리팩토링을 진행하면서 리팩토링의 재미를 느끼게 되었다. 위 코드 또한 좀 더 리팩토링해볼 수 있지 않을까? 란 생각을 잠시나마 해본다.

[Routine] 2 주차 시작!

[Routine] 2 주차 시작!

2023년 1월 23일 부터 1월 29일 까지의 나의 루틴.

#목차

나의 루틴을 더 확장하기.

2023-01-23

  • 설날 연휴~😙

2023-01-24

  • 여자친구와 만나서 카페에 가서 공부하였다.
  • 그리고 인프런에 김영한 님의 인강 강의를 모두 공부하려고 결제를 하였다. 30% 할인이 얼마 남지 않아 바로 한 번에 결제하게 되었다.
  • 앞으로 출/퇴근과 이것이자바다를 마치면 본격적으로 공부하려 한다.
  • 이번 주 금요일(2023-01-27)에 있을 회사 스터디 발표 자료를 만들었다.
  • 주제는 인증과 인가의 개념을 소개하려 한다.
  • 30분 정도 자료 조사하고 바로 독학사 공부를 하였다.
  • 그리고 남은 1시간 정도 공부하고 다음은 이것이 자바다를 공부하였다.
  • 그리고 저녁 먹고 다시 공부를 1~2시간가량 하고 집에 갔다.. 내일 출근을 위해…😂

2023-01-25

myroutine

  • 출근할 때 어제 결제한 김영한 님의 모든 개발자를 위한 HTTP 웹 기본 지식을 보면서 HTTP에 대해 조금 더 이해하려 듣고 출근을 했다.
  • 오늘은 독학사 1시간, 이것이 자바다 1시간을 공부하였다
  • 역시나 독학사는 재미없다…
  • 이것이 상대적인 거 때문에 이것이 자바다가 훨씬 재미있게 느껴진다…
  • 정말 기술서를 읽기 싫거나 혹은 나의 마음가짐이 조금 아닐 해질 때 독학사 같은 책들을 간간이 읽어보면 기술서가 얼마나 재미있는 책인지 느끼게 해주는 거 같다.
  • 다음에 혹시나 기술서가 재미 없어지려고 할 때 재미없는 책을 읽어야겠다.😁
  • 영한 님의 인강을 들으면서 퇴근하고 집에 가서 금요일(2023-01-27)에 있을 스터디 발표 자료와 독학사를 공부하였다.

2023-01-26

myroutine

  • 오늘도 역시나 영한 님 인강을 들으면서 출근하고 독학사 1시간, 이것이 자바다 1시간을 공부하였다.
  • 이제 점점 몸이 적응해 가는 거 같다.😙
  • 첫날에 생각만 해도 정말 몸살 걸려서 그 주는 몸이 너무 피곤했었다.
  • 하지만 인간은 적응의 동물?이라고 결국 적응해 나가고 있는 듯하다.
  • 역시나 영한 님 인강을 들으면서 퇴근 후 집에가서 내일 있을 스터디 발표자료 마지막 검토와 함께 독학사 공부를 하였다.

2023-01-27 스터디 발표날

myroutine

  • 오늘도 역시나.. 영한 님 인강을 들으면서 출근해서 독학사 1시간, 이것이 자바다 1시간을 공부하였다.
  • 당분간 독학사 시험까지는 아마도 이렇게 나눠서 공부할 듯싶다.. (얼른 떯어지던 합격하던 했으면 좋겠다… 개발 공부에만 신경 쓰고 싶다…😭)
  • 그리고 오늘은 이것이 자바다를 공부한 코드를 커밋 하였다.
  • 아직 적어 놓은 건 많고 정리해가면서 커밋 해야겠다.

스터디 발표 내용

내용들이 너무 길어 키워드들을 넣어 놓고 링크를 걸어 해당 블로그로 가서 보자

  1. thisiswoo - 인증과 인가
  2. asd - 기본형 매개변수와 참조형 매개변수
  3. 코드는 지우개로 지우게 - 추상 클래스

2023-01-28

  • 오늘은 여자친구와 400일인 기념적인 날이라 여자친구와 데이트를 하였다.😘

2023-01-29

  • 어제 열심히 놀고먹고해서 오늘은 열심히 공부를 했다.
  • 이것이 자바다 정리한 코드를 테스트해보고 커밋을 하였다.
  • 그리고 역시나 독학사 공부를 했는데 진짜 큰일이다… 아무리 생각해도 머리에 들어오지 않는다..
  • 괜히 시험 등록 한 듯하다…😂
  • 또한 한 주의 마무리인 스터디 한 내용을 잘 다듬어야 하는데 너무 길어서 걱정이다…
  • 스터디 내용을 간추려 핵심만 뽑아 간략하게 정리하고 싶은데 생각보다 쉽지가 않다… 꾸준히 연습해 봐야겠다.

Back to [Routine] 1 주차 시작!

Continue with [Routine] 3 주차 시작!

[Security] OAuth 2.0

[Security] OAuth 2.0

“해당 포스팅은 우아한Tech[10분 테코톡] 토닉, 후디의 인증과 인가 - 부족사회부터 소셜로그인까지을 참고하여 포스팅하였습니다. 영상을 제작해주신 우아한Tech토닉, 후디님에게 감사드립니다.”

#목차

OAuth 2.0

OAuth 2.0 이란?

“다른 웹사이트 상의 자신들의 정보에 대해 접근 권한을 부여할 수 있는 공통적인 수단이자 개방형 표준

소셜 로그인의 등장

social_login_buttons

“구글, 페이스북, 깃헙 등의 로그인을 사용하는 인증 및 인가 절차OAuth와 OpenID라 한다.”

우리는 어떻게 소셜 로그인을 사용한 로그인을 할 수 있을까?

what_is_oauth_openid

OAuth인가에 대한 기술이고, OpenID인증에 대한 기술이다.”

  • 여기서 근간 기술인 OAuthOpenID 두 가지 기술이 존재 한다.

OAuth2.0 이전

service

발단

  • 디스이즈우닷컴은 서비스를 제공하기 위해서 사용자의 구글 주소록이 필요해서 사용자의 ID/PW를 직접 제공받기로 한다.

problem

전개

  1. 사용자가 디스이즈우닷컴에 구글 ID/PW를 제공해 주면
  2. 그 정보로 디스이즈우닷컴에 구글에 로그인하게 된다
  3. 구글은 디스이즈우닷컴에게 사용자의 주소록을 제공해 준다
  4. 디스이즈우닷컴은 사용자에게 서비스를 제공해 준다

문제 발생

  • 하지만, 여기에는 굉장히 많은 문제점이 발생하게 된다
  • 사용자
    1. 디스이즈우닷컴이 해킹돼서 내 계정이 탈취되면?
    2. 에초에 디스이즈우닷컴이 악의적인 웹사이트 면?
  • 디스이즈우닷컴
    1. 사용자의 민감한 개인 정보를 가지고 있어도 되나?
  • 구글
    1. 회원 정보를 믿을 수 없는 제3자에게 가지고 되나?

it_company_oauth

OAuth의 표준화

  • 따라서, OAuth표준화시작된다 explan_oauth

OAuth의 버전

oauth_version

“해당 포스트에서는 OAth2.0 기준으로 포스팅 하겠다”

OAuth의 주체

name

OAuth의 detail 주체

detail_name

OAuth의 동작과정

oauth_diagram

“OAuth2.0의 동작과정을 간단한 시퀀스 다이어그램”
Scope 클라이언트에게 허용된 리소스 접근 범위

  1. Resource OwnerClient에게 로그인 요청하게 된다
  2. ClientAuthorization ServerOAuth 인증 요청하게 되는데, 이때 Scope도 같이 요청하게 된다
  3. Authorization ServerResource Owner에게 로그인 페이지 제공
  4. Resource Owner는 해당 페이지에서 로그인하게 된다
  5. Authorization ServerResource Owner에게 Authorization Code라는 임시 코드를 발급해 준다
  6. 그 즉시 Resource OwnerRedirect URI로 리디렉션 되는데, 이때 Authorization Code를 함께 가지고 리디렉션 된다.
  7. Client는 방금 받은 Authorization Code를 통해 Access Token발급 요청하게 된다
  8. Authorization ServerAccess Token발급해 준다
    • Client는 해당 Access Token을 자체 서비스에 저장 및 관리한다
  9. ClientResource Owner에게 로그인 성공을 알려준다
  10. 시간이 흐르고 Resource OwnerClient에게 서비스 요청
  11. 이때 ClientAccess Server저장된 Access Token으로 리소스 요청
  12. Access Server에서 Access Token검증되면 Client에게 리소스 제공
  13. 그리고 ClientResource Owner에게 서비스 제공

Continue with [Security] OpenID

[Routine] 첫 주차 시작!

[Routine] 첫 주차 시작!

2023년 1월 18일 부터 1월 22일 까지의 나의 루틴.

#목차

나의 루틴을 더 확장하기.

발단

my_plane

나의 출근 계획은 이러했다… 시작은 미약하였지만 끝은 창대하리라…

  • 개발 회사에 입사(2021-12-01) 후 첫 달에는 정시 출근(AM09:30)을 했다.
  • 하지만, 나이가 있는 상태에서 입사를해서 뭔가 더 일찍 다녀서 공부를 하던 잠을 더 자던 회사에 무조건 1시간을 일찍 와보고 싶었다.
  • 그렇게 입사 후 1달의 시간이 지나고 2022-01-03(월)일 부터 1시간씩 일찍 출근 하였다.
    • 아쉽게도.. 그 당시 회사에 출/퇴근 확인 할 시스템이 구축되어 있지 않았다…
  • 그리고… 시간이 지나면서 1시간에서 50분… 40분… 30분… 점점 나의 일찍 출근하는 시간이 점점 단축되어 갔다.(뭔가… 아닐해진거 일 수 도 있다.. ㅠㅠ)

before_my_routine

이전의 나의 출근 기록이다. 회사 이전 출근 기록 프로젝트가 버전 업 하면서 데이터를 모두 날리고 새로운 버전으로 시작하면서 새롭게 데이터를 쌓았다. 그래서 전 데이터들이 없는게 너무 아쉽다…

  • 그렇게 2022년 12월 쯤에…
  • 유튜브 개발바닥이라는 채널을 알게 되어 정말 열심히 듣게 되었다.
  • 그러던 중 향로님EO유튜브에 출연하여 공부시간을 듣고나서 너무 대단하다고 느껴졌다…
  • 출근을 지하철 첫 차(5시 30분)를 타서 7시에 회사에 도착해 9시까지 2시간을 매일같이 공부하셨다고 한다.
  • 주말에는 12시간씩 공부해서 주 마다 30시간씩 공부를 했다고 하셨다.

전개

result

하지만… 나의 실상은 이러했다…

  • 해당 유튜브를 보고 어떻게 주에 30시간씩이나 공부를 할 수 있지??? 라고 생각했다.
  • 그렇게 몇 일이 지나고, 나는 무작성 아침에 두 시간을 일찍가서 공부해보기로 하였다.
  • 특별한 계기는 없다…. 그냥 해보는 거였다.

2023-01-18

1st_myroutine

드디어 첫 번째 날…

  • 너무 일찍왔고… 몸살이 걸렸다……… 하…….
  • 학점은행제 학점을 따기 위해 독학사(현대사회와 윤리, 문학개론) 책을 사서 공부를 했다.
  • 시험(2023년 2월 26일)이 얼마 남지 않아서 공부하고 있긴 하지만… 역시나 이해가 되지 않는 상태에서 외우는 것은 나에겐 너무나도 어려운 것 같다.
  • 그리고 틈틈이 이것이 자바다를 공부하고 있다.
  • 그리고 커밋 할 코드들을 정리하였다.
  • 퇴근 후 집에 가서 운동을 했다. 땀을 빼면 몸살 기운이 사라질 거 같았다.
  • 그렇게 홈트 후 바로 몸살감기 약을 먹고 9시부터 11시까지 공부를 하였다.

2023-01-19

2nd_myroutine

두 번째 날…

  • 어제 운동을 괜히 했나 싶다. 몸살 기운이 사라지지 않았다.🤧
  • 몸의 컨디션이 좋지 않아서 그런지 1시간을 회사에서 졸았다…😪
  • 열심히… 그리고 최선을 다해… 졸고 또 졸고… 열심히 1시간 가량을 졸고 이것이 자바다를 1시간 가량 공부하였다.🤤
  • 확실히 개발 공부가 더 재미있긴 하다. 독학사… 너무 머리에 안 들어 온다.
  • Java17로 반영된 이것이 자바다를 보면 Java 버전별 추가된 기능들을 소개하곤 한다.
  • 차이점을 조만간 깃허브에 올릴 예정이다.
  • 퇴근 후 오늘은 운동을 하지 않았다. 컨디션이 더 좋지 않을 거 같아 운동을 쉬게 되었다.
  • 집에 가자마자 밥 먹고 씻고 약 먹고 일찍 잤다.
  • 다음날 아침 일찍 일어나기 위해 당분간 몸이 기억할 수 있게 하기 위해 또, 너무 무리하지 않게 하기 위해 일찍 잤다.

2023-01-20

3rd_myroutine

세 번째 날…

  • 어제 일찍 자서 그런지 컨디션이 많이 나아진 거 같다.
  • 오늘도 독학사와 이것이 자바다를 각각 1시간씩 공부하였다.
  • 그리고 오늘 오후 3시에 대표님이 전 직원을 회의실로 모아서 네해 인사 후 퇴근하도록 하였다.🥳
  • 퇴근 후 여자친구 만나서 카페에서 공부 좀 하다가 밥 먹고 집에 들어갔다.
  • 집에 와서 씻고 약 먹고 바로 잤다. 내일을 위하여…

2023-01-21

네 번째 날…

  • 오늘은 내일 설날이라 할머니 가족분들이 오신다고 하셔서 아빠와 아침 일찍 목욕탕에갔다 왔다.
  • 목욕탕 갔다오니까 몸살감기가 다 나은거 같다.
  • 하지만 너무 일찍 일어났는지 가족 분들 오시고 점심을 먹고 잠깐 쉬는 시간에 30분 정도만 자야지~ 했는데… 일어나니까 오후 6시이다…😭
  • 오늘은 우리 할머니랑 고스톱이나 쳐야겠다~

2023-01-22

다섯 번째 날…

  • 오늘은 내 블로그에 새로운 루틴 포스트를 추가하여 1주일의 기록들을 기록하려 한다.
  • 중요한것은 내가 꾸준히 공부하는 것을 기록하려 한다.
  • 처음부터 완벽할 수 없다고 생각한다.
  • 내가 하고 싶은건 습관을 만드는 것이다.
  • 처음은 힘들겠지만 적응하면 나에게 너무나 소중한 시간이 될거 같다는 생각이 든다.

결론

  • 세상엔 대단한 사람들이 많다.
  • 그 분들의 장점을 배우자.
  • 그리고 너무 무리 하지 말자… 잘 못하면 몸살 걸린다…

Continue with [Routine] 2 주차 시작!

[Security] 인증과 인가

[Security] 인증과 인가

“해당 포스팅은 우아한Tech[10분 테코톡] 🎡토니의 인증과 인가의 영상을 기반으로 포스팅하였습니다. 또한 설명이 너무 잘되어었어 복습하고자 글로 남깁니다. 영상을 제작해주신 우아한Tech토니님에게 감사드립니다.”

#목차

실 생활에서의 인증과 인가

인증(Authentication)이란?

authentication

  • (지문 또는 얼굴 등) 입증 가능한 정보로 인증이 필요한 곳에 입증하는 과정이다. 즉, 식별 가능한 정보로 서비스에 등록된 유저의 신원을 입증하는 과정
  • 쉽게 말해, 아이폰으로 계좌이체를 하려고 할 때, 어플에 접근하여 로그인 하는 과정인증이다.

인가(Authorization)란?

authorization

  • 입증(인증) 된 신원의 권한에 대한 허가를 나타내는 것이 인가이다. 즉, 인증된 사용자에 대한 자원 접근 권환 확인이다.
  • 쉽게 말해, 은행 어플에 접근하여 로그인(인증) 한 후, 계좌이체에서 마지막 송금 과정시 OTP, 생체인증권한을 통한 작업인가이다.

Web에서의 인증과 인가

web_authentication_authorization

Web에서 사용자가 게시판에 글 작성하는 서비스라고 생각해보자.”

  • 사용자가 사이트에 회원가입로그인을 하는 과정이 인증이다.
  • 인증이 됐으면 게시판에 게시글을 쓸 수 있는 권한이 생겼다. 이 과정이 인가이다. 다른 사람이 게시판에 작성한 게시글 또한 읽을 수 있다.
  • 하지만, 다른 사람이 작성한 게시글을 수정할 수 없다. 왜냐하면, 다른 사람이 작성한 게시글을 수정 할 권한(인가)이 없기 때문이다. 인가적용된 개념이다.

1.Request Header 활용

request_header

“Client와 Server 사이에 HTTP통신하게 된다. 가상의 사이트에 회원가입이 되어있는 상태라고 가정해보자.”

  1. DB에 ID, PW 정보가 있다. 사용자가 login URL로 접근하게 되면 login 요청을 보낼 수 있게 된다.
  2. 만약, 로그인 API가 구축되어 있는 상태라고 가정 했을 때, URL 앞에 ID, PW를 넣어주고 요청하게 되면 login이 된다.
  • 2번의 처리 과정을 간단하게 알아보자.

browser_encoding

“브라우저 요청 처리 방법은 요청 URL을 Base64encoder를 이용하여 encoding 하게 된다.”

  1. URL의 user:1q2w3e! 부분을 parsing 하여
  2. Base64를 통해 encoding을 하고
  3. 그렇게 변환된 문자열을 같게되고
  4. 요청 헤더Authorization에 넣어서 보내주는 개념이다.

request_header_login

여기까지가 기본적으로 로그인한 상태의 로직이다.”

  1. Client가 encoding 한 요청 헤더를 Server에 요청하게 된다.
  2. Server가 DB checking을 하고
  3. DB에 값이 있으면 Client에 OK 사인을 주게 된다.

Request Header만 활용할 시 문제점

  • 어떤 처리를 할 때(ex) 등록, 수정, 삭제 등…) 매번 인증을 해야 하는 번거로움이 발생하게 된다.
  • 이걸 해결하기 위해 Browser의 Storage를 활용하게 된다.

Browser 활용하기

  • Browser의 Storage 종류
    1. Local Storage
    2. Cookie Storage
    3. Session Storage

cookie_storage

Cookie Storage의 로직

  1. Cookie에 사용자의 ID, PW를 넣는고 인증이 필요한 요청을 할 때 Cookie도 같이 Server에 보내준다.
  2. Server는 DB에 쿠키에 담은 정보를 확인 요청하게 된다.
  3. DB는 Server가 요청한 DB 값이 있는지 확인 후 callback 해준다.
  4. Server는 다시 client에 callback 해준다. 그리고 사용자는 원하는 자원을 얻을 수 있다.
  • 사용자 입장에서는 굉장히 편리한 방법이다.

hacking

  • 하지만, 해커의 입장에서도 굉장히 편리한 방법이다.
    1. 보안에 취약하게 노출되어 있어 사용자 정보를 쉽게 탈취할 수 있게 된다.
    2. ClientServer보다 상대적으로 보안이 취약하다는 단점이 있다.
  • 이러한 두 가지 단점을 해결하기 위해(보안 향상) Session을 활용하여 Server에 도움을 요청하게 된다.

Session Storage

session_storage

Session Storage의 로직. 1번부터 3번의 로직은 Cookie Storage와 같다.”

  1. Cookie에 사용자의 ID, PW를 넣는고 인증이 필요한 요청을 할 때 Cookie도 같이 Server에 보내준다.
  2. Server는 DB에 쿠키에 담은 정보를 확인 요청하게 된다.
  3. DB는 Server가 요청한 DB 값이 있는지 확인 후 callback 해준다.
  4. Session은 인증된 사용자의 식별자와, 랜덤 한 문자열SESSIONID를를 만들어서
  5. 응답(Response Header)로 넘겨주고
  6. Client가 저장할 수 있도록 하는 것이다.

장점

  1. Client의 보안이 낮은 데이터를 갖고 있게 되지 않게 된다. 그렇게 되면 해커가 정보를 가져가게 되더라도 크게 위험하지 않게 된다.
  2. SESSION만료기간을 설정할 수 있어 해커가 가져가게 되더라도 기한이 만료되면 유효하지 않게 되는 장점이 있다.
  3. Session의 관리Server 자체에서 하고 있어 탈취된 Session을 Server에서 삭제하게 되면 더 이상 Session을 사용하지 못하게 된다.

단점

session_load_balancer

“중간에 Load Balancer가 여러 대의 서버에 요청하게 된다.”

  1. 서비스가 잘 돼서 서버를 여러 개 두게 되면 로드 밸런서도 생기게 된다.
    • Load Balancer 란? : 서버에 가해지는 트래픽을 여러 대의 서버에서 균등하게 분산시켜주는 역할.
  2. 한 번 인증돼서 SESSIONID를 받게 되면 다음 요청 땐 Session으로만 이용해서 요청하게 된다.
  3. 그 말은 이젠 DB까지 확인하지 않고 Server에서 Session을 확인하여 처리할 수 있게 됐다는 뜻이다.

session_load_balancer2

“이 상황에서 user가 두 번째 인증 요청을 보내게 된다.”

  1. 1번째 인증을 완료하고 2번째 인증이 필요해 다시 요청을 보내게 된다.
  2. 그런데, 로드 밸런서가 SESSIONID 값이 저장되어 있는 3번째 서버가 아닌 2번째 서버에 요청을 보내게 된다.
  3. 2번째 서버에는 SESSIONID 값이 없어 오류가 발생하게 된다.
  4. 이 문제의 원인은 Server 하나하나 자체에서 Session을 관리하고 있기 때문에 문제가 발생하게 된다.

문제 해결 - 세션 DB

session_storage_db

Session Storage(세션 DB)를 통해 SESSIONID 요청을 한 DB(Session Storage)에 요청하여 해결. 그런데…”

또 다른 문제 발생 - 세션 DB의 문제

session_storage_problem

  • Client가 많아져서 요청이 많아지게 되면 Session Storage에 과부하가 생겨 DB가 터지게 된다.
  • 사용자를 위해 Cookie나 Browser의 힘을 빌려서 계속 로그인까지 하게 해줬는데 이젠 보안상의 문제가 생겨 Server 쪽에 와서 인증/인가를 해줬더니 문제가 계속 발생하게 된다.

Stateful/Stateless

stateful_stateless.png

  • Client, Server, Session 저장소 3가지 모두 사용자의 상태를 관리할 수 있게 하였다. 그랬더니 문제가 발생하였다.
  • 그 이유는 ClientServer가 서로 통신할 때 사용하는 http와 Server 자체가 지향하는 REST API무상태성(Stateless)을 기초로 하기 때문이다.
  • 그런데, 실제로 인증과 인가를 구현할 때에는 사용자의 정보, 상태를 Client, Server, Session 저장소 3군데 모두 가지고 있었다.
  • 그 말은 상태성을 갖고 있다는 이야기다.
  • 두 패러다임충돌되고 있다. 두 패러다임의 충돌을 해소해 보자.
  • Client, Server, Session 저장소 모두 상태를 맡겨보았으니 나머지 통신(정보의 흐름)에 맡겨보자.
  • 요청과 응답 안에 사용자의 상태를 담아보자. 그걸로만 사용자의 인증과 인가를 처리하자.
  • 그것이 바로 TOKEN을 활용한 인증인가이다.

JWT

jwt

Secret key를 사용해서 JWT만들어 내고 인증 과정을 거친다.”

  • JWT 자체는 해독하기 무척 쉽기 때문에 JWT 내에는 민감한 정보(PW)를 대부분 담지 않는다.
  • 그리고 Secret key 중요한 만큼 노출되면 JWT 자체도 끝이 난다.
  • 그래서 토큰을 사용하기 위해서는 Secret key 서버 내부에 잘 관리해야 한다.

JWT 활용하기

jwt_work_flow

JWT 로직”

  1. 요청을 보낸다.
  2. Server에서 DB로 ID, PW를 체크한다.
  3. 체크가 완료되면
  4. Secret key를 이용해서 토큰을 만들어 낸다.
    • 실제로는 더 길 수 도 있다.
  5. Secret key를 이용 만든 토큰을
  6. header에 담아서 Client에 보내준다.
  7. 다음부터 사용자는 해당 JWT요청과 응답을 받는 형태가 된다.

JWT 좀 더 알아보기

token

token

  1. Client로부터 서버로 요청이 왔다.
  2. 유효성 검사서버에 있는 Secret key로 진행하게 된다.
  3. 거기서 유효하지 않게 되면 버리게 되고, 유효하게 되면 다음 단계인 사용자 정보를 파악하게 된다.
  4. decoding 하기 쉽기 때문에 사용자 정보 중에 이름으로 어떤 사용자인지 찾아낸다.
  5. 만료 시기로 토큰의 만료 시기를 활용할 수 있다.
  6. 권한으로 사용자의 권한(사용자/어드민 등)을 확인할 수 있다.
  7. 주의, 비밀번호는 담으면 안 된다. 비밀번호를 담게 되면 디코딩을 쉽게 할 수 있다는 점 때문에 노출되기 쉽기 때문이다.
  8. Secret key를 통해서 유효성 검사를 통과한 토근은 이미 인증을 받은 토큰이다.

JWT 장점

jwt_strengths

jwt의 장점

  1. Session Storage같은 경우 Session DB와 연관성이 있었는데, 이제는 로드 밸런서가 요청하는 곳에 각자 서버가 가진 Secret key로 해독해서 인증을 진행하면 된고 요청을 반환하면 된다는 장점이 있다.
  2. 확장성이 좋아 서버가 많아져도 똑같이 진행할 수 있다.

Token 단점

jwt_weaknesses

  1. 해킹을 당할 수 있다.
  2. Access Token이 탈취 당하면 해당 해커는 사용자와 똑같은 지위를 갖게 된다.

Token 만료기한

  1. Token 만료기한을 설정해 놓으면 만료기간 이후 해커뿐만 아니라 사용자도 사용할 수 없게 된다.
  2. 그래서 사용자 입장에선 굉장히 불편할 수 있다.

Refresh Token

refresh_token

Refresh Token은 위 문제를 해결하고자 나온 Token 방식이다.”

  1. 요청을 보낸다.
  2. Secret key를 통해 Token을 만들어 낸다. 이때 Access TokenRefresh Token을 한 번에 만들어 낸다.
  3. 그리고 Access Token은 저장하지 않고, Refresh Token만 따로 저장소에 저장하게 된다.
  4. Access TokenRefresh Token을 한 번에 응답 헤더(Response Header)로 보내게 된다.
  5. Client는 둘 다 저장하게 된다.
  6. 2번에서 만든 Access TokenServer에 저장하지 않는다.
  7. 다음부터는 ClientAccess Token을 이용하여 요청을 보내게 된다.

Access Token 만료

access_token_expire

Access Token만료되면…
사용자는 Access Token만료되었다는 사실을 모르고, 알 필요도 없다.”

  1. 사용자는 똑같이 요청을 보내게 된다.
  2. 만료된 access token 이면 만료되었다고 Client에 알려준다.
  3. 그럼 Client는 다시 Access TokenRefresh Token을 한 번에 Server에 요청하게 되어 저장소에 있는 Refresh Token을 비교하고 확인되면
  4. Secret key를 이용하여 갱신Access Token을 다시 발급해 주고 준다.
  5. 사용자는 갱신된 Access Token을 사용하여 다음 요청들을 보내게 된다.
  6. 만약, Refresh Token이 만료(7일 이전( 예) 2023.01.25 ~ 만료기한 2023.02.01)) 되었다면, Secret key를 통해 Access TokenRefresh Token을 다시 발급하여 위와 같은 로직을 수행하게 된다.

Token 핵심

Token 장점

  1. 토큰으로 상태 관리를 하기에 따로 세션을 둘 필요가 없다.
  2. 효율성좋아지고, DB에 요청하여 직접 확인하지 않아도 되기 때문에 속도가 빠르다.

Token 단점

  1. 토큰 관리를 해야 하며, 결국 토큰도 탈취당할 수 있다.
  2. 보안에 있어 꾸준히 신경 써야 한다.

마치며 - 더 공부해야 할 것들

보안(Security)

  • Token
    • JWT
  • OAuth
    • OAuth1.0
    • OAuth2.0
  • 인증 방법
    • 인증 서버
  • Option
    • HttpOnly : 서버에서 클라이언트로 정보를 보낼때 보낸 정보에 달아주는 옵션. Storage에 저장된 정보에 함부로 접근할 수 없게 만드는 옵션.
  • Sliding Session : Refresh Token상호 보안적인 것.
  • Refresh Token : Sliding Session상호 보안적인 것.
  • SSL/TLS1.3 : 접근하기 쉽고 가성비 좋은 보안 방법. => HTTPS(가장 추천하는 방식)
  • Haking 방법

Continue with [Security] OAuth

[SQL] SQLD 핵심 요약 - [1과목] Part2. 데이터 모델과 성능

[SQL] SQLD 핵심 요약 - [1과목] Part2. 데이터 모델과 성능

#목차

데이터 모델과 성능

성능 데이터 모델링

  • DB 성능 샹항을 목적으로 설계 단계의 데이터 모델링 떄부터 정규화, 반정규화, 테이블 통합, 테이블 분할, 조인 구조, PK, FK등 여러 가지 성능과 관련된 사항이 데이터 모델링에 반영될 수 있도록 하는 것
  • 분석/설계 단계에서 데이터 모델에 성능을 고려한 데이터 모델링을 수행할 경우 성능저하에 따른 재업무 비용을 최소화 할 수 있는 기회를 가지게 된다.
  • 데이터의 증가가 빠를수록 성능저하에 따른 성능개선비용은 기하급수적으로 증가하게 된다.

성능 데이터 모델링 고려사항 순서

  1. 데이터 모델링을 할 때 정규화를 정확하게 수행
  2. DB 용량 산정을 수행한다.
  3. DB에 발생되는 트랜잭션의 유형을 파악한다.
  4. 용량과 트랜잭션의 유형에 따라 반정규화를 수행
  5. 이력모델의 조정, PK/FK조정, 슈퍼/서브타입 조정
  6. 선능관점에서 데이터 모델을 검증한다.
  • 기본적으로 데이터는 속성간의 함수종속성에 근거하여 정규화되어야 한다.
  • 겅규화는 선택이 아니라 필수사항

함수적 종속성

  • 데이터들이 어떤 기준 값에 의해 종속되는 현상

정규화

  • 반복적인 데이터를 분리하고 각 데이터가 종속된 테이블에 적절하게 배치되도록 하는 것
  • 칼럼에 의한 반복, 중복적인 속성 값을 갖는 형태는 1차 정규화의 대상

반정규화

  • 정규화된 엔티티, 속성, 관계에 대해 시스템의 성능향상과 개발과 운영의 단순화를 위해 중복, 통합, 분리 등을 수행하는 데이터 모델리으이 기법
  • 일반적으로 정구화시 입력/수정/삭제 성능이 향상되며 반정규화시 조인 성능이 향상된다.

반정규화 절차

  1. 반정규화 대상조사(범위처리 빈도 수, 범위, 통계성)
  2. 다른 방법유도 검토(뷰, 클러스터링, 인덱스 조정)
  3. 반정규화 적용(테이블, 속성, 관계 반정규화)

반정규화 대상조사

  1. 자주 사용되는 테이블에 접근하는 프로세스의 수가 많고 항상 일정한 범위만을 조회하는 경우
  2. 테이블에 대량의 데이터가 있고 대량의 데이터 범위를 자주 처리하는 경우에 처리범위를 일정하게 줄이지 않으면 성능을 보장할 수 없는 경우
  3. 통계성 프로세스에 의해 통계 정보를 필요로 할 때 별도의 통계 테이블을 생성한다
  4. 테이블에 지나치게 많은 조인이 걸려 데이터를 조회하는 작업이 기술적으로 어려울 경우 SORTING, ORDER BY는 반정규화 대상X

다른방법유도 검토

  1. 지나치게 많은 조인이 걸려 데이터를 조회하는 작업이 기술적으로 어려울 경우 VIEW를 사용한다
  2. 대량의 데이터처리나 부분처리에 의해 성능이 저하되는 경우 클러스터링을 적용하거나 인덱스를 조정함
  3. 대량의 데이터는 PK의 성격에 따라 부분적인 테이블로 분리할 수 있다(파티셔닝 기법)
  4. 응용 애플리케이션에서 로직을 구사하는 방법을 변경함으로써 성능을 향상시킬 수 있다.

반정규화의 기법(테이블, 칼럼, 관계)

테이블 반정규화

  • 테이블 병합(1:1관계, 1:M관계, 슈퍼/서브타입)
    1. 1:1관계를 통합하여 선능향상
    2. 1:M관계를 통합하여 선능향상
    3. 슈퍼/서브 관계를 통합하여 성능향상
  • 테이블 분할(수직분할, 수평분할)
    1. 수직분할 : Column단위 테이블을 디스크 I/O를 분산처리하기 위해 테이블을 1:1로 분리하여 성능향상
    2. 수평분할 : Row단위 집중 발생되는 트랜잭션을 분석하여 디스크 I/O 및 데이터 접근의 효율성을 높여 성능을 향상하기 위해 Row단위로 테이블을 쪼갬
  • 테이블 추가(중복, 통계, 이력, 부분 테이블 추가)
    1. 중복 : 다른 업무이거나 서버가 다른 경우 동일한 테이블구조를 중복하여 원격조인을 제거하여 성능 향상
    2. 통계 : SUM, AVG, 등을 미리 수행하여 계산해 둠으로써 조회 시 성능을 향상
    3. 이력 : 이력테이블 중에서 마스터 테이블에 존재하는 레코드를 중복하여 이력테이블에 존재시켜 성능 향상
    4. 부분 : 하나의 테이블의 전체 칼럼 중 자주 이용하는 집중화된 칼럼들이 있을 때 디스크 I/O를 줄이기 위해 해당 칼럼들을 모아 놓은 별도의 반정규화된 테이블을 생성

칼럼 반정규화(중복, 파생, 이력, PK, 오작동)

  1. 중복 : 조인에 의해 ㅓ리할 때 성능저하를 예방하기 위해 중복된 칼럼을 위치 시킴
  2. 파생 : 트랜잭션이 처리되는 시점에 계산에 의해 발생되는 성능저하를 예방하기 위해 미리 값을 계싼하여 칼럼에 보관
  3. 이력테이블 : 대량의 이력데이터를 처리할 때 불특정날 조회나 최근 값을 조회할 때 나타날 수 있는성능저하를 예방하기 위해 이력테이블에 가능성 칼럼(최근값 여부, 시작과 종료일자 등)을 추가함
  4. PK에 의한 칼럼 추가 : 이미 PK안에 데이터가 존재하지만 선능향상을 위해 일반속성으로 포함하는 방법
  5. 응용시스템 오작동을 위한 칼럼 추가 : 업무적으로는 의미가 없지만 사용자의 실수로 원래 값으로 복귀하기 원하는 경우 이전 데이터를 임시적으로 중복하여 보관하는 기법

관계 반정규화

중복관계 추가

  • 데이터를 처리하기 위한 여러 경로를 거쳐 조인이 가능하지만 이 때 발생할 수 있는 성능저하를 예방하기 위해 추가적인 관계를 맺는 방법

로우 체이닝

  • 로우의 길이가 너무 길어서 데이터 블록하나에 데이터가 모두 저장되지 않고 두 개 이상의 블록에 걸쳐 하나의 로우가 저장되어 있는 형태

로우 마이그레이션

  • 데이터 블록에서 수정이 발생하면 수정된 데이터를 해당 데이터 블록에서 저하지 못하고 다른 블록의 빈 공간을 찾아 저장하는 방식
  • 로우 체이닝과 로우 마이그레이션이 발생하여 많은 블록에 데이터가 저장되면 DB 메모리에서 디크스 I/O가 발생할 때 많은 I/O가 발생하여 성능저하 발생
  • 트랜잭션을 분석하여 적절하게 1:1관계로 분리함으로써 성능향상이 가능하도록 해야 한다.

PK에 의해 테이블을 분할하는 방법(파티셔닝)

  1. RANGE PARTITION
    • 대상 테이블이 날짜 또는 숫자 값으로 분리가 가능하고 각 영역별로 트랜잭션이 분리되는 경우
    • ex) PARTITION BY COL1 ORDER BY COL3 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  2. LIST PARTITION
    • 지점, 사업소 등 핵심적인 코드값으로 PK가 구성되어 있고 대량의 데이터가 있는 테이블의 경우
  3. HASH PARTITION
    • 지정된 HASH 조건에 따라 해시 알고리즘이 적용되어 테이블이 분리

테이블에 대한 수평/수직분할의 절차

  1. 데이터 모델링을 완성한다.
  2. DB 용량산정을 한다.
  3. 대량 데이터가 처리되는 테이블에 대해 트랜잭션 처리 패턴을 분석한다.
  4. 칼럼 단위로 집

수퍼/서브 타입 모델

  • 슈퍼/서브타입에 대한 변환을 잘못하면 성능이 저하되는 이유
    • 트랜잭션의 특성을 고려하지 않고 테이블을 설계했기 때문
  1. 트랜잭션은 항상 일괄로 처리하는데 테이블은 개별로 유지되어 Union연산에 의해 성능이 저하될 수 있다.
  2. 트랜잭션은 항상 서브타입 개별로 처리하는데테이블은 하나로 통합되어 있어 불필요하게 많은 양의 데이터가 집약되러 있어 성능이 저하되는 경우가 있다.
  3. 트랜잭션은 항상 슈퍼+서브 타입을 공통으로 처리하는데 개별로 유지되어 있거나 하나의 테이블로 집약되어 있어 성능이 저하되는 경우가 있다.

Back to [SQL] SQLD 핵심 요약 - [1과목] Part1. 데이터 모델링의 이해

Continue with [SQL] SQLD 핵심 요약 - [1과목] Part2. 데이터 모델과 성능

[SQL] SQLD 핵심 요약 - [1과목] Part1. 데이터 모델링의 이해

[SQL] SQLD 핵심 요약 - [1과목] Part1. 데이터 모델링의 이해

#목차

데이터 모델링의 이해

모델링의 특징

  • 추상화 : 현실세계를 인정한 형식에 맞추어 표현
  • 단순화 : 복잡한 현실세계를 약속된 규약에 의해 제한된 표기법이나 언어로 표현
  • 명확화 : 누구나 이해하기 쉽게 대상에 대한 애매모호함 제거

모델링의 세 가지 관점

  • 데이터 관점 : 업무가 어떤 데이터와 관련이 있는지, 데이터간 관계가 무엇인지 (What, Data)
  • 프로세스 관점 : 업무가 실제로 하고있는 일이 무엇인, 무엇을 해야하는지 (How, Process)
  • 상관 관점 : 업무 처리하는 방법에 따라 데이터가 어떻게 영향을 받고 있는지 (Interaction)

데이터 모델링의 기능

  • 명세화, 구조화, 문서화, 다양한 관점, 상세수준 표현

데이터 모델링의 중요성 및 유의점

  • 중복 : 같은 시간 같은 데이터 제공
  • 비유연성 : 사소한 업무변화에 데이터 모델이 수시로 변경되면 안됨
  • 비일관성 : 신용 상태에 대한 갱신 없이 고객의 납부이력 정보 갱신 안됨(연계성이 떯어짐)

데이터 모델링의 3단계 진행

  • (추상적)개념적 -> 논리적 -> 물리적(구체적)
    • 개념적 데이터 모델링(in계획분석단계) : 추상화, 업무중심적, 포괄적, 전사적, EA수립시 사용
    • 논리적 데이터 모델링(in분석단계) : KEY, 속성, 관계 표현, 재사용성 높음(정규화)
    • 물리적 데이터 모델링(in설계단계) : 실제 데이터베이스를 이식할 수 있도록 성능, 저장 등 무릴적 성격 고려

데이터 독립성 요소

  • 왜부 스키마 : 개개 사용자가 보는 개인적 DB 스키마
  • 개념 스키마 : 모든 사용자 관점을 통합한 전체 DB
  • 내부 스키마 : 물리적 장치에서 데이터가 실제적 저장

데이터 독립성

  • 논리적 독립성 : 개념 스키마가 변경되어도 외부 스키마에 영향X
  • 물리적 독립성 : 내부 스키마가 변경되어도 외부/개념 스키마는 영향X

Mapping(사상)

  • 상호 독립적인 개념을 연결시켜주는 다리

데이터 모델링의 3요소

  • 어떤 것(Things), 성격(Attributes), 관계(Relationships)
  • 데이터 모델링은 프로젝트에 참여한 모두가 알아야 한다
  • 엔티티: 집합 / 인스턴스 : 단수

데이터 모델 표기법

  • 1976년 피터첸이 Entity Relationships Model 개발

ERD 작업 순서

  1. 엔티티를 그림
  2. 엔티티를 적절하게 배치
  3. 엔티티간 관계를 설정
  4. 관계명을 기술
  5. 관계의 참여도를 기술
  6. 관계의 필수여부를 기술

좋은 데이터 모델의 요소

  1. 완전성 : 업무에 필요한 모든 데이터가 모델에 정의
  2. 중복배제 : 하나의 DB내에 동일한 사실은 한번만
  3. 업무규칙 : 많은 규칙을 사용자가 공유하도록 제공
  4. 데이터 재사용 : 데이터가 독립적으로 설계돼야 함
  5. 의사소통 : 업무규칙은 엔티티, 서브타입, 속성, 관계 등의 형태로 퇴대한 자세히 표현
  6. 통합성 : 동일한 데이터는 한 번만 정의, 참조활용

엔티티란?

  • 업무에 필요하고 유용한 정보를 저장하고 관리하기 위한 집합적인 것, 보이지 않는 개념 포함

엔티티의 특징

  1. 반드시 해당 업무에서 필요하고 관리하고자 함
  2. 유일한 식별자에 의해 식별 가능
  3. 두 개 이상의 인스턴스의 집합
  4. 업무 프로세스에 의해 이용되어야 함
  5. 반드시 속성이 있어야 함(예외적으로 관계엔티티 경우는 주식별자 속성만 가지고 있어도 엔티티로 인정)
  6. 다른 엔티티와 최소 1개 이상의 관계가 있어야 함(관계를 생략하여 표현해야하는 경우는 통계성 엔티티, 코드성 엔티티, 시스템 처리시 내부 필요에 의한 엔티티 도출과 같은 경우)

엔티티의 분류

유무형에 따른 분류

  • 유형 : 물리적 형태, 안정적, 지속적 ex)사원, 물품, 강사
  • 개념 : 개념적 정보, 물리적 형태X ex)조직, 보험상품
  • 사건 : 업무수행시 발생, 통계자료 이용 ex)주문, 청구, 미납

발생시접에 따른 분류

  • 기본 : 그 업무에 원래 존재하는 정보, 타 엔티티의 부모 역할, 자신의 고유한 주식별자 가짐 ex)사원, 부서
  • 중심 : 기본 엔티티로부터 발생, 다른 엔티티와의 관계로 많은 행위 엔티티 생성 ex)계약, 사고, 주문
  • 행위 : 2개 이상의 부모엔티티로부터 발생, 자주 바뀌거나 양이 증가 ex)주문목록, 사원변경이력

엔티티의 명명

  • 현업업무에서 사용하는 용어 사용, 약어 사용금지, 단수명사 사용, 고유한 이름 사용, 생성의미대로 부여

속성

  • 업무에서 필요로 하는 인스턴스로 관리하고자 하는 의미상 분리되지 않는 최소의 데이터 단위
  • 한 개의 엔티티는 2개 이상의 인스턴스 집합
  • 한 개의 엔티티는 2개 이상의 속성을 가짐
  • 한 개의 속성은 1개의 속성값을 가짐

속성의 분류

  • 기본 : 업무로부터 추출한 모든 일반적인 속성
  • 설계 : 업무를 규칙화하기 위해 새로 만들거나 변형, 정의하는 속성 ex)일련번호
  • 파생 : 다른 속성에 영향을 받아 발생하는 속성, 빠른 성능을 낼 수 있도록 원래 속성의 값을 계산 ex)합

도메인

  • 각 속성이 가질 수 잇는 값의 범위 ex)5글

속성의 명명

  1. 해당업무에서 사용하는 이름 부여
  2. 서술식 속성명은 사용 금지
  3. 약어 사용 금지
  4. 전체 데이터모델에서 유일성 확보

관계

  • ** 엔티티의 인스턴스 사이의 논리적인 연관성으로서 존재의 형태로서나 행위로서 서로에게 연관성이 부여된 상태
    • 존재에 의한 관계 ex)소속된다
    • 행위에 의한 관계 ex)주문한다

패어링

  • 엔티티 안에 인스턴스가 개별적으로 관계를 가지는 것

UML

  • UML에는 연관관계와 의존관계가 있는데, 연관(존재적)관계는 항상 이용하는 관계이고 의존관계는 상대방 행위에 의해 발생하는 관계

ERD

  • ERD에서는 존재적 관계와 행위에 의한 관계를 구분하지 않고 표기했지만 UML에서는 이를 구분하여 연관관계는 실선, 의존관계는 점선으로 표현

관계의 표기법

  • 관계명 : 관계의 이름
  • 관계차수 : 1:1(One to One), 1:M(One to Many), M:N(Many to Many(n개))
  • 관계선택성(관계선택사양) : 필수관계, 선택관계

관계 체크사항

  1. 2개의 엔티티 사이에 관심있는 연관 규칙 O/X?
  2. 2개의 엔티티 사이에 정보의 조합 발생 O/X?
  3. 업무기술서, 장표에 관계연결에 대한 규칙 서술 O/X?
  4. 업무기술서, 장표에 관계연결을 가능케 하는 동사 O/X?

식별자

  • 엔티티내에서 인스턴스를 구분하는 구분자 식별자는 논리 데이터 모델링 단계에 사용
  • key는 물리 데이터 모델링 단계에 사용

식별자의 특징 : 유일성, 최소성, 불변성, 존재성

  1. 주식별자에 의해 모든 인스턴스들이 유일하게 구분
  2. 주식별자를 구성하는 속성의 수는 유일성을 만족하는 최소의 수가 되어야 함
  3. 지정된 주식별자의 값은 자주 변하지 않아야 함
  4. 주식별자가 지정이 되면 반드시 값이 들어와야 함

식별자 분류

대표성여부 : 주식별자, 보조식별자

  • 주식별자 : 엔티티 내에서 각 어커런스를 구분할 수 있는 구분자, 타 엔티티와 참조관계를 연결할 수 있음
  • 보조식별자 : 어커런스를 구분할 수 있는 구분자이나 대표성을 가지지 못해 참조관계 연결 불가

스스로 생성여부 : 내부식별자, 외부식별자

  • 내부식별자 : 스스로 생성되는 식별자
  • 외부식별자 : 타 엔티티로부터 받아오는 식별자

속성의 수 : 단일식별자, 복합식별자

  • 단일식별자 : 하나의 속성으로 구성
  • 복합식별자 : 2개 이상의 속성으로 구성

대체 여부 : 본질식별자, 인조식별자

  • 본질식별자 : 업무에 의해 만들어지는 식별자
  • 인조식별자 : 인위적으로 만든 식별자

주식별자 도출기준

  1. 해당 업무에서 자주 이용되는 속석임
  2. 명칭, 내역 등과 같이 이름으로 기술되는 것들은 X
  3. 복합으로 주식별자로 구성할 경우 너무 많은 속성 X

식별자 관계

주식별자

  • 자식의 주식별자로 부모의 주식별자 상속
    • 부모로부터 받은 식별자를 자식엔티티의 주식별자로 이용하는 경우

비식별자

  • 부모 속성을 자식의 일반 속성으로 사용
    1. 부모 없는 자식이 생성될 수 있는 경우
    2. 부모와 자식의 생명주기가 다른 경우
    3. 여러개의 엔티티가 하나의 엔티티로 통합되어 표현되었는데 각각의 엔티티가 별도의 관계를 가진 경우
    4. 자식엔티티에 별도의 주식별자를 생성하는 것이 더 유리한 경우
    5. SQL 문장이 길어져 복잡성 증가되는 것 방지
      • 약한 연결관계 표현, 점선 표기
      • 자식 주식별자구성을 독립적으로 구성

Continue with [SQL] SQLD 핵심 요약 - [1과목] Part2. 데이터 모델과 성능

[Java] JVM Stack & Heap

[Java] JVM Stack & Heap

“해당 포스팅은 우아한Tech[10분 테코톡] 🎅무민의 JVM Stack & Heap의 영상을 기반으로 포스팅하였습니다. 또한 설명이 너무 잘되어었어 복습하고자 글로 남깁니다. 영상을 제작해주신 우아한Tech무민님에게 감사드립니다.”

#목차

JVM(Java Virtual Machine)이란?

태초에 문제가 있었다…

  • C/C++는 컴파일 플랫폼과 타겟 플랫폼이 다를 경우, 프로그램이 동작하지 않는다. 플랫폼은 운영체제와 CPU 아키텍처의 조합이다.(플랫폼 = 운영체제(MacOS) + CPU 아키텍처(Apple M1))
  • C나 C++는 Compile하고 나면 그 기계 code가 타겟 플랫폼이 dependent(의존)하기 때문에 Compile하는 플랫폼이랑 다를 경우에는 동작할 수 없다.
  • 왜냐하면 OS마다 지원하는 System Call Interface(시스템 호출))가 다르고, CPU 아키텍쳐 마다 지원하는 ISA(Instruction Set Architecture)가 다르다.
    • System Call Interface 란 : Application이 운영체제(OS)에 있는 function(함수(기능))을 호출 하는 것을 의미한다.
    • ISA(Instruction Set Architecture) 란 : 명령어 집합 구조이며, 마이크로프로세서가 인식해서 기능을 이해하고 실행 할 수 있는 기계어 명령어를 말한다.

개발할 때는 문제가 없다

  • 동일한 플랫폼에서 컴파일과 실행을 같이 한다면, 프로그램은 아무 문제없이 동작한다.

same_os

  • macOS에서 compile하고 macOS에서 실행하게 되면 아무런 문제가 없다.
  • 보통 local에서 test 작업을 할 때 많이 사용하는 방법.
  • C/C++도 이와 같은 방법은 잘 작동한다.
  • 문제는…

배포할 때 문제가 발생한다

  • 플랫폼이 달라질 경우, 타겟 플랫폼에서 프로그램이 동작하지 않는다.

other_os

  • macOS에서 compile해서 나온 실행 파일(.exe)을 window로 실행하게 되면 실행되지 않는다.
  • 이게 문제이다… 이걸 해결하기 위해선…

크로스 컴파일(Cross Compile)

  • 타겟 플랫폼에 맞춰 컴파일하는 것을 ‘크로스 컴파일’이라 한다.

cross_compile

  • macOS에서 windows로 타겟을 잡고 컴파일을 할 수 있다.
  • 그렇게 나온 타겟 프로그램은 windows에서 실행이 가능하다.
  • 이런식으로 C/C++같은 언어들은 Cross Compile을 이용하여 타겟 프로그래밍을 작업 하였다.

JVM(Java Virtual Machine)으로 문제 해결

solving

[그림출처](https://www.researchgate.net/figure/Java-virtual-machine-task-exchange-on-a-loosely-coupled-network_fig3_334064226)
  • Java 소스 코드가 .jacac라는 Compile을 거치고 나면 Java Bytecode가 된다.
  • 이 Java Bytecode는 JVM이 설치된 플랫폼이라면 어떤 플랫폼이던 상관 없이 잘 동작하게 된다.
  • 물론, JVM이 플랫폼과 관련된 작업들을 대신 해주기 때문에 가능한 것이다.
  • 만약 배포하게 되는 곳의 OS가 linux면 linux용 JVMwindows면 windows의 JVM을 설치하게 된다면 macOS에서 build 하여 compile한 소스 코드들을 다른 OS에서 실행할 수 있게 JVM이 작업을 해준다.

WORA

Write Once, Run Anywhere(WORA)” - Sun Mycrosystems

wora

[그림출처](https://miro.medium.com/max/1400/1*8unTYz6pOhwryEb5b1S2Sg.png)
  • 즉, 당신이 코딩한 Java 코드를 Compile해서 배포하면, 어떤 플랫폼이든 다시 Compile할 필요 없이 실행시킬 수 있다. 단, 실행하려면 해당 플랫폼에 맞는 JVM을 설치되어 있어야 한다.

굳이 JVM?

  • C/C++도 Cross Compile해서 배포하면 되는데, 굳이 JVM을 사용해야 하는가? 굳이 JVM을 도입한 이유가 뭘까?
    • Java가 나오던 시기(1990년대)는 네트워크가 발전하던 시기이다.
    • 네트워크로 모든 것들이 연결 되고 다 기종의 디바이스에서 실행하기 위한 프로그램이 필요했다.
    • 그러나 C/C++은 당시에만 해도 Cross Compile을 해주는 번거러움이 발생했다.
      • 예를 들어 일반 운영체제 linux나 window가 아니라 Android, iOs, ubuntu, solaris 등등 등장하게 되어 Cross Compile에 한계가 생기기 시작하였다.
  • Java는 네트워크에 연결된 모든 디바이스에서 작동하는 것이 목적이었다.
  • 디바이스마다 운영체제나 하드웨어가 다르기 때문에, 자연스럽게 플랫폼에 의존(dependent)하지 않도록 언어를 설계했다. 그 결과가 Java Bytecode와 JVM이 등장하게 되었다.

Java의 야심

java's ambition

[그림출처](https://i.ytimg.com/vi/4Rk_zDimf2s/mqdefault.jpg)
  • Web Server에 .class파일이 있다.
    • .class파일 이란 : Java Bytecode를 담은 파일이다.
  • 해당 .class파일을 네트워크를 통해서 전달해주면 Web Browser에 JVM이 설치 되어 있어서 실행만 하면 된다.
    • 이것이 정확히 Javascript가 이런 동작을 하고 있다.
    • Javascript 정적 파일을 Web Browser에 보내주게 되면 Web Browser에 설치되어 있는 Javascript Runtime이 즉석에서 인터프리팅(interpreting)해서 실행하게 된다.
      • Compile 언어 : Java, C, C++, … -> 코드가 실행되기 전 Compiler를 거쳐서 기계어로 모두 변환되어 실행되는 프로그래밍 언어
      • Interpreter 언어 : 코드를 바로 실행하는 프로그램 또는 환경(웹 브라우저) -> Javascript(웹 브라우저), SQL(데이터베이스 언어), Python과 Ruby(자체 프로그래밍 언어)

Java 코드가 실행되기까지

compiler

  • 모든 Compiler는 위 그림과 같다.
  • Source Code가 Compiler의 여러 과정을 거쳐 Assembler가 된다.
  • AssemblerAssembly Language를 기계어 형태의 오브젝트 코드로 해석해 주는 컴퓨터 언어 번역 프로그램을 통해 기계어로 변환 된다.
  • Compile에도 Front-end, Back-end가 있다.
  • Web에서는 Backend는 크게 바뀌지 않고, Frontend가 Client종류(Web Browser)에 따라 바뀌게 된다.
  • Compile에서는 반대이다. Compile에서는 Frontend는 바뀌지 않는다.
  • 왜냐하면, Frontend가 하는게 개발자가 짠 Source Code를 분석해서 그 의미를 파악하는 것이다.
  • Abstract Syntax Tree(AST)가 추상적으로 표현하고, Intermediate Representation(IR)으로 번역하기 때문에 Frontend는 플랫폼과 아무 관련이 없다.
  • 그런데 Backend는 계속 바뀔 수 밖에 없는게 중앙 계층 표현(IR/IC)을 Assembly Language로 바꿔야 한다.
  • 그런데 이 Assembly Language라는 것은 운영체제(OS)나 기기에 dependent(의존)하기 때문에 Compiler의 구조에서 Backend만 Windows용, Linux용, MacOS용, 등…이 있는 것이고, 각 OS는 Frontend만 공유하는 것이다.
  • Compiler는 이러한 Layer Architecture로 되어있다.
  • C/C++ Compiler는 통째로 Compiler가 해준다.
  • 근데 Java에서 Frontend는 javac가 해주고, Backend는 JVM이 해준다. 결국 하는 일을 분리해 준 것이다.
  • 그래서 갖는 장점도 있다.
  • C언어는 한 번에 Compile 하고 나면 더 이상 개입할 수 없다.
  • 근데, 개발자들은 사전에 다 알 수가 없다. Runtime에서 어떤 일이 벌어질지…
  • Runtime에서만 발생하는 굉장히 소중한 정보들이 있고, 그 정보들을 이용해서 최적화를 하는 것이 JIT Compiler이다.

JVM 내부 구조

jvm

[그림출처](https://aljjabaegi.tistory.com/387)

Runtime Data Areas

jvm

[그림출처](https://www.devkuma.com/docs/jvm/memory-structure/)
  • JVM이 Java Bytecode를 실행하기 위해 사용하는 메모리 공간Runtime Data Area 라고 한다. 즉, JVM이 Java Bytecode를 실행하는 가상의 기계이다.

공유/개별 thread

per jvm

[그림출처](https://www.devkuma.com/docs/jvm/memory-structure/)
  • Method영역Heap영역모든 Thread가 공유하는 데이터 영역이다.
  • 반면, Stack영역PC Register, Native Method Stack 영역각 Thread마다 생성되는 개별 영역이다.

Method/Heap

method_heap

Method Area

  • Class Loader가 class파일을 읽어왔을때 클래스에 있는 정보들을 Parsing 해서 Method영역에 저장하는 곳.
  • 변수, 메소드, 정적 변수, Bytecode등을 저장하는 곳.

Heap Area

  • 프로그램을 실행하면서 생성한 모든 객체 Instance를 Heap에 저장하는 곳.

PC(Program Counter) Register

  • PC란 Program Counter의 줄임말이다.

pc register

  • 각 스레드는 어떤 메서드를 항상 실행하고 있다.
  • 그때, PC는 그 메서드 안에서 Bytecode 몇 번째 코드를 실행하고 있는지를 나타내는 역할을 한다.

Stack

stack

  • 스택은 스레드 별로 1개만 존재하고, 스택 프레임은 메서드가 호출될 때마다 생성된다.
  • 예를들어 스레드1에 빨간 네모칸스택이고, 아래로 성장하게 된다.
    1. 그때, 맨 위에 있는 stack framemain()메서드이다.
    2. 그리고 그 밑에 있는 stack frame은 main()메서드에서 호출한 어떠한 메서드이다
    3. 그 밑에 있는 stack frame은 그 메서드에서 호출한 또 다른 메서드이다
  • 즉, 메서드 호출 tree와 똑같다고 생각하면 된다.
  • 해당 메서드 실행이 끝나면 당연히 스택 프레임은 pop되어 스텍에서 제거 된다.

Stack Frame

  • 스택 프레임은 메서드가 호출될 때마다 새로 생겨 스택에 push 된다.
  • 스택 프레임 안에 들어가는 정보는 Local variables array, Operand stack, Frame Data를 갖는다.
  • Frame Data는 Constant Pool, 이전 스택 프레임에 대한 정보, 현재 메서드가 속한 클래스/객체에 대한 참조 등의 정보를 갖는다.
  • 즉, 쉽게 말해 Bytecode를 실행하기 위해 모두 필요한 것들이다.
  • 내 메서드가 어디에 속해있는지 등등…

Native Method Stack

Native Method Stack

  • JVM은 성능 향상 목적으로 Java Bytecode가 아닌 다른 언어로 작성된 코드를 compile하여 사용하는 경우가 있다. 그때 사용되는 메서드 이다.

Reference

[SQL] SQL과 NoSQL의 차이

[SQL] SQL과 NoSQL의 차이

#목차

SQL(Structured Query Language) 이란?

SQL

SQL
  • SQL(Structured Query Language) 관계형 데이터베이스(RDBMS) 또는 SQL 데이터베이스 작업을 위한 표준 언어이다.
  • SQL을 사용하여 데이터베이스 객체를 만들고 데이터베이스 레코드를 삽입(INSERT), 업데이트(UPDATE), 삭제(DELETE) 또는 쿼리를 조회(SELECT)할 수 있다.
  • SQL은 데이터베이스 최적화 및 유지 관리 또는 데이터 분석 수행과 같은 복잡한 작업에 사용될 수 있다.
  • SQL 데이터베이스에는 MySQL, Sybase, Microsoft SQL Server, Oracle 등이 많이 사용되고 있다.
-- Query 사용예
INSERT INTO EMPLOYEES (Name, Age, PhoneNumber) 
VALUES (“EMP1”, 21, “1234567890”);

데이터베이스 구조(DB Structure)

DB Structure

DB Structure
  • SQL 데이터베이스 구조의 데이터는 열(row)과 행(column)으로 구성된 테이블로 구성되어 있다.
  • SQL 데이터베이스는 수직적 구조로 새로운 데이터가 추가될 때마다 수직적으로 쌓이게 된다.

관계형 데이터베이스(Relational database)

DB Relation

DB Structure
  • 관계형 DB(RDBMS)는 데이터베이스에 저장된 데이터의 구조, 즉 데이터 스키마를 명확하게 정의하는 것 또한 매우 중요하다.
  • 테이블의 모든 레코드(column - fields)는 정의된 열(row)을 준수해야 하며, 해당 형식(테이블/행/열)에서만 데이터 조작을 수행할 수 있다.

NoSQL(Non SQL) 이란?

NoSQL

NoSQL
  • NoSQL은 고정 스키마가 필요하지 않고 쉽게 확장되며 조인을 수행할 수 없는 비관계형 데이터베이스이다.
  • 방대한 데이터 스토리지가 필요한 분산 데이터 저장소에 적합하여 빅데이터와 실시간 웹 앱에 많이 사용된다.
  • NoSQL 데이터베이스는 관계형 스키마에 데이터를 저장하지 않기 때문에 전체 테이블의 구조를 변경하거나 나머지 행에 중복 요소를 추가하지 않고도 즉시 데이터 속성을 추가할 수 있다.
  • NoSQL 데이터베이스는 수평적 확장이 뛰어나고 파티션 허용 오차가 기반에 내장되어 있어 많은 양의 데이터에 대해 1초 미만의 응답 시간이 필요한 시나리오에서 잘 작동한다.

NoSQL의 종류

NoSQL

NoSQL
  • NoSQL 데이터베이스는 수평적 구조로 새로운 데이터가 추가될 때마다 수평적으로 쌓이게 된다.

Document Databases

[
    {
        "title" : "The Thieves",
        "year" : 2012,
        "info" : {
            "directors" : [ "Choi Dong-hoon"],
            "release_date" : "2012-07-25T00:00:00Z",
            "rating" : 8,
            "genres" : ["Action", "Drama"],
            "image_url" : "https://en.wikipedia.org/wiki/The_Thieves#/media/File:The_Thieves.jpg",
            "plot" : "Ten Thieves. Only One Diamond. They began to Move.",
            "actors" : ["Kim Yoon-seok", "Kim Hye-soo", "Lee Jung-jae", "Jun Ji-hyun", "Simon Yam", "Kim Hae-sook", "Oh Dal-su", "Kim Soo-hyun", "Derek Tsang", "Angelica Lee", "Shin Ha-kyun"]
        }
    },
    {
        "title": "The Age of Shadows",
        "year": 2016,
        "info": {
            "plot": "Enemy or Comrade",
            "rating": 43
        }
    }
]
  • Document DB는 데이터를 JSON 형식의 문서로 데이터를 저장 및 쿼리하도록 설계된 비관계형 데이터베이스이다.
  • Document DB를 사용하면 개발자들이 자신의 애플리케이션 코드에서 사용하는 것과 동일한 문서 모델 형식을 사용하여 데이터베이스에서 보다 손쉽게 데이터를 저장하고 쿼리 작업을 할 수 있다.
  • Document DB는 문서 및 문서 데이터베이스의 유연하고 반구조화된 계층적 특성을 통해 개발자는 계속해서 애플리케이션의 요구를 발전시킬 수 있다.
  • Document DB유연한 인덱싱, 강력한 임시 쿼리, 문서 모음에 대한 분석을 지원한다.
  • Document DBMongoDB, CouchDB, MarkLogic 등이 있다.
// mongo DB Query 사용예
db.movies.insert(
    {
        "title" : "The Thieves",
        "year" : 2012,
        "info" : {
            "directors" : [ "Choi Dong-hoon"],
            // ...
        },
    },
    // ...
)

Key-Value-Based Databases

Key-Value-Based DB

Key-Value-Based DB
  • Key-Value DB는 키-값 메소드를 사용하여 데이터를 저장하는 비관계형 데이터베이스 유형이다.
  • Key-Value DB는 key를 고유한 식별자로 사용하는 키-값 쌍의 집합으로 데이터를 저장한다.
  • Key-Value DB는 단순한 객체에서 복잡한 집합체에 이르기까지 무엇이든 키와 값이 될 수 있으며 파티셔닝이 가능하고 다른 유형의 데이터베이스로는 불가능한 범위까지 수평 확장을 가능하게 한다.
  • Key-Value 기반 DB는 Redis, Memcache 등이 있다.


DynamoDB의 JAVA API를 활용한 key-value 데이터 CRUD 예제

/**
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * This file is licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License. A copy of
 * the License is located at
 *
 * http://aws.amazon.com/apache2.0/
 *
 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
*/

package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class DocumentAPIItemCRUDExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "ProductCatalog";

    public static void main(String[] args) throws IOException {

        createItems();

        retrieveItem();

        // Perform various updates.
        updateMultipleAttributes();
        updateAddNewAttribute();
        updateExistingAttributeConditionally();

        // Delete the item.
        deleteItem();

    }

    private static void createItems() {

        Table table = dynamoDB.getTable(tableName);
        try {

            Item item = new Item().withPrimaryKey("Id", 120).withString("Title", "Book 120 Title")
                .withString("ISBN", "120-1111111111")
                .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author12", "Author22")))
                .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                .withBoolean("InPublication", false).withString("ProductCategory", "Book");
            table.putItem(item);

            item = new Item().withPrimaryKey("Id", 121).withString("Title", "Book 121 Title")
                .withString("ISBN", "121-1111111111")
                .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author21", "Author 22")))
                .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                .withBoolean("InPublication", true).withString("ProductCategory", "Book");
            table.putItem(item);

        }
        catch (Exception e) {
            System.err.println("Create items failed.");
            System.err.println(e.getMessage());

        }
    }

    private static void retrieveItem() {
        Table table = dynamoDB.getTable(tableName);

        try {

            Item item = table.getItem("Id", 120, "Id, ISBN, Title, Authors", null);

            System.out.println("Printing item after retrieving it....");
            System.out.println(item.toJSONPretty());

        }
        catch (Exception e) {
            System.err.println("GetItem failed.");
            System.err.println(e.getMessage());
        }

    }

    private static void updateAddNewAttribute() {
        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 121)
                .withUpdateExpression("set #na = :val1").withNameMap(new NameMap().with("#na", "NewAttribute"))
                .withValueMap(new ValueMap().withString(":val1", "Some value")).withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after adding new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        }
        catch (Exception e) {
            System.err.println("Failed to add new attribute in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void updateMultipleAttributes() {

        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                .withUpdateExpression("add #a :val1 set #na=:val2")
                .withNameMap(new NameMap().with("#a", "Authors").with("#na", "NewAttribute"))
                .withValueMap(
                    new ValueMap().withStringSet(":val1", "Author YY", "Author ZZ").withString(":val2", "someValue"))
                .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after multiple attribute update...");
            System.out.println(outcome.getItem().toJSONPretty());

        }
        catch (Exception e) {
            System.err.println("Failed to update multiple attributes in " + tableName);
            System.err.println(e.getMessage());

        }
    }

    private static void updateExistingAttributeConditionally() {

        Table table = dynamoDB.getTable(tableName);

        try {

            // Specify the desired price (25.00) and also the condition (price =
            // 20.00)

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                .withReturnValues(ReturnValue.ALL_NEW).withUpdateExpression("set #p = :val1")
                .withConditionExpression("#p = :val2").withNameMap(new NameMap().with("#p", "Price"))
                .withValueMap(new ValueMap().withNumber(":val1", 25).withNumber(":val2", 20));

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after conditional update to new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        }
        catch (Exception e) {
            System.err.println("Error updating item in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void deleteItem() {

        Table table = dynamoDB.getTable(tableName);

        try {

            DeleteItemSpec deleteItemSpec = new DeleteItemSpec().withPrimaryKey("Id", 120)
                .withConditionExpression("#ip = :val").withNameMap(new NameMap().with("#ip", "InPublication"))
                .withValueMap(new ValueMap().withBoolean(":val", false)).withReturnValues(ReturnValue.ALL_OLD);

            DeleteItemOutcome outcome = table.deleteItem(deleteItemSpec);

            // Check the response.
            System.out.println("Printing item that was deleted...");
            System.out.println(outcome.getItem().toJSONPretty());

        }
        catch (Exception e) {
            System.err.println("Error deleting item in " + tableName);
            System.err.println(e.getMessage());
        }
    }
}

Column-Oriented/Family Databases

1.Column-Oriented Databases

Column Oriented DB

Column-Oriented DB
  • Column-Oriented DB는 Tabled의 data를 Column 단위로 쪼개어 저장하는 DB를 의미한다.
  • Column-Oriented DB는 하나의 Column이 하나의 Disk Block안에 저장된다.
  • Column-Oriented DB는 1개의 Block만 읽고 결과를 구할 수 있기 때문에 빠른 처리가 가능하다.
  • 이처럼 Data를 분석하는 동작의 경우 Data Table에서 모든 Column이 필요한 것이 아니라 일부 Column이 필요한 경우가 대부분이다.
  • 따라서 Column-oriented DB는 OLAP(Online Analytical Processing) 처리에 유리한 반면, OTLP(Online transaction processing) 처리에 불리하다.

2.Column-Family Databases

Column Family DB

Column-Family DB
  • Column-Family DB는 Column을 나타내는 Column Key/Data/Timestamp Tuple을 Row를 나타내는 Row Key에 Mapping하여 Data Table을 표현하는 DB이다.
  • RDBMS에서 NULL값도 Disk Block 공간을 차지하지만 Column Family DB에서는 Row별로 자유로운 Column 추가/삭제가 가능하기 때문에 NULL값을 위한 Column이 별도로 필요없다.
  • 일반적으로 Column-oriented DB와 Column Family DB가 혼용되어 사용되어 Column Family DB가 Column-oriented DB라고 간주하는 경우가 많은데 같은 DB라고 할 수는 없다.
  • Column Family DB인 HBASE는 Column의 집합인 Column Family 단위로 Disk Block에 저장되기 때문에 Column-oriented DB로 분류된다.
  • 하지만 또 하나의 Column Family DB인 CassandraRow 단위로 Disk Block에 저장되기 때문에 Column-oriented DB라고 할 수 없다.
Cassandra DB의 CRUD 예제
-- create a tuple
CREATE TABLE subjects (
  k int PRIMARY KEY,
  v tuple<int, text, float>
);

-- insert values
INSERT INTO subjects  (k, v) VALUES(0, (3, 'cs', 2.1));

-- retrieve values
SELECT * FROM subjects;

Graph Databases

Graph DB

Graph DB
  • Graph DB는 관계를 저장하고 탐색하도록 특별히 구축되다.
  • Graph DB는 노드를 사용하여 데이터 엔터티를 저장하고, 엣지로는 엔터티 간의 관계를 저장하게 되는데, 엣지는 항상 시작 노드, 끝 노드, 유형과 방향을 가지며, 상-하위 관계, 동작, 소유자 등을 문서화 한다.
  • 하나의 노드가 가질 수 있는 관계의 수와 종류에는 제한이 없다.
  • Graph DB 그래프는 특정 엣지의 유형 또는 전체 그래프를 전반을 통하여 트래버스될 수 있다.
  • Graph DB에서 노드 간의 관계는 쿼리 시간에는 포함되지 않지만 데이터베이스에서 유지되기 때문에 조인 또는 관계를 트래버스하는 속도가 매우 빠르다.
  • Graph DB는 데이터 간의 관계를 만들고 이러한 관계를 신속하게 쿼리해야 할 때 소셜 네트워킹, 추천 엔진, 이상 탐지 등의 사용 사례에 유용하다.
  • Graph DBNeo4j, RedisGraph(Redis에 내장된 그래프 모듈), OrientDB 등이 있다.

Neo4j DB의 예제

MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors)
RETURN tom, m, coActors

결론!

SQL과 NoSQL 비교

ParameterSQLNoSQL
관계관계형비관계형
쿼리 언어구조화된 쿼리 언어(SQL)문서, 키-값, 그래프, 컬럼기반
사용OLAP 시스템에 사용최신 애플리케이션 개발에 대한 요구에 부응하여 개발
개요미리 정의된 스키마구조화되지 않은 데이터에 동적 데이터베이스를 사용
확장성수직 확장수평 확장
유형테이블 기반의 DB문서 기반, 키-값 쌍 또는 그래프 DB
계층적 데이터 저장적합하지 않음적합
대표적인 DBSQL, MySQL, MS-SQL, PostgresMongoDB, Redis, Neo4j, Cassandra, Hbase

2022 DB Ranking

2022 DB Ranking

2022 DB Ranking
  • SQL의 언어의 사용량이 높긴 하지만 NoSQL의 사용량도 점차 꾸준히 늘고 있다. 즉, 기획하고 설계하는 프로젝트에 대해 선택하는 언어가 다른 거 같다. 어느 한쪽이 좋은 언어 라고 얘기하기는 어려운 거 같다. 각자의 장/단점이 있는 언어이기 때문에 해당 프로젝트에 가장 알맞은 언어를 선택하여 설계하여 개발하는 것이 가장 좋은 거 같다.

Reference

Pagination