내용 보기
작성자
관리자 (IP : 106.247.248.10)
날짜
2024-04-01 08:33
제목
[인터뷰 질문] [스크랩] 백엔드 질문들 (Java, Spring)
L, N, K 사 인터뷰 질문A오라클 조인 종류?간단하게 Inner, Outer, Left, Right [1] 등에 대한 질문이었음 과도하게 Broadcast Join, Nested loop 등을 생각하느라 답변을 잘 하지 못함 톰캣 ajp Connector 말고 다른 Connector?8기준 크게 HTTP Connector들(NIO, NIO2, APR) [3]과 AJP Connector 존재. 톰캣의 구조?Service, Engine, Host, Context, Connector 등의 객체로 구성된 구조. 서블릿 컨테이너 명세를 구현한 것. 스택 2개로 큐 만들기? 성능 개선 방법?하나는 insert용, 하나는 뒤짚기용 [4]. 성능 개선은 lazy 정도 밖에 떠오르지 않았음. Connection에서 Timeout 종류 [5]connect: 3-way handshake가 timeout 시간 안에 끝나야 함 read: 클라이언트가 서버로부터 timeout 시간 안에 응답을 받아야 함 write: 클라이언트가 서버에 timeout 시간 안에 성공적으로 write해야 함 HTTP keep-alive (client side): HTTP 헤더 일부로 클라이언트가 timeout 시간 안에 서버의 응답을 받지 못하면 서버가 살아 있는지 체크하기 위해 요청을 보냄. 죽었으면 Connection 끊음 Request (server side HTTP): 서버가 클라이언트로부터 timeout 시간 이상 데이터를 받지 않으면 서버는 Connection을 드랍함 (용어가 정확한지 모르겠음, HTTP keep-alive를 서버 관점에서 보는 것인 듯 함) Web Server의 Timeout이 매우 길고 요청이 무수히 많고 쓰레드 풀도 무한이며 작업은 그냥 무한한 sleep이라면, 가장 먼저 고갈되는 자원은?아마도 CPU-bound로 생각됨 [6] TCP Keepalive 길때 생기는 문제는?새롭게 진입하려는 커넥션이 자원을 사용하지 못해 생성되지 못함. 스프링 MVC 동작 방법?서블릿 구현체로 서블릿 - DispatcherServlet - Controller 간의 요청, 응답을 주고 받음. MQ 쓰는 이유?Kafka를 만든 Jay Kreps 글에서 로그의 역할과 관련되어 답변하려 했음 (이미지가 떠올랐음). MQ이기에 Kafka와 같은 장점은 많은 제약이 있어서(여러번 consume, 복잡도 줄이는 것? 등), 앞뒤 간의 의존성을 없앨 수 있는 부분이 크다고 답변함. (대략 decouple이라는 점과 상통하는 듯 [9]) 이벤트 소싱 형태에서 데이터의 상태를 복원하는 방법?Write-ahead log 같은 것을 이벤트 소싱 형태로 스트림으로 흘려주고, replay를 통해 복제할 수 있다고 함. CDC와 같은 도구들도 언급 [10]. BInterface vs abstract class [12]가볍게 이해하고 있는 부분만 언급했는데, default method를 예로들며 추가 질문이 들어왔음. Polymorphism과 연관되어 어떠한 답변을 기대한 듯 하였음. Abstract class는 언제 쓸까?
Interface는 언제 쓸까?
브라우저를 켜서 특정 사이트 접속 시 발생하는 일을 OSI 7계층 관점에 기반해 설명해달라[31, 32] mutex와 semaphore의 차이는? [27, 28, 29, 30]mutex mutex는 mutual exclusion을 제공하는 locking mechanism입니다. critical region은 task한 task가 '소유하게(Principle of Ownership)' 됩니다. mutex는 이러한 ownership의 존재로 인해 semaphore의 아래와 같은 문제점을 해결해줍니다:
몇몇 OS 내부의 mutex는 구현에 따라 Recursion, Priority inheritance, Death Detection을 지원하거나 지원하지 않을 수 있습니다. semaphore semaphore는 signaling mechanism으로 resource를 접근으로부터 protecting하지 않습니다. Semaphore의 Giving과 Taking은 근본적으로 decoupled되어 있습니다. 크게 binary와 counting semaphore가 존재합니다. 예로, 주차장을 관리하는 시스템의 경우 처음에 주차장 갯수를 count에 설정합니다. 이후 자리가 사용되면서 count는 줄어들게 되는데요. count가 0이 되면 다음 차는 주차가 blocked됩니다. 이후 차 1대가 나가면서 count는 1로 증가하고 기다리던 차가 사용할 수 있게 됩니다. 좀 더 시그널링적인 측면을 잘 나타내고 있는 예는 아래와 같습니다:
Task B는 특정 이벤트 발생을 기다립니다. Task A는 특정 이벤트 발생을 알리기 위해 어떠한 액션을 취하고, Task B는 그러한 부분을 확인하게 됩니다. 특히, binary semaphore에서 B가 semaphore를 take한 후에 A가 semaphore를 놓아주었다는 부분입니다. 이렇게 Binary semaphore는 리소스 접근에 대한 protecting을 하지 않습니다. AOP란? AOP의 주된 패턴은?개념은 잘 말했는데 안써봐서 그런지 패턴은 무엇이고, 내부는 어떻게 되어 있는지에 대한 질문에 답변 못함. AOP는 프로그래밍 패러다임으로 cross-cutting하여 특정 '측면'을 분리하고 모듈성을 높일 수 있음 [15]. AOP의 주된 패턴은 Proxy로 Spring AOP는 jdk dynamic proxies를 스탠다드로 사용함. 또한, CGLIB proxies도 사용할 수 있며 AspectJ를 사용해 annotation을 사용할 수 있음 [16]. Proxy 패턴을 보면, 정적 및 동적 프록시 패턴이 있음. [17] 정적은, 직접 @Override하거나
인터페이스와 구현체 타겟 클래스를 Proxy 클래스에 embed하여 아래와 같이 구현 가능:
그러나 타겟 클래스가 100개면 Proxy 클래스도 100개를 작성해야 되서 중복이 많이 발생함. 동적은 jdk dynamic agent 또는 cglib dynamic agent를 사용해서 구현할 수 있는데, 동적이든 정적이든 타겟 클래스 메소드에 변형을 가하진 않음. 먼저 jdk dynamic agent 기반은:
cglib은 low-level bytecode 기술을 사용함. bytecode 기술을 통해 클래스에 대한 서브클래스를 생성하고, 서브클래스에서 메소드 인터셉션 기술을 통해 부모 클래스 메소드에 대한 모든 콜을 인터셉트하고 cross-cutting 로직을 수행함:
JDK는 인터페이스를 구현하는 클래스 내 메소드만 프록시할 수 있음. cglib는 상속에 기반한 프록시를 하여 static, final 클래스를 프록시 할 수 없음. cglib은 private, static 메소드 프록시 불가능. AOP는 프로그래밍적 사고 방식으로 특정 메소드에 대해 non-intrusive extension이 가능하게 함. Spring AOP에는 Aspect, Join Point, Advice, Pointcut, Introduction, Target object, AOP Proxy, weaving 등의 개념이 존재하는데, 구현은 대략 아래와 같이 가능함: Advice 클래스 생성:
config 설정:
Python GIL쓰레드 풀 이야기 하다 파이썬 이야기로 흘러서 GIL 질문이 들어옴. 어버버 하다 이상하게 답변. Global Interpreter Lock으로 mutex로 언제나 오직 1개의 쓰레드만 Python interpreter의 control을 허용하도록 함. [18, 19] 파이썬은 가비지 콜렉션을 위해 reference counting을 사용하는데, 여러 개의 쓰레드가 reference 수를 동시에 변경하면 reference leak이 발생함. 그러한 부분을 막기 위해서는 공유되는 모든 객체에 lock을 걸어 reference를 추적해야 하는데, 이것보다는 interpreter에 lock을 걸어서 오직 1개의 쓰레드만 reference count를 변경할 수 있도록 하는 것이 더 쉽고 싱글쓰레드 상에서 빠름. CPU-bound면 매우 문제가 되나 대부분 프로그램이 IO-bound이고, 기존에는 쓰레드별로 균등하게 lock time을 분배했으나 Python 3.2에서는 쓰레드의 GIL acquisition request 수에 따라(CPU-bound, IO-bound 작업이 동시에 존재할 때 CPU-bound에 더 배분하기 위해) 분배함. CPython 말고 다른 구현체도 존재하니 대안으로 사용할 수 있고 (PyPy도 GIL을 달고 있긴 함 [20]) Filter & HandlerInterceptorFilter: webserver의 일부로 Spring 프레임워크에 속하지 않음. filter를 사용해 request를 조작하거나 servlet에 닿는 것을 막을 수도 있음. Coarse-grained tasks인 인증, 로깅 및 auditing, image와 data 압축, Spring MVC와 동떨어진 기능에 적절. HandlerInterceptor: Spring MVC 프레임워크의 일부로 DispatcheerServlet과 Controller 중간에 위치함. 애플리케이션 로깅과 같은 cross-cutting concerns, 상세한 인가 체킹, Spring context나 model 조작에 적절. Polymorphism이란? [22]Consequently, you can write programs that expect an object with a particular interface, knowing that any object that has the correct interface will accept the request. Moreover, dynamic binding lets you substitute objects that have identical interfaces for each other at run-time. This substitutability is known as polymorphism. Java primitive, reference type의 memory location@Transactional 내부구조? [24]So when you annotate a method with @Transactional, Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism. As you observed, though, the proxy mechanism only works when calls come in from some external object. When you make an internal call within the object, you're really making a call through this reference, which bypasses the proxy. There are ways of working around that problem, however. I explain one approach in this forum post in which I use a BeanFactoryPostProcessor to inject an instance of the proxy into "self-referencing" classes at runtime. I save this reference to a member variable called me. Then if I need to make internal calls that require a change in the transaction status of the thread, I direct the call through the proxy (e.g. me.someMethod().) Java hashmap 구조?Hash Table로 Chaining을 사용해 구현됨 [25] CLogging을 Plain Java로 직접 구현한다고 하면 어떻게 구현하겠는가?질문의도를 파악하다 오래 걸림. 프레임워크를 떠나서 본질적인 CS 기반에서 많이 생각하라고 조언 받음. 대략적인 답변은 "메모리에 쓰고, 주기적으로 파일로 쓴다, 그러한 처리는 추가적인 쓰레드로 구현하고 Spring Controller가 싱글톤이니 하나의 static 멤버로 큐를 두고 가져가는 형태로 구현하겠다" 정도. 64 bit 숫자 데이터를 CRD하는 앱을 만든다고 하면 자료구조는 무엇을 쓰고 어떻게 구현하겠는가?외운 답을 뱉지 말고, 하나씩 구체적으로 구현하는 레벨로 설명해줄 것을 당부받음. 해시 테이블은 떠올랐으나 원하는 답변을 찾기까지 추가적인 질문이 계속됨. 무슨 해시 함수 쓸지 말하다가 실수해서 좀 더 자세히 공부할 필요가 있다고 느낌 [26]. 해시 테이블에 추가질문이 들어와 Chaining, Open Addressing 등을 이야기 하다가,
우여곡절 끝에 double hashing을 떠올리고, (dynamic) perfect hashing을 떠올리고 답변 Struts, DWR, Spring 비교?주요 특징은 아래 표를 통해 비교해 볼 수 있습니다 [33, 34]:
Struts를 Spring으로 변경한 이유는?전체적으로 일관된 프레임워크를 사용해 복잡도를 줄임, 테스트가 용이하도록. 리팩토링을 진행하며 기술적으로 챌린징했던 점은?질문 시 원하는 것이 "엄청난 트래픽으로 발생한 문제를 탁월한 기술력으로 해결"과 같은 기술적 난제 해결 사례라고 느꼈으나 사실 그런 것은 없고 파악하기 힘든 히스토리, 알 수 없는 담당자, 레거시가 많았기에 기술적으로 조금 포장해서 말하다가 빙빙 돔. DMap에서 해시 기반과 트리 기반 구현의 차이 [35, 36, 37]Java HashMap은 AbstractMap class를 extend하며 Map interface를 implement함. Map 구현체는 보통 bucketed hash table로 동작하나 buckets이 너무 커지면 TreeNodes의 노드들로 변환되어 각각의 구조가 java.util.TreeMap과 유사해짐. TreeMap은 AbstractMap class를 extend하고 NavigableMap interface를 implement함. TreeMap은 요소들을 Red-Black tree에 저장함(Self-Balancing Binary Search Tree).
hash collision?두 개의 다른 데이터의 해시 값이 같을 때를 말함. Resolution 방법 [36]
Java List와 Stream의 차이Stream은 아래와 같은 부분에서 Collections과 다르다 [37]:
HDFS를 CAP theorem에 기반해 설명하면? [38]HDFS는 일관성(Consistency)과 Partition tolerance를 지원하고, Availability 부분에 trade-off가 존재함. Consistency HDFS 문서 상에 아래와 같은 내용들은 HDFS가 일관성을 가지고 있다는 사실을 잘 보여줌
Availability 문서 상의 아래와 같은 내용은 Available하지 않다는 부분을 시사함. HA를 제공하나, 네임노드는 SPOF로 다운 시 파일 시스템에 대한 접근이 일시적으로 불가능해짐.
Partition Tolerance Partition은 분산 시스템에서의 통신 단절을 말함 [39]. HDFS의 데이터노드 중 한 대의 노드가 다운되거나 사라져도 시스템은 영향을 받지 않고 운영 될 수 있음. OAuth를 잘 아는가?잘 모른다고 대답. 접근 위임을 위한 open standard (authorization protocol). 주로 인터넷 사용자가 웹사이트나 애플리케이션이 다른 웹사이트에 존재하는 사용자의 정보에 비밀번호 없이 접근할 수 있도록 허용해주는 데에 사용됨. Spring Security를 많이 써보았는가?많이 안써봤다고 대답. Java 애플리케이션에 인증가 인가를 제공함 [41]. (Coding) List를 Java Array만으로 구현하기[42] 메시지 서비스를 데이터베이스를 사용해 구현한다고 할 때, 대략적인 ERD는?위 메시지 서비스를 Kafka를 사용해 구현한다면 어떠한 방식으로 구현될 것 같은가?Reference [1] https://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj29840.html [2] https://kadensungbincho.com/blog/backend/apache-tomcat-internals [3] https://tomcat.apache.org/tomcat-8.5-doc/config/http.html#Connector_Comparison [4] https://stackoverflow.com/a/39089983/8854614 [5] http://www.allenlipeng47.com/blog/index.php/2020/01/05/timeouts/ [6] https://softwareengineering.stackexchange.com/a/70717 [7] https://kadensungbincho.tistory.com/58 [9] https://aws.amazon.com/message-queue/benefits/ [10] https://kadensungbincho.tistory.com/98 [11] https://www.tutorialspoint.com/when-to-use-an-abstract-class-and-when-to-use-an-interface-in-java [12] https://byexample.xyz/java/8/default/ [13] https://stackoverflow.com/a/479168/8854614 [14] https://stackoverflow.com/a/479154/8854614 [15] https://www.baeldung.com/aspectj [16] https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop [18] https://realpython.com/python-gil/ [19] https://www.youtube.com/watch?v=Obt-vMVdM8s [20] https://doc.pypy.org/en/latest/faq.html#does-pypy-have-a-gil-why [21] https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter [22] Design Patterns Elements of Reusable Object-Oriented Software [23] https://stackoverflow.com/a/32049775/8854614 [24] https://stackoverflow.com/a/1099284/8854614 [25] https://www.geeksforgeeks.org/internal-working-of-hashmap-java/ [26] https://kadensungbincho.tistory.com/122 [27] https://stackoverflow.com/a/86021/8854614 [28] https://www.geeksforgeeks.org/mutex-vs-semaphore/ [29] https://blog.feabhas.com/2009/09/mutex-vs-semaphores-%E2%80%93-part-1-semaphores/ [30] https://barrgroup.com/embedded-systems/how-to/rtos-mutex-semaphore [31] https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/How_the_Web_works [32] https://kadensungbincho.tistory.com/70 [33] https://www.educba.com/spring-vs-struts/ [34] https://netbeans.apache.org/kb/docs/web/quickstart-webapps-struts.html [35] https://www.baeldung.com/java-treemap-vs-hashmap [36] https://stackoverflow.com/a/31161193/8854614 [37] https://stackoverflow.com/a/39432937/8854614 [38] https://stackoverflow.com/questions/58796173/how-does-the-cap-theorem-apply-on-hdfs [39] https://www.ibm.com/cloud/learn/cap-theorem [40] https://en.wikipedia.org/wiki/OAuth [41] https://docs.spring.io/spring-security/site/docs/current/reference/html5/ [42] https://www.geeksforgeeks.org/internal-working-of-arraylist-in-java/ [43] https://tech.kakao.com/2020/06/08/websocket-part1/ [44] https://vertabelo.com/blog/database-model-for-a-messaging-system/ [45] https://dba.stackexchange.com/questions/268388/chat-conversation-history-entity-relationship-diagram [46] https://dba.stackexchange.com/questions/268388/chat-conversation-history-entity-relationship-diagram [47] https://stackoverflow.com/a/8351589/8854614 [48] https://stackoverflow.com/a/6542556/8854614 [49] https://stackoverflow.com/a/6425511/8854614 [50] https://engineering.linecorp.com/en/blog/the-architecture-behind-chatting-on-line-live/ |
출처1
https://kadensungbincho.com/blog/backend/backend-interview-questions-that-i-ve-been-asked?utm_source=tistory&utm_campaign=auto&utm_medium=blog
출처2