대표적인 웹서버는 Apache, Ngnix가 있습니다.웹서버란 HTTP 프로토콜을 기반으로 클러이언트가 웹 브라우저에 요청을하면 그 요청을 받아서 정적 컨텐츠를 제공하는 서버입니다. 정적 컨텐츠는 단순 HTML 문서, CSS, 이미지, 파일 등 즉시 응답 가능한 컨텐츠를 말합니다. 웹서버가 정적 컨텐츠가 아닌 동적 컨텐츠를 요청 받으면 WAS가 요청을 처리하게 되고 그 결과를 웹서버가 클라이언트가 전달하는 역할도 하게 됩니다.
WAS(Web Application Server)는 서블릿 컨테이너, 웹 컨테이너라고 불리기도 하는데 웹 서버의 기능들을 구조적으로 분리하여 처리하는 목적으로 만들어졌습니다. 분산 트랜젝션, 보안, 쓰레드 처리 등을 처리하는 분산 환경에서 사용이 됩니다. WAS는 프로그램 환경과 DB 접속 기능을 제공하고 여러개의 트랜잭션을 관리할 수 있습니다. WAS의 종류로는 Tomcat, JBOSS, WebSphere 등이 있습니다.
Stack과 Queue 그리고 Array와 Linked List 자료구조에 대해 말씀해주시고 차이점에 대해 설명해주세요.
배열(Array)와 Linked List에 설명을 드리자면 먼저 배열은 구조가 간단하고 데이터를 읽는데 걸리는 access time이 짧은 편입니다. 단점으로는 크기를 변경할 수 없고, 크기 변경을 피하기 위해 충분히 큰 배열을 생겅하면 메모리가 낭비가 됩니다. 또 비순차적인 데이터의 추가, 삭제에 시간이 많이 걸린다는 단점이 있습니다. LinkedList는 이런 배열의 단점을 보완한 것이 특징입니다. 비연속적으로 존재하는 데이터를 연결하고 단 한번의 참조 변경으로 데이터 삭제가 가능합니다. 또 한번의 Node 객체 생성과 두번의 참조 변경만으로 데이터 추가가 가능합니다. 링크트리스트는 데이터 접근성이 나쁘다는 단점이 있는데 이중 연결 리스트는 이러한 문제를 보완하여 접근성을 향상시켰습니다. 배열은 빠른 접근이 요구되고, 데이터의 삽입과 삭제가 적을 때 사용하고 링크드리스트는 삽입과 삭제 연산이 잦고, 검색 빈도가 적을 때 사용합니다.
@SpringBootTest는 프로젝트 내부에 있는 스프링 빈을 모두 등록해서 사용해서 테스트가 느리다는 특징이 있습니다. 실제 운영 환경에서 사용되는 클래스들을 통합해서 테스트하기 때문에 실제 환경과 가장 유사하게 테스트가 가능합니다. Service 의 메서드가 변경이 되어도 Mocking 값을 수정하지 않아도 되서 변경이 자유롭습니다. 그러나 테스트 단위가 크기 때문에 디버깅이 어렵다는 단점이 있습니다.
@WebMvcTest는 컨트롤러의 역할만을 테스트합니다. Web Layer에 해당하는 빈만 생성해서 테스트하기 때문에 @SpringBootTest보다 빠르다는 장점이 있습니다. 그러나 Mock 객체를 사용해서 실제 동작과는 차이가 날 수 있습니다. 또한 메서드 변경이 일어날 때 Mocking값을 수정해줘야 한다는 번거로움이 있습니다.
트랜잭션이 무엇인지 설명해 주세요.
트랜잭션이란 데이터베이스의 상태를 변화시키기 위해서 수행하는 작업의 단위를 뜻합니다. 원자성(Atomicity)은 트랜잭션의 가장 큰 특성으로 트랜잭션 안의 작업들이 분리되어 작업불가하고 모두 반영되던가 전혀 반영되지 않아야 합니다.일관성은트랜잭션이 진행되는 동안 데이터베이스가 변경되었더라도 기준은 트랜잭션을 진행하기 위해 참조한 데이터베이스 정보로 진행되어야 합니다.고립성은 둘 이상의 트랜잭션이 동시에 실행되고 있을때 서로 트랜잭션 연산에 관여되지 않아야합니다.지속성은 트랜잭션이 성공적으로 완료 되었다면 그 결과는 영구적으로 반영되어야 합니다.
TCP와 UDP의 공통점과 차이점을 설명해보세요.
TCP(Transmission Control Protocol)는 신뢰성 있는 데이터 전송을 지원하는 연결 지향형 프로토콜로 일반적으로 TCP와 IP가 함께 사용되는데, IP가 데이터의 전송을 처리한다면 TCP는 패킷 추적 및 관리를 하게 됩니다. 연결 지향형인 TCP는 3-way handshaking이라는 과정을 통해 연결 후 통신을 시작하는데, 흐름 제어와 혼잡 제어를 지원하며 데이터의 순서를 보장합니다. UDP(User Datagram Protocol)는 비연결형 프로토콜로써, 인터넷상에서 보내는 쪽에서 일방적으로 데이터를 전달하는 통신 프로토콜로 TCP와는 다르게 연결 설정이 없으며, 혼잡 제어를 하지 않기 때문에 TCP보다 전송 속도가 빨라 실시간 동영상 스트리밍 서비스 같은 서비스에 적합합니다. 그러나 데이터 전송에 대한 보장을 하지 않기 때문에 패킷 손실이 발생할 수 있습니다.
parameter는 매개변수명을 말하고 argument는 함수와 메서드의 입력 값(value)를 뜻합니다. 함수를 정의할 때 사용되는 변수를 매개변수, 실제로 함수가 호출될 때 넘기는 변수값을 argument(인수)라고 설명할 수 있습니다.
프로세스와 스레드의 차이에 대해 설명해 주세요
프로세스는 운영체제로부터 자원을 할당받는 작업의 단위이고, 스레드는 프로세스가 할당받은 자원을 이용하는 실행의 단위입니다. 프로세스는 실행될 때 운영체제로부터 프로세서, 필요한 주소공간, 메모리 등 자원을 할당받습니다. 스레드란 한 프로세스 내에서 동작되는 여러 실행의 흐름으로 프로세스 내의 주소공간이나 자원들을 같은 프로세스내에 스레드끼리 공유하면서 실행됩니다.
하나의 큰 어플리케이션을 여러개의 작은 어플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍쳐를 말합니다. 예전에는 Monolithic Architecture라는 소프트웨어의 모든 구성요소가 한 프로젝트에 통합되어 있는 형태로 개발을 하였습니다. 소규모프로젝트에는 합리적일지 모르나 일정 규모 이상의 서비스에서 Monolithic Architecture 는 비효율적입니다. Microservice Architecture에서는 하나의 어플리케이션을 작은 서비스 단위로 나누어서 작업을 하기 때문에 각각의 서비스의 독립적 배포가 가능하고 다른 서비스에 대한 의존성이 낮아집니다. 또한 확장성이 높으며 에러가 발생해도 그 에러가 발생한 단위의 서비스를 격리가 가능하기 때문에 유연한 대처가 가능합니다.
MSA의 단점으로는 상대적으로 복잡하다는 점이 있고 서비스가 커질 수록 그 복잡도가 늘어날 수 있다는 점이 단점입니다. 서비스가 분리되어 있기 때문에 트랜잭션의 복잡도가 증가하고 많은 자원을 필요로 하게 됩니다. 또 데이터가 여러 서비스에 걸쳐 분산되기 때문에 한번에 조회하기가 어려울 수 있고, 데이터의 정합성도 관리하기 어렵습니다. 성능면에서는 서비스간 호출시 API를 사용하기 때문에 통신 비용이나, latency가 그만큼 늘어난다는 단점이 있습니다.
제네릭에 대해서 설명하고, 컬렉션 클래스에서 왜 제네릭을 사용하는 지 설명해주세요.
데이터 타입을 일반화한다는 의미를 가지고 있으며 클래스나 메서드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법입니다. 클래스에서 사용할 타입을 클래스 외부에서 설정하는 것 입니다. 제네릭의 장점은 객체 타입의 안정성을 높일 수 있고 반환 값에 대한 타입 변환을 쉽게 할 수 있다는 점입니다. 타입 체크와 형변환을 생략할 수 있어서 코드가 간결해진다는 장점도 있습니다. 컬렉션은 이러한 장점 때문에 제네릭 기법으로 구현이 되어 있습니다. 컬렉션을 특정 타입만 다루지 않고 여러 종류의 타입으로 변환할 수 있도록 컬렉션을 일반화 시키기 위해 제네릭을 사용합니다.
List, Set, Map, HashMap의 차이에 대해서 설명해주세요.
List는 데이터들이 순서대로 저장되고 중복을 허용합니다.
Set은 데이터의 집합으로 순서가 없고 중복되는 데이터를 허용하지 않아서 중복되지 않는 데이터를 사용할 때 유용합니다.
Map은 key와 value라는 페어로 이루어지는 데이터의 집합입니다. key는 중복되지 않고 순서를 보장하지 않습니다. 인덱스가 따로 존재하지 않기 때문에 iterator를 사용해야합니다. HashMap은 마찬가지로 key에 대한 중복이 없으며 순서를 보장하지 않습니다. 동기화가 보장이 되지 않고, key와 value값으로 null을 허용한다는 특징이 있습니다.
정리하자면, list는 데이터들이 순서대로 저장되며 중복을 허용하고, set은 순서가 보장되지 않고 중복을 허용하지 않고, Map은 순서가 보장되지 않고 key값의 중복은 허용하지만 value값은 중복될 수 없다는 특징이 있습니다.
DI(Dependency Injection)에 대한 설명과 해당 기술의 장점에 대해 설명해주세요.
DI(Dependency Injection)란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입으로, 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식입니다. DI(의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다는 장점이 있습니다.
의존성을 주입하는 방법에는생성자 주입, Setter 주입, 필드 주입 등이 있는데 Spring에서는 생성자 주입을 권장하고 있습니다. 생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장되기 때문에 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우 강제로 주입하기 위해 사용할 수 있다는 장점이 있습니다. 스프링은 애플리케이션 실행 시점에서 필요한 객체(bean)을 DI 컨테이너에서 생성합니다. 그리고 의존성이 있는 두 객체를 연결하기 위해 한 객체를 다른 객체로 주입시킵니다. 이러한 개념은 제어의 역전(Inversion of Control, IOC)라고 불립니다. 왜냐하면, 어떠한 객체를 사용할지에 대한 책임을 개발자가 아닌 프레임워크가 가지는 동시에 개발자는 수동적으로 주입받는 객체를 사용하기 때문입니다.
DB에서 인덱스를 잘 사용하면 어떤 장점이 있을까요?
인덱스는 데이터베이스에서 테이블의 검색 성능을 높여주는 방법으로 select where 쿼리 처럼 특정 데이터를 찾을 때 빠른 속도로 검색할 수 있습니다. 인덱스를 생성하면 특정 칼럼(속성)값을 기준으로 정렬하여 데이터의 물리적 위치주소와 함께 별도 파일에 저장합니다. 테이블의 데이트는 순서없이 쌓이게 되므로 특정 조건의 데이터를 찾으려면 테이블의 모든 데이터에 접근하여 비교하는 과정이 필요하지만 인덱스를 사용하면 search-key가 정렬되어 있기 때문에 조건 검색 시 속도가 빠릅니다.
대량의 데이터를 가지고 있고 특정 조건의 데이터를 찾을 때는 인덱스를 활용하여 빠르게 데이터를 가져올 수 있습니다.
인덱스의 단점은 추가 저장공간이 필요하다는 점입니다. 데이터가 변경이 있는 경우 인덱스도 수정되어 성능 저하가 일어날 수 있습니다.
인덱스는 where 절에서 '자주 조회'하고 '수정 빈도가' 낮고 '데이터 중복'이 적은 칼럼을 선택하는 것이 좋습니다. 데이터의 양이 많을수록 인덱스 성능 효율이 커진다고 할 수 있습니다.
한 테이블에 인덱스가 너무 많은면 데이터 수정시 소요시간이 커지고, 데이터 중복이 높은 값은 인덱스를 생성하는 것이 크게 의미가 없습니다. 인덱스의 장점보다 저장 공간을 차지하고 데이터 수정에 대한 성능 저하가 더 크기 때문입니다.
차라리 밤새서 코딩하고 싶습니다!! 면접 준비 귀찮지만 어쩔수 없죠!!! 예상 질문 답변 정리입니다!!!
1. 배열 vs. 링크드리스트
-> 배열은 구조가 간단하고 데이터를 읽는데 걸리는 access time이 짧은 편입니다. 단점으로는 크기를 변경할 수 없고, 크기 변경을 피하기 위해 충분히 큰 배열을 생겅하면 메모리가 낭비가 됩니다. 또 비순차적인 데이터의 추가, 삭제에 시간이 많이 걸린다는 단점이 있습니다. LinkedList는 이런 배열의 단점을 보완한 것이 특징입니다. 비연속적으로 존재하는 데이터를 연결하고 단 한번의 참조 변경으로 데이터 삭제가 가능합니다. 또 한번의 Node 객체 생성과 두번의 참조 변경만으로 데이터 추가가 가능합니다. 링크트리스트는 데이터 접근성이 나쁘다는 단점이 있는데 이중 연결 리스트는 이러한 문제를 보완하여 접근성을 향상시켰습니다. 배열은 빠른 접근이 요구되고, 데이터의 삽입과 삭제가 적을 때 사용하고 링크드리스트는 삽입과 삭제 연산이 잦고, 검색 빈도가 적을 때 사용합니다.
2. CORS 란?
CORS는 Cross Origin Resource Sharing의 약자로 브라우저에서 다른 출처의 리소스를 공유하는 방법입니다. 브라우저에서 허용되지 않은 출처의 리소스를 사용하려고 한다면 SOP(Same-Origin Policy)에 의해 차단되고, 이를 허용하기 위해선 CORS 설정을 통해 Access-Control-Allow-Origin 응답 헤더에 추가해주면 설정을 통해 허용된 자원에 접근할 수 있게 됩니다.
3. 시간복잡도와 공간복잡도
어떠한 알고리즘의 성능 평가가 필요할 때 복잡도의 척도를 사용하는데 그 복잡도가 낮을수록 좋은 알고리즘입니다. 시간 복잡도(time complexity)는 특정 알고리즘이 어떤 문제를 해결하는데 걸리는 시간을 의미하고 공간 복잡도(space complexity)는 특정 알고리즘이 어떤 문제를 해결하는데 차지하는 공간(메모리)을 의미합니다.
4. 사용자 패스워드를 전송하고 보관하는 방법
유저의 패스워드를 받은 클라이언트는 평문으로 서버로 전송합니다. 평문을 받은 서버는 패스워드를 단방향 해시 함수로 암호화하여 보관합니다. 단방향 해시함수는 수학적 연산에 의해 원본 데이터를 완전히 다른 암호화된 데이터(다이제스트)로 변환하는 것을 말합니다. 원본 데이터로는 다이제스트를 구할 수 있지만 다이제스트로는 원본데이터를 구할 수 없어야 합니다. 이것을 단방향이라 합니다. 단방향 해시함수는 브루트포스 공격으로 쉽게 당할 수 있기 때문에 이를 보완하기 위해 입력된 다이제스트를 N번 반복해서 생성하는 것인 key stretching과 원문 패스워드에 임의의 문자열을 추가하여 해싱하는 것인 salting을 이용해 보안의 강도를 높힐 수 있습니다.
5. 스택과 큐
스택은 말그대로 데이터를 차곡차곡 쌓아 올린 자료구조를 말합니다. 데이터가 순서대로 쌓이고 가장 마지막에 쌓인 자료가 가장 먼저 삭제되는 구조로 LIFO(Last In First Out)입니다. 스택에서 삽입 연산은 push(), 삭제 연산은 pop()입니다. 큐는 스택과 다르게 먼저 들어온 것이 먼저 나가는 선입선출 구조를 가지고 있습니다. 이를 FIFO(First In First Out)라고 합니다. 큐에서 삽입 연산은 push(), 삭제 연산은 shift()입니다.
6. DI와 IoC
DI(Dependency Injection)란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입으로, 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식입니다. DI(의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아집니다. IoC(Inversion of Control)란 "제어의 역전" 이라는 의미로, 말 그대로 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다. IoC는 제어의 역전이라고 말하며, 간단히 말해 "제어의 흐름을 바꾼다"라고 한다. 객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.
의존성을 주입하는 방법에는 생성자 주입, Setter 주입, 필드 주입 등이 있는데 Spring에서는 생성자 주입을 권장하고 있습니다. 생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장되기 때문에 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우 강제로 주입하기 위해 사용할 수 있다는 장점이 있습니다.
스프링에서의 IOC는 사용자가 객체를 직접 생성하지 않고 객체의 생성 및 소멸과 같은 제어권을 스프링에게 위임하는 것을 말합니다. 스프링이 모든 의존성 객체를 만들고 필요한 곳에 주입시켜줌으로서 Bean들은 싱글톤 패턴의 특징을 갖습니다.
7. Call by reference란?
함수의 호출 방식 중 하나로, 참조에 의한 호출 방식입니다. 함수를 호출할 때 인자로 reference(값에 대한 참조 주소, 메모리상의 주소를 담고 있는 변수)를 전달하며 참조 타입(reference type)을 전달합니다. reference를 전달했기 때문에 인자는 일반적으로 전역 변수의 특성을 갖습니다. 그러나 참조 타입의 변수를 함수 내에서 재할당 하게 되면 원본 값이 변경된다는 위험이 있습니다. 이러한 점을 방지 하기 위해서는 reference로 다른 값을 전달하여 사용합니다. 값이 같은 다른 참조값을 만들어 사용하는 것입니다.
8. Overriding vs. Overloading
오버라이딩은 상속받은 조상의 메서드를 자신에 맞게 변경하는 것을 말하고 오버라이딩은 같은클래스에서 메소드의 이름은 같고 매개변수의 개수나 타입이 다른, 기존에 없는 새로운 메서드를 정의하는 것을 의미합니다. 서로 이름은 비슷하지만 관계는 없습니다.
9. MVC 모델
MVC (모델-뷰-컨트롤러) 는 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴입니다. 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있습니다. 이러한 "관심사 분리" 는 더나은 업무의 분리와 향상된 관리를 제공합니다. MVC의 Model은 데이터와 비즈니스 로직을 관리하고 View는 레이아웃과 화면을 처리합니다. Controller는 명령을 모델과 뷰 부분으로 라우팅합니다.
10. JPA 필요한 경우 vs 필요하지 않은 경우
JPA는 객체지향과 RDB의 완전히 다른 두 패러다임 사이의 불일치에 의해 탄생한 ORM 입니다. ORM은 객체와 RDB 두 기둥위에 있는 기술로, 두 패러다임 사이의 균형을 맞추고 sql을 직접 작성하는 번거로움을 덜어주는 역할을 합니다. 그러나 모든 쿼리를 JPA로 해결하지 못하는 순간이 발생하기도 한다. 이럴 때, 특히 쿼리문이 복잡해지는 경우에는 직접 쿼리문을 작성해야하는 경우가 발생합니다. 결국엔 개발자는 JPA만을 사용할 수는 없으며 때에 따라 sql도 직접 작성해야합니다.
11. JPA의 더티 체킹이란?
JPA는 트랜잭션이 끝나는 시점에 변화가 있는 모든 엔티티 객체를 데이터 베이스에 자동으로 반영해줍니다. 이때 '변화가 있는'의 기준은 최초 조회 상태이고 JPA는 최초 조회 시 데이터를 1차 캐시에 스냅샷 형태로 저장해둡니다. 그 이후 트랜잭션이 끝날 때 해당 스냅샷과 엔티티를 비교하게 되며 다른 점이 존재한다면 update 쿼리문이 날라가게 됩니다. 이러한 과정은 영속성 컨텍스트가 관리하는 엔티티에만 적용이 되며, 준영속, 비영속 상태의 엔티티는 적용되지 않습니다.
더티 체킹은 해당 엔티티의 모든 필드에 대해 업데이트를 진행하는데, 한 테이블 당 컬럼의 수가 많을 경우, 비용적인 측면이 부담스러울 수 있습니다. 이를 보완하기 위해서 실제 값이 변경된 컬럼으로만 update 쿼리를 만드는 기능인 @DynamicUpdate 어노테이션을 해당 엔티티 클래스에 선언해주면 됩니다.
12. Annotation이란?
Annotation은 코드 사이에 주석처럼 쓰이며 특별한 의미, 기능을 수행하도록 하는 기술입니다. 소스코드에 추가해서 사용할 수 있는 메타 데이터의 일종입니다. 어노테이션의 예시로 @Override는 @Override를 선언한 메서드가 오버라이드 되었다는 것을 나타냅니다. @Deprecated 해당 메소드에 대해 버전 업 등으로 인하여 더 이상 사용을 권장하지 않는 경우에 사용됩니다. 스프링 프레임워크에서는 @Component 빈으로 등록하거나, @ComponentScan를 통해 @Component, @Service, @Repository, @Controller, @Configuration 중 1개라도 등록된 클래스를 찾으면, context에 빈으로 등록해준다.또 다른 예로 Lombok 라이브러리에서 제공하는 Annotaion @Setter, @Getter 등은 코드를 줄여 가독성을 높여주는 역할을 합니다.
13. 인덱스란? 인덱스의 일반적인 원리는?
인덱스란 저장 공간을 활용해 데이터베이스의 테이블 검색 속도를 높여주는 자료구조입니다. 하나의 컬럼이나 여러개의 컬럼을 키로 갖고 키에 해당하는 주소값을 저장하는 색인입니다. 저장된 주소를 바탕으로 더욱 빠른 탐색을 할 수 있습니다. 가장 일반적으로 사용되는 B-Tree 원리로 설명하자면, 테이블을 B-Tree 구조로 색인화(indexation) 하여, 찾고자 하는 데이터가 첫번째 루트 노드에서 어느 위치에 포함될 지를 알게 되면 전체 목록을 검색하는 것이 아닌 위치가 포함된 일부분의 데이터에서만 검색을 하여 매우 빠른 속도로 검색할 수 있게 됩니다. 단점으로는 데이터의 추가, 변경, 삭제가 자주 일어난다면 인덱스를 다시 정렬해줘야 한다. 그래서 검색을 위주로 하는 테이블에 인덱스를 생성하는 것이 좋습니다.
14. 이분탐색(Binary Search)이 무엇이고 시간복잡도는 어떻게 되며 그 이유는 무엇인가?
이분 탐색(Binary Search)은 결정 문제(Decision Problem)의 답이 이분적일 때 사용할 수 있는 탐색 기법입니다. 정렬되어 있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 알고리즘이며 배열 내부의 데이터가 정렬되어 있어야만 사용할 수 있다는 특징이 있습니다. 찾으려는 데이터와 중간점의 데이터를 반복적으로 비교해 원하는 데이터를 찾습니다. 탐색 단계마다 범위를 반으로(÷2) 나누는 것과 동일하기 때문에 시간 복잡도는 O(log₂N) 입니다. (빅오 표기법에서 계수는 무시함으로 logN으로 표시할 수 있습니다.)
15. 트리 vs. 그래프
트리와 그래프는 둘 다 노드와 노드를 연결하는 자료구조 입니다. 트리는 두 노드 사이에 항상 단 1개의 경로 만을 가지며 루트 노드에서 뻗어나가는 방향성이 존재하고 거슬러 올라갈 수 없기 때문에 사이클이 존재하지 않습니다. 또한 부모 자식의 관계가 있어 계층형 모델이라고도 불립니다. 그래프는 방향이 있는 그래프도 방향이 없는 그래프도 존재 합니다. 트리와 달리 루트노드 개념과 부모자식 개념이 없고 하나의 노드에서 2개 이상의 경로가 가능합니다. 네트워크가 이 모델에 해당합니다.
16. 트랜잭션이란? 원자성, 일관성, 고립성, 지속성이란?
트랜잭션이란 데이터베이스의 상태를 변화시키기 위해서 수행하는 작업의 단위를 뜻합니다. 원자성(Atomicity)은 트랜잭션의 가장 큰 특성으로 트랜잭션 안의 작업들이 분리되어 작업불가하고 모두 반영되던가 전혀 반영되지 않아야 합니다. 일관성은 트랜잭션이 진행되는 동안 데이터베이스가 변경되었더라도 기준은 트랜잭션을 진행하기 위해 참조한 데이터베이스 정보로 진행되어야 합니다.고립성은 둘 이상의 트랜잭션이 동시에 실행되고 있을때 서로 트랜잭션 연산에 관여되지 않아야합니다. 지속성은 트랜잭션이 성공적으로 완료 되었다면 그 결과는 영구적으로 반영되어야 합니다.
17. 정규화란? 대표적인 장점과 단점은?
정규화(Normalization)란 데이터베이스의 중복을 최소화하며 데이터를 구조화하는 프로세스입니다. 정규화를 통해서 데이터의 무결성을 유지하고 저장 용량을 줄일수 있습니다. 하지만 정규화를 하게 되면 테이블이 많이 나눠지게 되고 그렇게된다면 join이 많아지기 때문에 성능 저하가 될 수 있다는 단점이 있습니다.
18. HTTP보다 HTTPS가 더 안전한 원리는?
HTTP는 서버에서부터 브라우저로 전송되는 정보가 암호화 되지 않기 때문에 제 3자에 데이터를 쉽게 도난당할 수 있습니다. HTTPS 프로토콜은 SSL(보안 소켓 계층 Secure Sockets Layer)을 통해 사용자가 사이트에 제공하는 정보를 암호화하는데, 중간에서 누군가 데이터를 훔쳐 낸다고 하더라도 암호화되어있기 때문에 평문으로 전달하는 http보다 더 안전합니다.
19. TCP 3 way handshake란?
TCP 3 way handshake란 연결하고자 하는 두 장치 간의 논리적 접속을 성립하기 위해 사용하는 연결 확인 방식으로, 3번의 확인 과정을 거친다고 해서 3 way handshake라고 부릅니다. 동작 과정은 1. SYN (synchronize sequence numbers) 연결 확인을 위해 보내는 무작위의 숫자값으로 클라이언트에서 서버로 보내고 2. ACK (acknowledgements) Client 혹은 Server로부터 받은 SYN에 1을 더해 SYN을 잘 받았다는 ACK와 SYN을 같이 보냅니다. 3. ACK (acknowledgements)를 보내 연결을 확인합니다.
20. 프로젝트에서 시간복잡도를 낮춘 사례가 있는가?
저희 프로젝트에서는 MySQL을 사용했는데 full-text index O(N)의 시간복잡도를 검색기능을 위해 역인덱스를 사용하는 ElasticSearch를 적용해 해시테이블 방식의 O(1)의 시간복잡도로 개선한 경험이 있습니다. 또 개인적인 프로젝트로는 3중 포문을 2중으로 줄여서 시간 복잡도를 낮춘 경험이 있습니다.
21. TCP vs. UDP
TCP(Transmission Control Protocol)는 신뢰성 있는 데이터 전송을 지원하는 연결 지향형 프로토콜로 일반적으로 TCP와 IP가 함께 사용되는데, IP가 데이터의 전송을 처리한다면 TCP는 패킷 추적 및 관리를 하게 됩니다. 연결 지향형인 TCP는 3-way handshaking이라는 과정을 통해 연결 후 통신을 시작하는데, 흐름 제어와 혼잡 제어를 지원하며 데이터의 순서를 보장합니다. UDP(User Datagram Protocol)는 비연결형 프로토콜로써, 인터넷상에서 보내는 쪽에서 일방적으로 데이터를 전달하는 통신 프로토콜로 TCP와는 다르게 연결 설정이 없으며, 혼잡 제어를 하지 않기 때문에 TCP보다 전송 속도가 빨라 실시간 동영상 스트리밍 서비스 같은 서비스에 적합합니다. 그러나 데이터 전송에 대한 보장을 하지 않기 때문에 패킷 손실이 발생할 수 있습니다.
22. MySQL을 사용한 이유는?
MySQL은 RDBMS, 관계형 데이터 베이스 모델입니다. 관계형데이터 베이스는 테이블을 통해 정형화된 데이터를 저장하고 테이블끼리 관계를 맺을 수 있습니다. 경우에 따라 테이블을 나누어 데이터를 관리할 수 있고 JOIN을 사용해서 나누어져있는 테이블의 데이터를 불러올 수 있습니다. NoSQL은 비관계형 데이터 베이스 모델인데 NoSQL은 수평적 확장을 쉽게 할 수 있어 많은 데이터를 저장하고 분산 처리를 쉽게 할 수 있습니다. 대신 ACID(Atomicity, Consistency, Isolation, Durablity) 성질을 준수하지 않습니다. 저희는 하나의 트랜잭션으로 데이터를 처리할 때 예외적인 상황을 줄이는 것 뿐만 아니라, ACID를 준수하는 관계형 데이터 베이스 모델을 선택했습니다. 그중에서도 저희가 제일 익숙한 MySQL을 선택했는데 촉박한 프로젝트기간을 고려하면 새로운 관계형데이터 베이스 모델을 습득하는 것이 경제적이지 ㅇ않다는 판단을 하였기 때문입니다. 다만, 디자인이 업데이트 되고 데이터 구조가 자주 수정이 되면서 데이터 구조를 자주 업데이트 하게 되었는데 스키마를 매번 수정해야하는 번거로움이 있었습니다.
23. Traffic이 몰렸을 때 어떻게 해결할 것인가?
서버의 성능을 높이는 스케일업이나 여러대로 늘리는 스케일 아웃이 있는데 기존에 이미 8gb를 16gb로 늘린 적이 있기 때문에 비용 측면상 스케일 아웃을 시도할 것 같습니다. 로드 밸런서(load balancer)를 통해서 정합성 문제를 해결할 수 있다고 알고 있는데 도커나 쿠버네티스 같은 컨테이너 툴에 대한 자세한 방법은 아직은 잘 모릅니다. 현재는 in-memory 방식인 Redis를 refresh 토큰 발행에 쓰고 있는데 MySQL에 저장할 필요없다고 판단해서 DB 부하를 줄이고자 적용했습니다.
스프링 부트에서는 내장 Tomcat에 Thread Pool을 만들고, Request가 들어오면 해당 Thread가 해당 요청을 담당해서 처리합니다. 쓰레드는 Connection Pool에서 유휴 상태인 DB Connection이 존재하면 사용하고, 생성해야 한다면 생성합니다. 그리고 DB Connection을 이용해서 DB에서 쿼리를 날린 뒤 사용자에게 결과를 반환하게 됩니다.
다중 스레드를 사용하면 스레드 풀에 보관하고 관리하게 되는데 스레드 최대수랑 대기하는 수를 설정할 수 있습니다. 비동기처리를 할 때 @AsyncConfigururSupport를 통해 스레드 숫자를 조절한 경험이 있습니다.
25. 다중상속이란?
인터페이스는 여러 인터페이스를 상속받는 다중 상속이 가능합니다. 자바에서는 클래스의 다중상속은 불가능합니다. 만약 2개 이상의 클래스로부터 다중상속을 받는 자식 클래스가 있는데 부모클래스에 같은 메서드가 존재한다면 어느것을 상속을 받아야할지 파악할 수 없기 때문입니다. 인터페이스가 다중상속이 가능한 이유는 메서드가 정의 되지 않았기 떄문입니다.
26. Base64 인코딩이란?
Base64란 Binary Data를 Text로 바꾸는 인코딩(binary-to-text encoding schemes)의 하나로써 Binary Data를 Character set의 영향을 받지 않는 공통 ASCII (아스키) 영역의 문자로만 이루어진 문자열로 바꾸는 인코딩입니다. HTML 또는 Email과 같이 문자를 위한 Media에 Binary Data를 포함해야 될 필요가 있을 때, 포함된 Binary Data가 시스템 독립적으로 동일하게 전송 또는 저장 되는 걸 보장하기 위해 사용합니다.
27. 프로세스 vs 스레드
프로세스는 운영체제로부터 자원을 할당받는 작업의 단위이고, 스레드는 프로세스가 할당받은 자원을 이용하는 실행의 단위이다. 프로세스는 실행될 때 운영체제로부터 프로세서, 필요한 주소공간, 메모리 등 자원을 할당받는다. 스레드란 한 프로세스 내에서 동작되는 여러 실행의 흐름으로 프로세스 내의 주소공간이나 자원들을 같은 프로세스내에 스레드끼리 공유하면서 실행된다.
28. 동기 vs 비동기
동기는 요청과 응답이 동시에 일어납니다. 하나의 데이터 요청에 대한 서버의 응답이 이루어질 때까지 대기하는데 그로 인해 응답이 올 때까지 다른 작업을 수행하지 못하고 대기해야 하는 단점이 발생합니다. A작업이 모두 진행 될 때까지 B작업은 대기를 해야 합니다. 하지만 설계가 매우 간단하고 직관적이라는 장점도 존재합니다.
비동기는 요청과 결과가 동시에 일어나지 않을 거라는 약속입니다. 요청에 따른 응답을 기다리지 않고 다른 작업을 수행할 수 있고 응답이 왔을 때 처리하면 되므로 자원을 효율적으로 활용할 수 있다는 장점이 있습니다. 하지만 동기식 처리보다 설계가 복잡하다는 단점이 있습니다.
29. 동시성 vs 병렬성
동시성이란 여러 작업이 동시에 실행되고 있는 것처럼 구현되는 것입니다. 싱글 코어에서 단일 프로세스 내에 멀티 스레드를 동작시키는 방식으로 구현합니다. 동시성은 작업이 빠르게 번갈아가며 실행되어 실제로 코어는 한 번에 하나의 명령어만 처리할 수 있지만 동시에 실행되는 것처럼 보이는 것이고, 병렬성은 실제로 동시에 작업을 처리하는 것입니다. 병렬성은 멀티코어에서 멀티 스레드를 동작시키는 방식으로 구현합니다.
30. JVM이란 무엇이고 왜 필요한가?
JVM이란 Java Virtual Machine 의 줄임말로, Java Byte Code 를 운영체제에 맞게 해석해주는 역할을 합니다. 즉, 작성한 자바 프로그램의 실행 환경을 제공하는 자바 프로그램의 구동 엔진입니다. Java compiler 는 .java 파일을 .class 라는 자바 바이트코드로 변환시켜주는데 Byte Code 는 기계어(Native Code)가 아니므로 OS 에서 바로 실행이 되지 않습니다. 이때 JVM은 OS가 Byte Code 를 이해할 수 있도록 해석해주는 역할을 담당합니다. JVM은 메모리 관리도 담당합니다. 이를 '가비지 컬렉터'라고 하는데, 가비지 컬렉터는 Java7부터 힙 영역의 객체들을 관리하는 역할을 담당합니다.
31. Java가 컴파일 되는 과정 설명
개발자가 자바 소스코드(.java)를 작성하면 자바 컴파일러가 자바 소스코드(.java)파일을 읽어 바이트코드(.class)코드로 컴파일 합니다. 바이트코드(.class)파일은 아직 컴퓨터가 읽을 수 없는 JVM(자바 가상 머신)이 읽을 수 있는 코드입니다. (java - > class) 컴파일된 바이트코드(.class)를 JVM의 클래스로더(Class Loader)에게 전달합니다. 클래스 로더는 동적로딩(Dynamic Loading)을 통해 필요한 클래스들을 로딩 및 링크하여 런타임 데이터 영역(Runtime Data Area), 즉 JVM의 메모리에 올립니다. 마지막으로 실행엔진(Execution Engine)은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행합니다. 이 때 실행 엔진은 두 가지 방식(인터프리터와 JIT컴파일러)으로 변경합니다.
32. JVM의 스택과 힙메모리 영역 설명
Stack의 경우에는 정적으로 할당된 메모리 영역입니다. Stack에서는 원시Primitive 타입 (boolean, char, short, int, long, float, double) 의 데이터가 값이랑 같이할당이 되고, 또 Heap 영역에 생성된 Object 타입의 데이터의 참조 값이 할당 됩니다. 그리고 Stack 의 메모리는 Thread당 하나씩 할당 됩니다. 만약 새로운 스레드가 생성되면 해당 스레드에 대한 Stack이 새롭게 생성되고, 각 스레드 끼리는 Stack 영역을 접근할 수 없습니다.
Heap메모리는 동적으로 할당된 메모리 영역입니다. 모든 인스턴스 변수들이 저장되는 영역입니다. 힙 영역에서는 모든 객체는 Object 타입을 상속받습니다. 힙 영역은 stack 영역과 다르게 보관되는 메모리가 호출이 끝나더라도 삭제되지 않고 유지가 됩니다. 그러다 어떤 참조 변수도 Heap 영역에 있는 인스턴스를 참조하지 않게 되면 가비지 컬렉터가 메모리를 청소합니다.
33. 클래스와 인스턴스의 차이
클래스(Class) 란 객체를 만들어 내기 위한 설계도이고 연관되어 있는 변수와 메서드의 집합입니다. 인스턴스(Instance) 란 설계도를 바탕으로 구현된 구체적인 실체입니다. 즉, 객체를 실체화 하면 그것을 ‘인스턴스’라고 부릅니다. 실체화된 인스턴스는 메모리에 할당됩니다. 클래스는 붕어빵을 만들기 위한 틀이 되고 인스턴스는 붕어빵 틀로 찍어낸 각각의 붕어빵이다.
34. Spring Security의 구조와 JWT 발급 과정
Spring Security란 Spring 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크입니다. 인증(Authentication)은 해당 사용자가 본인이 맞는지를 확인하는 절차이고 인가(Authorization)는 인증된 사용자가 요청한 자원에 접근가능한지를 결정하는 절차로 인증 성공 후 인가가 이루어집니다. JWT(Json Web Tokens)는 통신시 권한 인가를 위해 사용하는 토큰으로, 사용자가 서버는 시크릿 키(secret key)를 통해 access token을 발급하고, 사용자에게 JWT를 전달합니다. 로그인이 필요한 api 호출 시 header에 jwt를 담아 전송 하게 되면 서버에서 JWT 서명을 확인 후(인증) secret key로 디코드하여 사용자 정보가 일치한다면 요청사항에 응답합니다(인가).
35. N+1 문제의 발생 이유와 해결 방법 (3가지 이상)
전 프로젝트에서 게시물 삭제를 할 때 연관된 댓글과 게시글 좋아요, 댓글 좋아요 등도 함께 지워지는데 cascade.remove를 사용해서 쿼리게시글 삭제시 다수의 쿼리가 날아가는 N+1 문제가 발생했던 적이 있었습니다. 추후에 @Modifying 을 이용해서 where in 을 써 쿼리를 직접 써서 문제 해결을 한 적이 있었습니다. where in을 사용하니 쿼리를 한번만 날려도 관련 데이터가 한꺼번에 삭제가 되었었습니다. 성능도 개선이 되었었습니다. 쿼리를 수정해서 n+1 문제를 해결하는 방법이 있었고 FetchJoin, EntityGraph, Batch Size(베치 사이즈 늘리기) 로 해결을 할 수 있습니다.
36. 즉시 로딩 vs 지연로딩
즉시 로딩이란, 데이터를 조회할 때, 연관된 모든 객체의 데이터까지 한꺼번에 불러오는 것이고, 지연 로딩이란, 필요한 시점에 연관된 객체의 데이터를 불러오는 것입니다. 따라서 연관된 모든 객체의 데이터 조회가 필요하다면 즉시 로딩을 사용하지만, 즉시로딩 사용시 예상치 못한 SQL 문제(N+1)가 발생할 수 있기 때문에 지연 로딩을 권장합니다.
37. JWT란? 어디서 처리는지, 검증방법, 재발급 방식
JWT는 Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token입니다. JWT는 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 정보를 안전하게 전달합니다. 주로 회원 인증이나 정보 전달에 사용됩니다. JWT는 Header, Payload, Signature 3부분으로 이루어지며, json 형태의 각 부분은 Base64Url로 인코딩 되어 표현 됩니다. JWT 처리는 로그인을 하게되면 서버에서 회원의 정보와 시그니처의 시크릿 키를 이용해 access 토큰과 refresh 토큰을 발급한 후에 클라이언트에게 넘겨주고 리프레쉬는 암호화하여 db에 저장해줍니다. 검증은 이 토큰이 서버가 발급한 토큰이 맞는지 확인합니다. 재발급 주기는 평균적으로 access 토큰은 2시간 refresh 토큰은 2주입니다. api 통신을 하게되면 클라이언트가 header에서 엑세스 토큰을 담아서 보내고 서버에서 검증한 뒤 API 로직이 수행됩니다.
38. Garbage Collector란?
C/C++ 같은 언어는 인스턴스를 만들 때 메모리를 할당하고 사용이 끝난 뒤 Destructor를 사용해 직접 해제해야했지만, 자바에서는 GC를 이용하여 개발자들이 메모리 관리를 비교적 신경쓰지 않아도 됩니다. GC에서 사용되지 않은 메모리를 내부 알고리즘에 의하여 수거해가기 때문입니다. 이로인해 자바는 메모리를 컨트롤해야 하는 언어보다 개발자가 좀 더 프로그래밍 로직에 집중할 수 하고 메모리 할당 이슈로부터 개발자의 부담을 덜 수 있게 되었습니다. 가비지 컬렉터는 힙영역에서 동적으로 할당했던 메모리 영역 중 필요 없게 된 메모리 영역을 주기적으로 삭제하는 프로세스를 말합니다. 예를 들면 더 이상 참조변수의 참조를 받고있지 않는 객체들을 가비지 컬렉터가 주기적으로 확인하여 제거합니다. GC는 Mark and Sweep 알고리즘을 사용합니다. 스택의 모든 변수 또는 Reachable 객체를 스캔하면서 각각이 어떤 객체를 참고하고 있는지를 탐색하고 사용되고있는 메모리를 식별하는데, 이러한 과정을 Mark라고합니다. 이후에 Mark가 되지 않은 객체들을 메모리에서 제거하는것을 sweep 이라고 합니다.
39. Java Map 내부구현은 어떻게 이루어져 있는가?
자바의 Map은 Key , Value으로 이루어진 데이터의 집합으로 Key의 중복을 하용하지 않으나 Value의 중복은 허용하고, 데이터 순서가 보장되지 않는습니다. Map의 구현 클래스는 HashMap, LinkedHashMap, TreeMap 등이 있습니다. Map에서 특정 데이터를 찾을 때는 key를 이용해서 검색을합니다. 가장 기본이되는 Map의 구현 클래스 HashMap은 순서보장없이 저장이 되고 treeMap은 정해진 정렬기준(숫자, 알파벳대분자, 소문자, 한글 )로 순서를 가지고, linkedHashMap은 입력순으로 데이터를 관리합니다.
스프링 IoC컨테이너가 생성되면 Component-Scan으로 Bean을 등록합니다. IoC컨테이너에서 의존성을 주입합니다. 스프링은 Bean에게 콜백 메서드를 통해 초기화 시점을 알려주며 스프링 컨테이너가 종료되기 직전에도 소멸 콜백 메서드를 통해 소멸 시점을 알려주고 스프링이 종료됩니다. 스프링의 콜백방식에는 3가지 방식이 있는데, 인터페이스 (InitializingBean, DisposableBean) 방식과 설정정보에서 초기화 메서드, 종료 메서드 지정하는법, @PostConstruct, @PreDestory 어노테이션을 사용하여 초기화 콜백/ 소멸전 콜백시 사용하는 방법이 있습니다. @PostConstruct, @PreDestroy 어노테이션입으로 스프링이 아닌 다른 컨테이너에서도 동작한다는 장점이 있지만 외부 라이브러리에는 적용하지 못합니다 @PostConstruct 의존관계 주입이 완료되면 호출되고 @PreDestroy 빈이 소멸되기 직전에 호출됩니다.
41. AOP, Interceptor, Filter 의 차이점, Request가 들어올때 거치는 순서, 각 역할들의 장점
세 가지 모두 공통 관심사를 처리하는 데에 있습니다. Interceptor와 Filter는 Servlet 단위에서 실행되고, AOP는 메서드 앞의 Proxy패턴의 형태로 실행됩니다. 실행 순서로는 Request가 들어오면 Filter -> InterCceptor -> AOP -> Intercepotr -> Filter가 됩니다. 필터의 역할은 요청과 응답을 거르고 정제하는 역할입니다. 일반적으로 인코딩 변환처리, 인증 인가 등의 요청에 대한 처리를 합니다 Interceptor는 요청에 대한 작업 전/후 로 가로챕니다. 스프링과 무관한 자원에 대해 동작을 하고, 보통 로그인, 권한 체크, 프로그램 실행 시간 게산 작업, 로그 확인 등의 업무를 처리합니다. AOP는 주로 '로깅', '트랜잭션', '에러 처리'등 비즈니스단의 메서드에서 조금 더 세밀하게 조정하고 싶을 때 사용하고 , Interceptor나 Filter와는 다르게 메소드 전후의 지점에 자유롭게 설정이 가능합니다.