CORS란 무엇인가?
CORS의 주체는 브라우저 어떤 URL을 접근할 때, 브라우저에 URL에 입력하거나 postman, curl 등에는 정상적으로 동작하는 요청이, 유독 브라우저가 렌더링한 프론트엔드에서 ajax로 호출이 안되는 현상이 있다. 이때 콘솔에서는 CORS란 에러메시지가 노출된다. 이 문제의 원인이자 차단의 주체는 바로 브라우저이다.
CORS의 주체는 브라우저 어떤 URL을 접근할 때, 브라우저에 URL에 입력하거나 postman, curl 등에는 정상적으로 동작하는 요청이, 유독 브라우저가 렌더링한 프론트엔드에서 ajax로 호출이 안되는 현상이 있다. 이때 콘솔에서는 CORS란 에러메시지가 노출된다. 이 문제의 원인이자 차단의 주체는 바로 브라우저이다.
브라우저에서 URL을 검색하면 브라우저는 google.com에 대한 요청 전문을 만들고 OS에 요청한다. OS는 DNS Lookup을 통해 아래와 같은 과정으로 도메인에 대한 IP를 찾는다. OS에서 hosts파일을 확인한다. OS가 캐싱한 DNS cache을 확인한다. DNS 서버(1.1.1.1, 8.8.8.8, ISP 제공)에게 해당 도메인에 대한 IP를 질의한다. DNS 서버는 루트 네임서버로부터 해당 도메인의 TLD(top-level domain: .com .net 등을 관리하는 최상위 네임서버) 서버의 IP를 질의한다. 응답받은 TLD의 IP를 사용하여 해당 도메인의 IP를 질의한다. 캐싱된 IP가 있더라도, 유효기간이 만료(TTL)된 경우 캐시를 버리고 다시 질의함. OS는 확보한 IP를 기반으로 해당 서버를 찾는다. 필요에 따라, https를 위한 ssl 핸드쉐이크를 수행한다. 패킷의 암호화를 목적으로 하며 공인인증서를 기반으로 비밀키를 공유한다. 응답을 받으면 브라우저는...
옵티마이저의 최적화 MySQL의 버전이 올라갈 수록 옵티마이저의 성능은 개선되고 전반적인 성능이 개선된다. 하지만 옵티마이저가 기대하는 방향으로 동작하지 않을 수 있으며 상황에 따라 특정 동작을 유도해야 할 수 있다. 이런 경우 옵티마이저의 스위치나 힌트를 활용하여 변경할 수 있다. 옵티마이저는 옵티마이저 옵션에 따라 동작하는데, 옵션은 옵티마이저 스위치(optimizer_switch)를 사용하여 변경한다. 이번 글은 옵티마이저 옵션의 각 기능을 살펴보며 MySQL의 최적화 기법을 알아보는데 목적이 있다.
옵티마이저란? 옵티마이저란 MySQL에서 쿼리를 최적으로 실행하기 위해 각 테이블의 데이터가 어떤 분포로 저장돼 있는지 통계 정보를 참조하며 최적의 실행 계획을 수립하기 위한 기능. 현재 글은 특히 SELECT에서 옵티마이저가 어떤 방식으로 최적화를 하는지 알아보겠다.
디스크 읽기 성능에 따른 인덱스의 중요성 SSD는 HDD보다 성능 상 좋지만 여전히 디스크 I/O가 컴퓨터에서 가장 느린 부분이다. 디스크 I/O의 처리가 성능 튜닝에 있어서 여전히 중요하며 이는 인덱스 설정과 큰 관련을 가짐.
다음 자료를 기반으로 정리하고 작성하였습니다. 저의 글보다 링크의 글을 더 추천합니다. 간단하게 CAP와 PACELC를 정리하는 형태로 현재 글은 작성되었습니다. http://eincs.com/2013/07/misleading-and-truth-of-cap-theorem/
트랜잭션과 락 트랜잭션(Transaction)은 작업의 완전성, 데이터의 정합성을 보장하는 기능. 논리적인 작업 셋에 대하여 모두 완벽하게 처리하거나 처리하지 못할 경우에는 원 상태로 복구하여 작업의 일부만 적용하는 현상(Partial update)이 발생하지 않게 만들어주는 기능.
InnoDB 스토리지 엔진 InnoDB는 MySQL에서 사용할 수 있는 스토리지 엔진 중 거의 유일하게 레코드 기반의 잠금을 제공한다. 레코드 기반 잠금을 기반으로 높은 동시성 처리가 가능하며 안정적이고 성능이 뛰어남.
MySQL의 전체 구조 MySQL 서버는 크게 MySQL 엔진과 스토리지 엔진으로 구분한다. MySQL 엔진: 클라이언트의 접속, 쿼리요청을 처리하는 커넥션 핸들러와 SQL 파서 및 전처러기, 쿼리 최적화 실행을 위한 옵티마이저 스토리지 엔진: 실제 데이터를 디스크 스토리지에 저장하거나 읽음
사용자 식별 계정명과 접속지점(호스트명, 도메인, IP)으로 사용자를 식별함. 아이디와 아이피는 따옴표로 감싼다. 모든 외부 컴퓨터에서 접속 가능한 계정을 생성할 경우 호스트를 %로 입력한다.
스토어드 프로그램(stored program) 스토어드 프로그램(스토어드 루틴)은 절차적인 처리를 위한 MySQL의 기능. 스토어드 프로그램은 다음을 포함함. 스토어드 프로시저 스토어드 함수 트리거 이벤트 장점 데이터베이스의 보안 향상 스토어드 프로그램 단위로 실행 권한을 부여 SQL 인젝션 같은 보안 사고 방어 기능의 추상화: 스토어드 프로그램을 사용하여 개발 언어나 도구와 관련 없는 특정 기능을 구현할 수 있음 절차적 기능 구현과 네트워크 소요시간 절감 SQL의 실행 결과는 빠르더라도 네트워크 경유 시간은 많은 자원을 사용. 프로그램에서 여러 번의 쿼리를 통해 데이터를 호출하는 것보다, 스토어드 프로그램으로 로직을 구현하여 한 번의 네트워크를 사용하는 것이 나음. 절차적 기능 구현을 위한 IF, WHILE 등 기능을 제공 개발 업무의 구분: SQL 개발조직이...
DDL 명령 시 알고리즘과 락 DDL 명령 각각마다 사용 가능한 알고리즘과 리빌드 여부, DML 허용 여부가 다르다. 그러므로 사용하는 서버의 버전에 맞춰 매뉴얼을 확인해야 한다. 해당 매뉴얼은 아래 링크를 참고하자. https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html
들어가며 대체로 insert와 update 작업은 레코드 단위로 발생하므로 성능 상 문제가 크게 발생하지 않는다. select의 경우 여러 테이블을 조합하기 때문에 성능 상 문제가 발생할 경우가 많다. select 쿼리를 최적화하기 위한 방법을 정리한다. select 쿼리의 각 파트(select-from-where-…) 별로 구분하여 정리한다.
파티션이란? 논리적으로는 하나의 테이블이지만 물리적으로는 여러 개의 테이블로 분리해서 관리하기 위함.
리터럴과 관련한 MySQL의 특징과 주의사항 MySQL의 사용에 있어서 다양한 명령이나 쿼리를 작성할 때, 백틱 등 특수 기호나 문자나 숫자 등 값으로 대입하고 and나 or 등 연산자를 사용한다. 이를 잘못 작성하면 오류가 발생하거나 혹은 쿼리 성능에 큰 영향을 미칠 수 있다. 그러므로 DDL, DML 등의 문법만큼 쿼리 문장 작성 규칙을 이해하고 정확하게 사용할 필요가 있다. 더불어 ANSI 표준에 없는 MySQL만의 표현법이 존재한다. 가능하면 ANSI에 맞춰 리터럴과 연산자를 사용한다.
MySQL의 내장 함수 DDL, DML이 ANSI 표준에 따라 일정 부분 호환 가능하다. 다만, DBMS 간 내장 함수는 사실상 호환되지 않는다. MySQL은 자체적으로 제공하는 내장 함수 이외에 사용자 정의 함수(User Defined Function)를 제공한다. 사용자가 직접 함수를 구현할 수 있다.
roll up 테이블 통계를 사용할 때 보통 group by를 자주 사용한다. group by와 더불어 좀 더 풍부한 내용을 제공하는 roll up에 대해 알아보자.
lateral 요구사항이 복잡한 통계를 요구하는 경우, with를 사용하거나 혹은 2-3 중의 서브쿼리와 함께 복잡한 조건절을 필요로 한다. 이런 경우 상황에 따라 lateral이 문제 해결에 도움이 될 수 있다. 아래는 school 테이블과 students 테이블이 있다. 요구 사항으로는 학교 별로 1,2,3등을 출력하고 그 순서로 나열하는 것이다. lateral을 몰랐던 나는 아래와 같이 rank 함수와 join을 사용하여 쿼리를 작성할 것 같다.
exsist where의 서브쿼리로만 사용 가능하다. 해당 서브쿼리의 결과로서 레코드가 하나라도 있을 경우 true를 반환한다. 그러므로 서브쿼리의 select 절은 의미가 없는 값(1)을 결과로 리턴한다. 레코드의 존재유무만 따지므로 대체로 IN과 JOIN보다 성능이 좋다.
요구사항 대규모, 분산 시스템에서 유일 ID를 생성한 시스템을 설계해야 한다. 요구사항은 아래와 같다. 유일한 값을 생성한다. 정렬할 수 있다. ID가 1씩 증가하는 것은 아니지만, 시간이 지날수록 숫자의 크기는 커야 한다. 초당 10,000개(1밀당 10개)의 ID를 생성할 수 있다. 64비트 이하의 용량을 차지한다.
자바 8 이전의 Future의 사용 Future는 미래의 결과를 얻기 위한 인터페이스다. Executor에 수행할 작업(Callable, Runnable)을 인자로 주입하면 Future 객체를 리턴 받는다. Future#get()으로 미래의 결과를 받을 때까지의 메인 스레드의 코드블럭은 논블로킹으로 동작한다.
stream의 collect과 다양한 최종 연산 타입 - toList, toSet, joining, summarizing 등 자바의 stream api을 최종 연산할 때 대표적으로 collect 메서드를 사용한다. List로 반환하는 Collector.toList()와 Set을 반환하는 Collectors.toSet()이 대표적이다.
람다와 함수형 인터페이스 함수형 프로그래밍의 큰 특징 중 하나는 함수가 값으로서 동작하는 점이다. 아래는 자바 8 이후로 추가된 함수형 프로그래밍으로 코드를 작성하였다.
Mockito와 BDDMockito BDDMockito는 Mockito를 BDD친화적으로 만든 API이다. BDD는 given - when - then으로 이뤄지며, Mockito의 when은 BBDMockito의 given으로, verify는 then으로 이름이 변경된다. 현재 코드는 BDDMockito를 기반으로 작성되었다. ArgumentsMatcher와 ArgumentsCaptor를 BDDMockito에 사용할 수 있다.
ngram을 사용할 일이 있었으며, 마침 mysql이 지원하였다 ngram? ngram은 인덱스 중 하나로 자동완성에 자주 사용하는 기능이다. 단어를 정해진 갯수로 자른 모든 조합을 인덱스로 배치한 후 그 단어를 맵핍하는 방법이다. 쿼리 : eating 사이즈 : 3 결과 : eat, ati, tin, ing ngram에 대하여 쿼리를 할 경우 DB는 다음과 같으 방식으로 응답한다. 쿼리 : eat 결과 : ‘eat’, ‘eat’ting, w’eat’her, sw’eat’ ngram은 보통 자동완성에 사용한다. 쿼리 : 노트북 응답 : 삼성’노트북’, ‘노트북’케이스 등
부모 테이블을 페이징처리하되, 조건에는 자식테이블이 있다. 아래는 부서(department)와 내선번호(phone)테이블이 있다. 내선번호는 부서에 의존한다. 페이징의 대상이 내선번호일 경우 큰 문제가 없다. 하지만 부서를 기준으로 페이징처리하되, 내선번호의 필터링이 필요한 경우 어떻게 하는가? ddl과 dml은 아래와 같다.
프록시 패턴 특정 객체에 대한 접근을 제어하거나 기능을 추가할 수 있는 패턴 초기화 지연, 접근 제어, 로깅, 캐싱 등 다양하게 응용해 사용 할 수 있다. 기존 코드의 변경 없이 새로운 기능을 추가할 수 있다. 데코레이터 패턴과 거의 유사하다. 가장 큰 차이는 객체 제어에 있다. 데코레이터는 행동을 추가한다. 프록시는 객체 자체를 제어한다.
데코레이터 패턴 기존 코드를 변경하지 않고 부가 기능을 추가하는 패턴 프록시 패턴과 거의 유사한 디자인 패턴이다. 기존 코드와 같은 데이터 타입을 가진다. 새로운 클래스를 만들지 않고 기존 기능을 조합할 수 있다. 런타임 때 원하는 데코레이터를 결정할 수 있다.
반복자 패턴 컬렉션의 구현 방법을 노출하지 않으며 집합 내 모든 항목에 접근하는 패턴 리스트 및 반복문을 단순화하여 순회하는 방식. list는 add, set, size, clear 등 다양한 메서드를 제공 iterator는 hasNext와 next등 단순한 메서드만 제공 클라이언트는 집합 자료구조(컬렉션, 배열, 컴포짓 등)를 이터레이터로만 받는다. 곧 집합 자료구조를 이터레이터로 구현해야 한다. 클라이언트는 집합에 대한 정렬, 필터링이 어렵다. 그저 next(), hasNext() 정도의 메서드만 사용 가능하다. 그러므로 정렬 및 필터링이 필요한 경우 이터레이터 구현 과정에서 적합한 로직을 작성해야 한다.
컴포지트 패턴 객체를 트리구조로 구성하여 부분-전체 계층구조를 구현. 모든 노드는 요소(Component)로서의 동일한 특성을 공유한다. 개별 객체로서의 리프와 복합 객체로서의 중간 노드(Composite)는 동일한 메서드를 구현하고 동일한 동작을 해야 한다. 다만 복합 객체는 개별 객체 전체의 행동을 담보하고 통합적인 동작을 수행한다. 결과적으로 클라이언트는 컴포지트 패턴을 활용하면 그것이 개별 객체인지 복합 객체인지 관계 없이 동일한 동작의 수행을 보장받는다.