문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 다음 판 양쪽 다음 판 | ||
web:신규서비스 [2021/11/12 16:51] kwon37xi [이미지와 정적 리소스 서빙 시스템 image, static resources] |
web:신규서비스 [2022/03/03 23:38] kwon37xi [확장성 고려] |
||
---|---|---|---|
줄 19: | 줄 19: | ||
===== 신기술 선택 ===== | ===== 신기술 선택 ===== | ||
* 다음과 같은 용어를 확인해볼것. | * 다음과 같은 용어를 확인해볼것. | ||
- | * '' | + | * '' |
===== 용어 통일 ===== | ===== 용어 통일 ===== | ||
줄 78: | 줄 78: | ||
* 게다가 그 와중에 또다른 권한 군이 들어오게 되면 모든 MSA 서비스가 그것들을 모두 신경써가면서 개발해야하게 되어 개발 속도를 떨어뜨리고 보안 위협이 시작되게 된다. | * 게다가 그 와중에 또다른 권한 군이 들어오게 되면 모든 MSA 서비스가 그것들을 모두 신경써가면서 개발해야하게 되어 개발 속도를 떨어뜨리고 보안 위협이 시작되게 된다. | ||
* **외부 노출 API가 인증과 권한을 전담해야 한다.** | * **외부 노출 API가 인증과 권한을 전담해야 한다.** | ||
+ | * 하나의 API 애플리케이션은 하나의 인증만 처리한다. 인증이 여러 종류가 섞이는 순간 혼동으로 인해 보안 사고가 발생할 확률이 높아진다. 특히, **Front 서버에 내부용 API를 넣는 행동은 절대로 해서는 안된다.** | ||
===== 약한 결합도 높은 응집도의 Inteface 기반 개발 ===== | ===== 약한 결합도 높은 응집도의 Inteface 기반 개발 ===== | ||
* 각각의 모듈간의 호출은 '' | * 각각의 모듈간의 호출은 '' | ||
줄 127: | 줄 128: | ||
* 비추천(계정관련만 https) : '' | * 비추천(계정관련만 https) : '' | ||
* 개발용 도메인을 '' | * 개발용 도메인을 '' | ||
+ | * 내부망용 도메인 네임 규칙과 외부망용 도메인 네임 규칙을 명확히 가져가야 보안 이슈 발생시 대응이 쉽다. | ||
===== 안정성 ===== | ===== 안정성 ===== | ||
* SPoF(Single Point of failure)를 제거하라. | * SPoF(Single Point of failure)를 제거하라. | ||
줄 133: | 줄 135: | ||
===== 확장성 고려 ===== | ===== 확장성 고려 ===== | ||
- | * 선형 증가 데이터와 지수적 증가 데이터를 잘 구분하여 선형 증가 데이터는 RDBMS(혹은 상황에 따라 다른 적합한 것), 지수적 증가 데이터베이스는 RDBMS sharding 혹은 [[: | + | * 선형 증가 데이터와 지수적 증가 데이터를 잘 구분하여 |
+ | * 선형 증가 데이터 : 상품, 사용자 등 | ||
+ | * 지수적 증가 데이터 : 주문, 배송 등 상품에 대해 사용자가 행위하는 것 | ||
+ | * 선형 증가 데이터는 RDBMS(혹은 상황에 따라 다른 적합한 것), 지수적 증가 데이터베이스는 RDBMS sharding 혹은 [[: | ||
* 초반부터 지나친 확장성 대비는 오히려 악영향을 줄 수 있는 것은 사실이지만, | * 초반부터 지나친 확장성 대비는 오히려 악영향을 줄 수 있는 것은 사실이지만, | ||
* 현재(2013) 상황으로 봤을 때 처음부터 NoSQL을 도입하는 것이 RDBMS를 도입하는 것과 비교해서 특별히 더 어렵지도 않게 되었다. | * 현재(2013) 상황으로 봤을 때 처음부터 NoSQL을 도입하는 것이 RDBMS를 도입하는 것과 비교해서 특별히 더 어렵지도 않게 되었다. | ||
줄 177: | 줄 182: | ||
* 중요 테이블의 경우 최종 수정된 내용만 가지고 있고 그에 대해 제약 조건을 모두 지키도록 설계한다. 다만, 변경시마다 **중요 변경사항을 history 테이블을 따로 두어** 남기도록 한다. 그래야 서비스 유지보수시 알 수 없는 오류에 대한 참고 데이터로 삼아 고객의 요구에 대해 올바로 대응 할 수 있다. history는 RDBMS 가 아니라 NoSQL로 남기는 것도 좋다. | * 중요 테이블의 경우 최종 수정된 내용만 가지고 있고 그에 대해 제약 조건을 모두 지키도록 설계한다. 다만, 변경시마다 **중요 변경사항을 history 테이블을 따로 두어** 남기도록 한다. 그래야 서비스 유지보수시 알 수 없는 오류에 대한 참고 데이터로 삼아 고객의 요구에 대해 올바로 대응 할 수 있다. history는 RDBMS 가 아니라 NoSQL로 남기는 것도 좋다. | ||
* **컬럼의 의미를 바꾸지 말 것.** DB의 역사가 오래될 수록 컬럼의 의미를 중간에 바꾸는 경우가 있는데, **컬럼의 의미를 변경하려면 기존 데이터를 모두 마이그레이션 하던지, 새로운 컬럼을 만들어서 새로운 의미를 부여하든지 한다.** 기존 데이터를 그대로 남겨둔 상태로 컬럼의 의미를 바꾸면 매핑되는 객체 구조 설계에도 문제가 생기고 쿼리 결과를 처리하는 모든 구문에 상황에 따른 조건문이 계속 추가되어 개발 부담을 가중시키게 된다. | * **컬럼의 의미를 바꾸지 말 것.** DB의 역사가 오래될 수록 컬럼의 의미를 중간에 바꾸는 경우가 있는데, **컬럼의 의미를 변경하려면 기존 데이터를 모두 마이그레이션 하던지, 새로운 컬럼을 만들어서 새로운 의미를 부여하든지 한다.** 기존 데이터를 그대로 남겨둔 상태로 컬럼의 의미를 바꾸면 매핑되는 객체 구조 설계에도 문제가 생기고 쿼리 결과를 처리하는 모든 구문에 상황에 따른 조건문이 계속 추가되어 개발 부담을 가중시키게 된다. | ||
- | * DB 자체의 타입 enum 을 사용하지 말라. 또한 프로그래밍 언어 enum 을 사용할 때 절대로 순서 숫자값(ordinal)로 저장하면 안된다. 이 둘은 모두 enum 항목들의 순서 변경이 발생하는 순간 엄청난 마이그레이션을 수행해야한다. 그에 비해 성능 향상은 그리 크지 않아보인다. | + | * DB 자체의 타입 enum 을 사용하지 말라. 또한 프로그래밍 언어 enum 을 사용할 때 절대로 순서 숫자값(ordinal)로 저장하면 안된다. 이 둘은 모두 enum 항목들의 순서 변경이 발생하는 순간 엄청난 마이그레이션을 수행해야한다. 그에 비해 성능 향상은 그리 크지 않아보인다. MySQL의 enum은 겉보기와는 달리 ordinal 로 작동하기 때문에 **enum 의 순서가 변경**되면 단순 alter table로 문제가 해결되지 않고 기존 데이터를 모두 마이그레이션 해야 한다. |
* 과도한 동적 쿼리를 생성하지 말라. - 특히 iBatis/ | * 과도한 동적 쿼리를 생성하지 말라. - 특히 iBatis/ | ||
* 상태에 따라 WHERE 절이 나타났다 사라졌다하는 식의 동적 쿼리는 자칫 실수하면 모든 조건이 없어져서 엄청난 부하를 일으키는 SELECT 쿼리나 모든 데이터를 삭제하는 DELETE 문이 될 수 있다. | * 상태에 따라 WHERE 절이 나타났다 사라졌다하는 식의 동적 쿼리는 자칫 실수하면 모든 조건이 없어져서 엄청난 부하를 일으키는 SELECT 쿼리나 모든 데이터를 삭제하는 DELETE 문이 될 수 있다. | ||
줄 183: | 줄 188: | ||
* 필요한 쿼리는 항상 상황별로 다 따로 만든다. | * 필요한 쿼리는 항상 상황별로 다 따로 만든다. | ||
* Backup/Fail Over 전략을 수립해둔다. : DB 생성 초기 부터 백업/ | * Backup/Fail Over 전략을 수립해둔다. : DB 생성 초기 부터 백업/ | ||
- | * 페이징으로 데이터를 불한/ | + | * 페이징으로 데이터를 불한/ |
* '' | * '' | ||
* 처리처럼 데이터를 분할해서 가져갈 경우 항상 '' | * 처리처럼 데이터를 분할해서 가져갈 경우 항상 '' | ||
* 대체로 **PK asc**를 하는게 DB에서 가장 성능이 좋다. [[https:// | * 대체로 **PK asc**를 하는게 DB에서 가장 성능이 좋다. [[https:// | ||
+ | * [[https:// | ||
* offset/ | * offset/ | ||
* 사용자 ID 같은 경우에는 소문자로통일해서 받는것이 좋다. 대문자로 입력해도 소문자로 변환한다. 사용자는 자신이 대소문자를 어떻게 입력했는지 혼동하는 경우가 많다. 단 email 같은 외부 값을 받는 경우는 있는 그대로 넣어야 한다. | * 사용자 ID 같은 경우에는 소문자로통일해서 받는것이 좋다. 대문자로 입력해도 소문자로 변환한다. 사용자는 자신이 대소문자를 어떻게 입력했는지 혼동하는 경우가 많다. 단 email 같은 외부 값을 받는 경우는 있는 그대로 넣어야 한다. | ||
줄 287: | 줄 293: | ||
* 문자 필드에 어떤 문자를 사용할 수 없게 해야하는 상황일 경우에도, | * 문자 필드에 어떤 문자를 사용할 수 없게 해야하는 상황일 경우에도, | ||
* 인증 토큰(token) 은 변조가 불가하면서 애플리케이션 사용에 필요한 최소한의 데이터를 담도록 한다. [[web: | * 인증 토큰(token) 은 변조가 불가하면서 애플리케이션 사용에 필요한 최소한의 데이터를 담도록 한다. [[web: | ||
+ | * DDoS 공격 방어를 위해 WAF(Web Application Firewall, 웹방화벽) 설정을 해야한다. | ||
===== 서버 운영 ===== | ===== 서버 운영 ===== | ||
* 절대로 여러 사람이 공유하는 공용 계정으로 서버를 관리하지 말라(AWS 등 포함). 이는 치명적인 보안 사고로 이어진다. | * 절대로 여러 사람이 공유하는 공용 계정으로 서버를 관리하지 말라(AWS 등 포함). 이는 치명적인 보안 사고로 이어진다. | ||
줄 326: | 줄 333: | ||
* 이렇게 해야 '' | * 이렇게 해야 '' | ||
* 절대로 예외를 먹지 말것. 정말 특별한 경우가 아니면 항상 예외의 stacktrace까지 모두 남길것. 특별한 경우에는 왜 특별한지 주석 달 것. | * 절대로 예외를 먹지 말것. 정말 특별한 경우가 아니면 항상 예외의 stacktrace까지 모두 남길것. 특별한 경우에는 왜 특별한지 주석 달 것. | ||
+ | * UI 관점에서 사용자 행위 로그를 꼭 남기도록 하고 이를 분석하여 개선 방향을 도출할 수 있도록 한다. | ||
===== Production Server ACL ===== | ===== Production Server ACL ===== | ||
* 운영 시스템에 대한 ACL은 개발 초기부터 망 분리 등을 통해 운영시스템에서만 접속가능하도록 하고 **절대 개발자 PC, 테스트 시스템 등에서는 접속이 불가능**하도록 구성한다(여기서 말하는 접속은 서버에 대한 SSH 접속이 아니라 DB,Redis,MQ 같은 시스템, API 서버 등에 대한 접속을 뜻한다). | * 운영 시스템에 대한 ACL은 개발 초기부터 망 분리 등을 통해 운영시스템에서만 접속가능하도록 하고 **절대 개발자 PC, 테스트 시스템 등에서는 접속이 불가능**하도록 구성한다(여기서 말하는 접속은 서버에 대한 SSH 접속이 아니라 DB,Redis,MQ 같은 시스템, API 서버 등에 대한 접속을 뜻한다). | ||
줄 377: | 줄 384: | ||
* API 호출 내부에서 다른 API를 호출해서 결과를 합치는 일을 하는 것은 좋지 않다. 내부 호출 API의 장애가 전체적으로 다 전파 돼 버린다. | * API 호출 내부에서 다른 API를 호출해서 결과를 합치는 일을 하는 것은 좋지 않다. 내부 호출 API의 장애가 전체적으로 다 전파 돼 버린다. | ||
* 최초의 API호출자는 여러 API 호출이 필요하면 다른 API에게 또 다른 API호출을 요청하기 보다는 스스로 모든 요청을 하는게 장애 포인트를 줄여나가는 방법이다. | * 최초의 API호출자는 여러 API 호출이 필요하면 다른 API에게 또 다른 API호출을 요청하기 보다는 스스로 모든 요청을 하는게 장애 포인트를 줄여나가는 방법이다. | ||
- | ===== MQ 등을 통한 비동기 처리 ===== | + | * 오류가 나면 오류를 발생시키는게 낫다('' |
+ | * 오류 발생시 API 응답은 '' | ||
+ | * 이렇게 되면 모든 호출자가 응답에 오류코드가 있는지 일일이 확인해야 한다. | ||
+ | * 이를 확인하지 않고 데이터를 사용할 경우 에러가 즉각 발생했으면 오히려 문제가 덜 발생했을 것을 더 큰 문제로 커지게 된다. | ||
+ | * 예를들어 에러코드는 존재하고, | ||
+ | ===== MQ 등을 통한 비동기 처리 | ||
* 비동기 처리는 반응 속도를 높이고 전송 신뢰도를 높여주는 등 좋은 점이 있지만 단점들도 많으므로 확실히 이해해야 한다. | * 비동기 처리는 반응 속도를 높이고 전송 신뢰도를 높여주는 등 좋은 점이 있지만 단점들도 많으므로 확실히 이해해야 한다. | ||
* 메시지 전송이 실패하는 경우(클라이언트측 버그로 메시지를 먹어버리고 종료되는 경우, 프로듀서는 보냈다고 됐지만 네트워크 단절 등으로 안 가는 경우등이 발생함)에 대비히 철저하게 메시지 재전송이 가능하도록 솔루션을 만들어야 한다. | * 메시지 전송이 실패하는 경우(클라이언트측 버그로 메시지를 먹어버리고 종료되는 경우, 프로듀서는 보냈다고 됐지만 네트워크 단절 등으로 안 가는 경우등이 발생함)에 대비히 철저하게 메시지 재전송이 가능하도록 솔루션을 만들어야 한다. | ||
줄 383: | 줄 395: | ||
* **비동기 타이밍 문제도 심각하다.** 이 경우 비동기를 사용하면 안되는데 비동기를 사용한 경우일 수 있다. A -> B로 메시지를 보냈는데 B 가 메시지를 Consuming 하기 전에 A 혹은 C 등의 다른 서비스가 B가 메시지를 받았다는 가정하에 어떤 행위를 할 경우 오류가 발생한다. 매우 빈번히 발생하는 문제이다. 비동기를 사용하면 안 되거나 B가 메시지를 받았는지 확인할 수 있는 방안을 강구해야 한다.(JMX의 경우에는 Consume 확인 기능이 존재함) | * **비동기 타이밍 문제도 심각하다.** 이 경우 비동기를 사용하면 안되는데 비동기를 사용한 경우일 수 있다. A -> B로 메시지를 보냈는데 B 가 메시지를 Consuming 하기 전에 A 혹은 C 등의 다른 서비스가 B가 메시지를 받았다는 가정하에 어떤 행위를 할 경우 오류가 발생한다. 매우 빈번히 발생하는 문제이다. 비동기를 사용하면 안 되거나 B가 메시지를 받았는지 확인할 수 있는 방안을 강구해야 한다.(JMX의 경우에는 Consume 확인 기능이 존재함) | ||
* MQ Consumer 서버를 API 서버와 분리한다. MQ Consumer 가 DB 커넥션 쓰레드나, | * MQ Consumer 서버를 API 서버와 분리한다. MQ Consumer 가 DB 커넥션 쓰레드나, | ||
+ | * Event body 에 모든 데이터를 심는 방법은 이벤트 전송 부담을 키운다. 이벤트에는 이벤트를 발생시킨 데이터의 종류(상품, | ||
===== Single Page Application? | ===== Single Page Application? | ||
* 2020년 현재 대부분의 Front End Framework 이 SPA 기반이다. SPA를 사용하지 말라는 것은 유효하지 않다. | * 2020년 현재 대부분의 Front End Framework 이 SPA 기반이다. SPA를 사용하지 말라는 것은 유효하지 않다. | ||
줄 420: | 줄 433: | ||
* Sprint 를 1주 단위 정도로 잘게 쪼개는 게 좋다. 목표를 명확히 가시화 한다. | * Sprint 를 1주 단위 정도로 잘게 쪼개는 게 좋다. 목표를 명확히 가시화 한다. | ||
* 스프린트당 통합 테스트를 목표로 정하는게 좋다. 허접해도 통합해서 뭔가를 보는게 좋다. | * 스프린트당 통합 테스트를 목표로 정하는게 좋다. 허접해도 통합해서 뭔가를 보는게 좋다. | ||
+ | |||
+ | ===== 외부 연결 정보와 인증서 관리 ===== | ||
+ | * 외부 API 연동 Key 혹은 HTTPS 인증서 등의 목록을 면밀히 관리해야 한다. | ||
+ | * 특히 인증서 자체의 숫자가 늘어나서 관리가 안 될 수 있기 때문에 소스코드에 API Key 등을 두지 말고, 특정 저장소에서 일관되게 사용할 수 있게 해야 한다. | ||
+ | * HTTPS SSL 인증서의 경우 만료일 관리 스케줄링을 하고, 관리 주체를 명확히 가져가도록 한다. | ||
+ | |||
===== 신규 개발 조직 구축시 먼저 할 일 ===== | ===== 신규 개발 조직 구축시 먼저 할 일 ===== | ||
줄 437: | 줄 456: | ||
* [[: | * [[: | ||
* [[java: | * [[java: | ||
+ | * 개발 시간도 아니면서 개발 시간이 부족하게 만드는 요소들(배포 복잡도로 인한 배포 시간이 너무 오래걸린다던가, | ||
* 기술 선언서를 만든다. | * 기술 선언서를 만든다. | ||
* 장애대응 방법과 태도(비난하지 말고 함께 문제를 해결한다던가) | * 장애대응 방법과 태도(비난하지 말고 함께 문제를 해결한다던가) | ||
줄 449: | 줄 469: | ||
* Test 방법 | * Test 방법 | ||
* 그리고 지속적인 회고로 기술 선언서를 개선한다. | * 그리고 지속적인 회고로 기술 선언서를 개선한다. | ||
+ | |||
+ | |||
===== 지속적인 업그레이드 ===== | ===== 지속적인 업그레이드 ===== |