🫥

최근호

Velog 글

JavaScript는 왜 싱글스레드인가?

목차

서론
시작하는 말
필수개념정리
JavaScript의 싱글 스레드 특성
언어적 측면
이벤트 루프
Node.js의 싱글 스레드 모델
Node.js란 무엇인가?
비동기 I/O
이벤트 드리븐 아키텍처
이벤트 드리븐 프로그래밍의 장점
결론
참고문헌

1. 서론

1.1 시작하는 말

방학동안 프로젝트를 시작하게 되면서 자바스크립트를 입문할 계기가 생겼습니다. 하나씩 공부하며 문득 자바스크립트는 싱글스레드임에도 어떻게 비동기처리가 가능 한 것인지, Node.js의 worker_threads는 멀티스레드라고 불러야 하는게 아닌지에 대한 궁금증에서 시작되어, 자바스크립트가 왜 싱글스레드를 선택했는가? 라는 궁금증을 해소하기위해 공부한 내용을 써보려고 합니다.

1.2 명칭 정리

프로세스: 실행중인 프로그램을 의미하며, 시스템 리소스를 할당 받음
스레드: 프로세스 내에서 실행되는 작업의 단위, 여러 스레드가 하나의 프로세스를 구성 할 수 있음
싱글 스레드: 하나의 스레드가 작업을 처리하는 방식
멀티 스레드: 여러 스레드가 병렬로 작업을 처리하는 방식
블로킹/논블로킹 : 블로킹은 현재 작업중인 프로세스 외에 다른 작업은 모두 차단하는 상태를 말하고, 논블로킹은 현재 작업중인 프로세스와 상관 없이 실행 가능한 상태를 말한다.
동기/비동기 : 동기는 실행중인 프로세스가 종료될 때까지 다른 프로세스는 기다려야 하는 상태, 비동기는 현재 실행중인 프로세스가 종료되지 않았더라도 실행 할 수 있는 상태를 말한다.
Callback: 특정 작업이 완료되었을 때 실행된다. 비동기 작업이 끝난 후 다음 실행될 작업을 정의하는 가장 기본적인 방법, 콜백 지옥이라는 대표적인 단점이 있음
Promise: 비동기 작업의 완료와 실패를 나타내는 객체, 콜백지옥을 해결하지만 문법이 복잡하다.
Async/Await: ES8에서 도입된 프로미스를 기반으로 비동기 코드를 동기코드처럼 작성 할 수 있게 하는 패턴. 코드 가독성이 높아지고, 동기식 코드처럼 작성할 수 있어 직관적이지만, Promise를 사용하지 않는 환경에서는 사용이 불가능함
이벤트 루프: JavaScript가 비동기 작업을 처리하는 메커니즘으로, 콜백 함수들을 큐에 넣고 순차적으로 실행함

1.3 싱글 스레드의 특징

싱글스레드는 한번에 하나의 일만 수행할 수 있다.
따라서 Context Switching(문맥 교환)이 필요하지 않다.
프로그래밍 난이도가 쉽고 자원(cpu,메모리)을 적게 쓴다.
cpu만 사용하는 단순 계산은 번갈아가면서 작업해야하는 멀티스레드보다 빠를 수 있다.
에러를 처리하지 못하거나 연산량이 큰 작업같은 경우에는 멈추거나, 다음 작업이 시작되는데 오랜 시간이 걸린다.

2. JavaScript의 싱글 스레드 특성

2.1 언어적 측면

JavaScript는 초기에 브라우저 내에서 사용자 인터페이스와 상호작용하기 위해 설계되었습니다. 사용자 경험을 저해하지 않기 위해, JavaScript는 한 번에 하나의 작업만 수행하도록 설계되었습니다. 이는 여러 작업이 동시에 발생할 경우 충돌이나 데이터 불일치 문제를 피할 수 있게 합니다.
싱글 스레드 모델은 JavaScript 엔진이 한 번에 하나의 작업을 처리하는 실행 컨텍스트를 갖고 있음을 의미합니다. 이로 인해 개발자는 복잡한 동시성 제어 문제를 신경 쓰지 않고도 코드를 작성할 수 있습니다.

2.2 이벤트 루프

JavaScript의 비동기 처리는 이벤트 루프에 의해 관리됩니다. 이벤트 루프는 콜백 함수들이 대기열에 추가되는 순서대로 실행되도록 보장합니다. 이 구조는 다음과 같은 단계를 포함합니다:
1.
콜 스택(Call Stack): 현재 실행 중인 함수가 쌓이는 구조입니다.
2.
태스크 큐(Task Queue): 비동기 작업(타이머, 네트워크 요청 등)이 완료되었을 때 콜백이 대기하는 큐입니다.
3.
이벤트 루프(Event Loop): 콜 스택이 비어 있을 때 태스크 큐에서 콜백을 꺼내 실행합니다.
이러한 이벤트 루프 메커니즘은 JavaScript가 싱글 스레드 환경에서도 효율적으로 비동기 작업을 처리할 수 있게 합니다.
console.log('Start'); setTimeout(() => { console.log('Timeout'); }, 0); console.log('End'); // 출력 결과: // Start // End // Timeout
JavaScript
복사

