Node.js로 데이터베이스 커넥션 풀을 구현하면서 사용하게 된 라이브러리를 정리하기 위해 작성합니다.
[generic-pool]
- Node.js에서 일반적인 자원 풀링을 구현할 수 있도록 도와주는 라이브러리임. - 이 라이브러리를 사용하면 자원( DB connection, HTTP 요청 등) 을 관리하고 재사용할 수 있음. - 특히, 데이터베이스 연결과 같은 생성 비용이 비싼 자원을 사용할 때 효과적임.
사용법 1. 풀 생성 및 구성 : "generic-pool" 을 사용하여 풀을 생성하고 필요한 옵션을 구성함. 2. 자원 생성 및 반환 로직 정의 : 풀에서 관리할 자원을 생성하고 반환하는 로직을 정의함. ( 이는 "create" 와 "destroy" 옵션에 해당함) 3. 자원 획득 및 반환 : "acquire" 함수를 사용하여 자원을 획득하고, 작업이 끝난 후에 "release" 함수를 사용하여 자원을 풀에 반환함.
사용이유 1. 성능향상 : 자원을 반복적이고 생성하고 소멸하는 것은 비용이 많이 들며 시스템 성능을 저하시킬 수 있음. 대신 자원을 풀에 보관하고 필요할 때 재사용함으로써 성능을 향상시킬 수 있음. 2. 자원관리 : 풀을 사용하면 동시에 여러 작업에서 자원을 공유하고 관리할 수 있음. 이는 메모리 누수나 자원 고갈과 같은 문제를 방지할 수 있음. 3. 서버 부하 감소 : 풀을 사용하면 서버에 대한 부하를 분산할 수 있음. 예를 들어, 데이터베이스 연결 풀을 사용하면 동시에 많은 클라이언트 요청을 처리할 수 있고, 데이터베이스 서버에 대한 과도한 부하를 방지할 수 있음. 4. 애플리케이션 확장성 : 풀을 사용하면 애플리케이션의 확장성을 향상시킬 수 있음. 풀을 관리하는 컴포넌트를 쉽게 확장하거나 교체하여 시스템의 요구 사항에 맞게 조정할 수 있음. 5. 안정성 : 풀을 사용하면 시스템이 과부하 상태일 때도 자원을 효율적으로 관리할 수 있음. 이는 시스템의 안정성을 높일 수 있음.
※ 자원 풀링 - 다수의 요청이 동시에 발생하는 경우, 요청마다 자원을 새로 생성하는 것이 아니라 풀에 미리 생선된 자원을 할당하여 사용하고, 작업이 끝나면 자원을 풀에 반환하는 방식으로 동작함. => 이를 통해 성능을 향상시킬 수 있음.
실무를 하다보니.. 새로운 것을 만들기보다는 기존에 있던 것을 유지보수 하거나 기능을 추가하는 일이 많습니다. 아무래도 새로운 모듈을 추가하거나 새로운 것을 처음부터 개발하는 경우는 많이 없었습니다. 그래서 잊고지내던 친구들을 다시 보고싶어 정리를 결심하게 되었습니다.
1. Node 프로젝트의 'devDependencies' 와 'dependencies' 의 차이.
1) dependencies (의존성) : 이 카테고리에 있는 패키지는 프로덕션 환경에서 실행될 때 필요한 패키지입니다. 즉, 실제로 애플리케이션이 동작할 때 사용됩니다. 이러한 패키지들은 애플리케이션의 핵심 로직을 지원하거나 실행에 필수적인 라이브러리임.
-> 이게 뭔말이냐.. npm install express 를 하면 express 모듈을 사용해서 서버를 구축하잖아요? 그럼 이건 프로덕션 환경(실제 서비스) 에서 사용되는 것이기 때문에 dependencies 에 속하게 되는 거죠..
2) devDependencies (개발 의존성) : 이 카테고리에 있는 패키지는 주로 개발 환경에서 개발자의 작업을 돕거나 테스트, 빌드, 디버깅 등을 지원하는 도구나 라이브러리임. 즉, 이러한 패키지들은 실제 프로덕션 환경에서 필요하지 않으며, 주로 개발자가 코드를 작성하고 테스트하는 동안 사용됨.
-> 이건... 많이들 사용하시는 npm install rand-token nodemon --save-dev 를 사용하는 경우죠. 그럼 대개 뭐가 있냐.. 위에서 install 한 라이브러리들이 대개 개발자의 작업을 돕는 도구나 라이브러리가 되는 것이죠.
개발을 진행하면서 CRUD만 작성을 하다보니깐 에러를 처리하는 부분이 마음에 들지 않아서!! 특히, catch부분에 ctrl + c , ctrl + v 로 500에러만 나타내주기 보다는 각각의 상황에 맞춰 에러를 핸들링 해주고 싶었습니다. 구글링을 통해서 best practice를 찾아보고 적용하면서 부족한 부분이 무엇인지에 대해서도 알 수 있었습니다. next()의 동작과 app.js의 플로우와 app.use를 세밀하게 더 살펴볼 수 있었고 제 코드에 적용할 수 있었던 기회였습니다!
자료구조 Hash에서 정리했듯이 crypto를 활용하여 비밀번호를 암호화 하는 방식에 대해서 왜 사용을 하였는지에 초점을 두고 정리를 하고자합니다.
솔트(Salt)란?
암호학에서 솔트는 데이터, 비밀번호, 통과암호를 해시 처리하는 단방향 함수의 추가 입력으로 사용되는 랜덤 데이터입니다.
솔트(Salt)는 왜 사용한 것인가요?
예를 들어, 'jeong-park' 이라는 스트링을 sha512로 해시 해보겠습니다. "2C1E444BE95BCB0236B7C82FDA667EC441B7A7E087898EA3299512675FADB1D65106905CEF0F757CB0D96A1AB82F97B83D3C64A8F30052893E6A8EC46D5935AA" 위처럼 나옵니다. 제가 아닌 다른 사람들이 'jeong-park'이라는 스트링을 입력하여 sha512로 해시하면 똑같이 나옵니다.
항상 똑같은 결과값을 반환한다면? 해시 함수를 사용하여 변환 가능한 모든 해시 값을 저장시켜 놓고 저장시켜 놓으면 원래의 비밀번호를 추출(레인보우 테이블)해낼 수 있지 않을까요? 이러한 문제 때문에 Salt을 사용하며, 또한 Key Stretching 이라는 친구를 사용합니다.
*Key Stretching은 해시된 값을 또 다시 해시 함수의 입력 값으로 넣어서 해싱을 반복하는 것입니다. 이런 방식으로 무작위 대입을 통해 해시 값을 구하는 시간을 늘려서 레인보우 테이블이나 무차별 대입 공격을 어렵게 하기 위함이라고 합니다.
1. createSalt : randomBytes 메소드로 64바이트 길이의 salt를 생성합니다. new_salt는 버퍼형식으로 나오기 때문에 toString("base64")을 사용하여 리턴해줍니다. 2. createHashedPassword : pbkdf2(유저가 입력한 비밀번호, 만들어준 솔트값, 키스트래칭, 비밀번호의 길이, 해시함수) 입니다.
(유저가 입력한 비밀번호 + 솔트 값) => Hash 값을 * Key Stretching 만큼 반복 하여 = HashedPassword를 만들어 줍니다.