3. Node.js의 싱글 스레드 모델

3.1 Node.js란 무엇인가?

Node.js는 서버 사이드에서 자바스크립트를 실행할 수 있는 환경으로, 높은 성능과 확장성을 자랑합니다. 이러한 성능과 확장성의 핵심에는 이벤트 드리븐 아키텍쳐가 있습니다. 본 문서에서는 Node.js의 이벤트 드리븐 아키텍쳐에 대해 자세히 설명하겠습니다.

3.2 비동기 I/O

Node.js는 JavaScript 런타임 환경으로, 서버 측 애플리케이션을 구축하기 위해 설계되었습니다. Node.js는 I/O 작업을 비동기로 처리하여 싱글 스레드 모델의 한계를 극복합니다. 파일 시스템 접근, 네트워크 요청, 데이터베이스 쿼리 등의 I/O 작업은 비동기로 처리되어 메인 스레드가 차단되지 않습니다.

3.3 이벤트 드리븐 아키텍처

Node.js는 이벤트 루프를 사용하여 비동기 작업을 처리합니다. Node.js의 비동기 I/O와 이벤트 드리븐 아키텍처는 높은 성능과 확장성을 제공합니다. 많은 동시 연결을 효율적으로 처리할 수 있어 웹 서버로서의 강력한 성능을 발휘합니다.
이벤트 드리븐 아키텍쳐는 다음과 같은 요소들로 구성됩니다:
이벤트(Event): 시스템에서 발생하는 상태 변화나 작업.
이벤트 핸들러(Event Handler): 이벤트가 발생했을 때 실행되는 함수.
이벤트 루프(Event Loop): 이벤트를 계속해서 감시하고, 이벤트가 발생하면 적절한 핸들러를 호출하는 무한 루프.

3.4 이벤트 드리븐 프로그래밍의 장점

고성능: 비동기 I/O 작업을 통해 높은 처리량과 짧은 응답 시간을 유지할 수 있습니다.
확장성: 많은 클라이언트의 요청을 효율적으로 처리할 수 있습니다.
단순성: 이벤트 기반의 구조로 인해 코드가 직관적이고 이해하기 쉬워집니다.

4. 결론

JavaScript가 싱글 스레드인 이유는 언어 설계 초기부터 사용자 인터페이스와의 상호작용을 고려한 결과입니다. 싱글 스레드 모델은 단순성과 안정성을 제공하며, 이벤트 루프 메커니즘을 통해 비동기 처리를 효율적으로 관리합니다. Node.js는 이러한 특성을 활용하여 비동기 I/O와 이벤트 드리븐 아키텍처를 통해 높은 성능을 발휘합니다. 따라서 JavaScript와 Node.js의 싱글 스레드 모델은 복잡한 동시성 제어 없이 비동기 작업을 처리할 수 있는 유연하고 강력한 환경을 제공합니다.

5. 참고문헌

Mozilla Developer Network (MDN) Web Docs: Callback
Mozilla Developer Network (MDN) Web Docs: Promise
Mozilla Developer Network (MDN) Web Docs: Async/Await
Mozilla Developer Network (MDN). JavaScript Event Loop. MDN
Node.js 공식 문서. Node.js v20.x Documentation. Node.js

좋은 REST API란 무엇인가?

목차

1.
REST와 API의 정의
REST의 정의
API의 정의
2.
좋은 REST API의 특성
자원 기반의 구조
HTTP 메서드의 활용
상태 코드의 적절한 사용
데이터 형식의 일관성
보안 및 인증
버전 관리
문서화
3.
좋은 REST API의 설계 예시
사용자 자원 관리 예시

1. REST와 API의 정의(수정 전)

REST의 정의

REST(Representational State Transfer)는 분산 시스템의 소프트웨어 아키텍처 스타일 중 하나로, 웹 기반의 시스템에서 자주 사용됩니다. 2000년 로이 필딩(Roy Fielding)의 박사 학위 논문에서 처음 소개되었습니다. REST는 시스템 간의 상호작용을 단순하고 확장성 있게 만들기 위한 아키텍처 원칙을 제시합니다. 이는 주로 HTTP 프로토콜을 통해 이루어지며, 자원을 URI(Uniform Resource Identifier)로 식별하고, 해당 자원에 대한 작업을 표준 HTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하여 수행합니다.

API의 정의

API(Application Programming Interface)는 소프트웨어 간의 상호 작용을 정의하는 규칙과 도구의 집합입니다. API는 특정 기능을 노출하고, 다른 소프트웨어가 그 기능을 사용할 수 있게 합니다. API는 함수 호출, 데이터 구조, 클래스 및 프로토콜을 포함하여 다양한 형태로 제공될 수 있습니다.

2. 좋은 REST API의 특성

자원 기반의 구조

REST API는 자원을 중심으로 설계됩니다. 자원은 URI를 통해 고유하게 식별되며, 각 자원은 해당 URI에 매핑됩니다. 예를 들어, 사용자 정보를 관리하는 자원은 /users URI로 접근할 수 있습니다.
GET /users - 모든 사용자 목록 조회 GET /users/{id} - 특정 사용자 정보 조회 POST /users - 새로운 사용자 생성 PUT /users/{id} - 특정 사용자 정보 업데이트 DELETE /users/{id} - 특정 사용자 삭제
Plain Text
복사

HTTP 메서드의 활용

REST API는 HTTP 메서드를 활용하여 자원에 대한 작업을 수행합니다. 주요 HTTP 메서드와 그 의미는 다음과 같습니다:
GET: 자원의 조회
POST: 자원의 생성
PUT: 자원의 전체 수정
PATCH: 자원의 부분 수정
DELETE: 자원의 삭제

상태 코드의 적절한 사용

REST API는 클라이언트의 요청에 대한 결과를 나타내기 위해 HTTP 상태 코드를 사용합니다. 주요 상태 코드는 다음과 같습니다:
200 OK: 요청 성공
201 Created: 자원 생성 성공
400 Bad Request: 잘못된 요청
401 Unauthorized: 인증 필요
403 Forbidden: 접근 금지
404 Not Found: 자원을 찾을 수 없음
500 Internal Server Error: 서버 내부 오류

데이터 형식의 일관성

REST API는 JSON(JavaScript Object Notation)과 XML(eXtensible Markup Language)과 같은 데이터 형식을 사용하여 클라이언트와 서버 간에 데이터를 주고받습니다. 일반적으로 JSON이 더 널리 사용됩니다. API는 일관된 데이터 형식을 유지하여 사용자가 쉽게 이해하고 사용할 수 있도록 합니다.

보안 및 인증

REST API는 보안과 인증을 고려해야 합니다. 이를 위해 HTTPS를 사용하여 데이터 전송을 암호화하고, OAuth, JWT(JSON Web Token)와 같은 인증 방식을 채택합니다. 이러한 방식을 통해 사용자 데이터와 시스템을 보호할 수 있습니다.

버전 관리

API는 시간이 지남에 따라 변경될 수 있으므로, 버전 관리를 통해 호환성을 유지합니다. API 버전은 일반적으로 URI 경로에 포함됩니다.
GET /v1/users - 버전 1의 사용자 자원 접근 GET /v2/users - 버전 2의 사용자 자원 접근
Plain Text
복사

문서화

REST API는 명확하고 상세한 문서화를 통해 사용자가 API를 이해하고 사용할 수 있도록 합니다. 문서화에는 엔드포인트, 사용 가능한 메서드, 요청 및 응답 형식, 상태 코드 등이 포함되어야 합니다. Swagger와 같은 도구를 사용하면 자동화된 문서화를 제공할 수 있습니다.

3. 좋은 REST API의 설계 예시

사용자 자원 관리 예시

GET /users
Plain Text
복사
모든 사용자 목록을 반환합니다. 각 사용자는 JSON 형식의 객체로 표현됩니다.
GET /users/{id}
Plain Text
복사
특정 사용자의 정보를 반환합니다. {id}는 사용자의 고유 식별자입니다.
POST /users
Plain Text
복사
새로운 사용자를 생성합니다. 요청 본문에는 생성할 사용자의 정보(JSON 형식)가 포함됩니다.
PUT /users/{id}
Plain Text
복사
특정 사용자의 정보를 업데이트합니다. 요청 본문에는 업데이트할 사용자의 정보(JSON 형식)가 포함됩니다.
DELETE /users/{id}
Plain Text
복사
특정 사용자를 삭제합니다.

JSON 예시

사용자 생성 요청
POST /users { "name": "John Doe", "email": "johndoe@example.com", "password": "securepassword123" }
JSON
복사
사용자 정보 조회 응답
GET /users/1 { "id": 1, "name": "John Doe", "email": "johndoe@example.com", "created_at": "2024-06-29T12:34:56Z" }
JSON
복사

출처

Roy Fielding's Dissertation: "Architectural Styles and the Design of Network-based Software Architectures"
MDN Web Docs: HTTP Methods
REST API Tutorial (restfulapi.net)
Swagger (swagger.io)