문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 다음 판 양쪽 다음 판 | ||
web:신규서비스 [2023/03/29 13:06] kwon37xi |
web:신규서비스 [2024/02/08 09:41] kwon37xi [MQ 등을 통한 비동기 처리 / event driven] |
||
---|---|---|---|
줄 159: | 줄 159: | ||
* 이럴 때는 PK 값을 일정 규칙에 따라 짧은 문자열로 바꿔주는 약한 변환을 해주거나, | * 이럴 때는 PK 값을 일정 규칙에 따라 짧은 문자열로 바꿔주는 약한 변환을 해주거나, | ||
* 아예 PK와 함께 **UUID 같은 완전 특수한 새로운 값을 Unique Index를 걸어서 생성해서 이를 Natual Key 형태로 사용**하면 보안성을 강화할 수 있다. | * 아예 PK와 함께 **UUID 같은 완전 특수한 새로운 값을 Unique Index를 걸어서 생성해서 이를 Natual Key 형태로 사용**하면 보안성을 강화할 수 있다. | ||
+ | * 이는 반대로 말하면 **다른 시스템으로부터 PK로 숫자로 받는다면, | ||
===== 운영체제 OS ===== | ===== 운영체제 OS ===== | ||
줄 189: | 줄 190: | ||
* 중요 테이블의 경우 최종 수정된 내용만 가지고 있고 그에 대해 제약 조건을 모두 지키도록 설계한다. 다만, 변경시마다 **중요 변경사항을 history 테이블을 따로 두어** 남기도록 한다. 그래야 서비스 유지보수시 알 수 없는 오류에 대한 참고 데이터로 삼아 고객의 요구에 대해 올바로 대응 할 수 있다. history는 RDBMS 가 아니라 NoSQL로 남기는 것도 좋다. | * 중요 테이블의 경우 최종 수정된 내용만 가지고 있고 그에 대해 제약 조건을 모두 지키도록 설계한다. 다만, 변경시마다 **중요 변경사항을 history 테이블을 따로 두어** 남기도록 한다. 그래야 서비스 유지보수시 알 수 없는 오류에 대한 참고 데이터로 삼아 고객의 요구에 대해 올바로 대응 할 수 있다. history는 RDBMS 가 아니라 NoSQL로 남기는 것도 좋다. | ||
* **컬럼의 의미를 바꾸지 말 것.** DB의 역사가 오래될 수록 컬럼의 의미를 중간에 바꾸는 경우가 있는데, **컬럼의 의미를 변경하려면 기존 데이터를 모두 마이그레이션 하던지, 새로운 컬럼을 만들어서 새로운 의미를 부여하든지 한다.** 기존 데이터를 그대로 남겨둔 상태로 컬럼의 의미를 바꾸면 매핑되는 객체 구조 설계에도 문제가 생기고 쿼리 결과를 처리하는 모든 구문에 상황에 따른 조건문이 계속 추가되어 개발 부담을 가중시키게 된다. | * **컬럼의 의미를 바꾸지 말 것.** DB의 역사가 오래될 수록 컬럼의 의미를 중간에 바꾸는 경우가 있는데, **컬럼의 의미를 변경하려면 기존 데이터를 모두 마이그레이션 하던지, 새로운 컬럼을 만들어서 새로운 의미를 부여하든지 한다.** 기존 데이터를 그대로 남겨둔 상태로 컬럼의 의미를 바꾸면 매핑되는 객체 구조 설계에도 문제가 생기고 쿼리 결과를 처리하는 모든 구문에 상황에 따른 조건문이 계속 추가되어 개발 부담을 가중시키게 된다. | ||
- | * DB 자체의 타입 enum 을 사용하지 말라. 또한 프로그래밍 언어 enum 을 사용할 때 절대로 순서 숫자값(ordinal)로 저장하면 안된다. 이 둘은 모두 enum 항목들의 순서 변경이 발생하는 순간 엄청난 마이그레이션을 수행해야한다. 그에 비해 성능 향상은 그리 크지 않아보인다. MySQL의 enum은 겉보기와는 달리 ordinal 로 작동하기 때문에 **enum 의 순서가 변경**되면 단순 alter table로 문제가 해결되지 않고 기존 데이터를 모두 마이그레이션 해야 한다. | + | * DB 자체의 타입 enum 을 사용하지 말라. 또한 프로그래밍 언어 enum 을 사용할 때 절대로 순서 숫자값(ordinal)로 저장하면 안된다. 이 둘은 모두 enum 항목들의 순서 변경이 발생하는 순간 엄청난 마이그레이션을 수행해야한다. 그에 비해 성능 향상은 그리 크지 않아보인다. |
* 과도한 동적 쿼리를 생성하지 말라. - 특히 iBatis/ | * 과도한 동적 쿼리를 생성하지 말라. - 특히 iBatis/ | ||
* 상태에 따라 WHERE 절이 나타났다 사라졌다하는 식의 동적 쿼리는 자칫 실수하면 모든 조건이 없어져서 엄청난 부하를 일으키는 SELECT 쿼리나 모든 데이터를 삭제하는 DELETE 문이 될 수 있다. | * 상태에 따라 WHERE 절이 나타났다 사라졌다하는 식의 동적 쿼리는 자칫 실수하면 모든 조건이 없어져서 엄청난 부하를 일으키는 SELECT 쿼리나 모든 데이터를 삭제하는 DELETE 문이 될 수 있다. | ||
줄 196: | 줄 197: | ||
* Backup/Fail Over 전략을 수립해둔다. : DB 생성 초기 부터 백업/ | * Backup/Fail Over 전략을 수립해둔다. : DB 생성 초기 부터 백업/ | ||
* 페이징으로 데이터를 불한/ | * 페이징으로 데이터를 불한/ | ||
- | * '' | + | * '' |
+ | * 또한 '' | ||
* 처리처럼 데이터를 분할해서 가져갈 경우 항상 '' | * 처리처럼 데이터를 분할해서 가져갈 경우 항상 '' | ||
* 대체로 **PK asc**를 하는게 DB에서 가장 성능이 좋다. [[https:// | * 대체로 **PK asc**를 하는게 DB에서 가장 성능이 좋다. [[https:// | ||
줄 202: | 줄 204: | ||
* offset/ | * offset/ | ||
* 사용자 ID 같은 경우에는 소문자로통일해서 받는것이 좋다. 대문자로 입력해도 소문자로 변환한다. 사용자는 자신이 대소문자를 어떻게 입력했는지 혼동하는 경우가 많다. 단 email 같은 외부 값을 받는 경우는 있는 그대로 넣어야 한다. | * 사용자 ID 같은 경우에는 소문자로통일해서 받는것이 좋다. 대문자로 입력해도 소문자로 변환한다. 사용자는 자신이 대소문자를 어떻게 입력했는지 혼동하는 경우가 많다. 단 email 같은 외부 값을 받는 경우는 있는 그대로 넣어야 한다. | ||
- | * DB Connection Pool 의 **connectionTimeout** 값(**커넥션풀에서 커넥션을 가져오는데 걸리는 최대시간**)을 2~3초 정도로 짧게 가져간다. 또한 JDBC 사용시, **connectionTimeout**(**실제 DB에 접속하는데 걸리는 시간**)도 1초 이내로 짧게 가져가야한다. 그래야 DB 서버 Fail Over 에 빠르게 반응하게 된다. | + | * DB Connection Pool 의 **connectionTimeout** 값(**커넥션풀에서 커넥션을 가져오는데 걸리는 최대시간**)을 2~3초 정도로 짧게 가져간다. 또한 JDBC 사용시, **connectionTimeout**(**실제 DB에 접속하는데 걸리는 시간**)도 1초 이내로 짧게 가져가야한다. 그래야 DB 서버 Fail Over 에 빠르게 반응하게 된다. |
* Write 트랜잭션(Transaction)은 최소로 유지해야한다. 만약 write 트랜잭션 내에서 다른 데이터의 과도한 조회 등이 발생한다면 write 를 위한 선행 데이터 조회와 write 그 자체의 트랜잭션을 따로 분할해서 | * Write 트랜잭션(Transaction)은 최소로 유지해야한다. 만약 write 트랜잭션 내에서 다른 데이터의 과도한 조회 등이 발생한다면 write 를 위한 선행 데이터 조회와 write 그 자체의 트랜잭션을 따로 분할해서 | ||
* 위의 상황과 유사하지만 비록 순수 Read라 하더라도 트랜잭션을 짧게 가져가야 한다. Long Transaction을 일으키는 큰 문제중의 하나가 DB 트랜잭션 내부에서 다른 API 호출하는 것이다. 외부 API 호출등 | * 위의 상황과 유사하지만 비록 순수 Read라 하더라도 트랜잭션을 짧게 가져가야 한다. Long Transaction을 일으키는 큰 문제중의 하나가 DB 트랜잭션 내부에서 다른 API 호출하는 것이다. 외부 API 호출등 | ||
줄 210: | 줄 212: | ||
* PK 기반으로 해야 실수 했을 때 어느 PK의 데이터를 되돌려야할지 확인이 쉽고, | * PK 기반으로 해야 실수 했을 때 어느 PK의 데이터를 되돌려야할지 확인이 쉽고, | ||
* 처음에 쿼리를 짜던 시점과 실제 실행 시점 사이에 뭔가 변경된 데이터가 있을 때 그걸 알아채기도 쉬움. | * 처음에 쿼리를 짜던 시점과 실제 실행 시점 사이에 뭔가 변경된 데이터가 있을 때 그걸 알아채기도 쉬움. | ||
+ | * 또한 롤백시 롤백이 매우 오래걸릴 수도 있다. 한 방쿼리는 **지양**한다. | ||
* 여러건 조회시 항상 정렬 조건(order by)를 지정해야한다. 정렬을 넣지 않고 어도 PK로 정령돼 있는 경우들이 있는데 이걸 믿고 있다가 나중에 순서가 예상과 다르게 나와서 장애가 나는 경우가 있다(특히 non-clustered index 조회일경우). 가급적 PK기준으로 지정한다. | * 여러건 조회시 항상 정렬 조건(order by)를 지정해야한다. 정렬을 넣지 않고 어도 PK로 정령돼 있는 경우들이 있는데 이걸 믿고 있다가 나중에 순서가 예상과 다르게 나와서 장애가 나는 경우가 있다(특히 non-clustered index 조회일경우). 가급적 PK기준으로 지정한다. | ||
+ | * 유사하게 Stream의 '' | ||
* 기본적으로 Slow Query 모니터링을 걸고 알람을 한다. slow query 시간에 따라 알람 레벨을 주는 것도 좋을 것 같다. | * 기본적으로 Slow Query 모니터링을 걸고 알람을 한다. slow query 시간에 따라 알람 레벨을 주는 것도 좋을 것 같다. | ||
* '' | * '' | ||
줄 219: | 줄 223: | ||
* 정렬이 필요한 경우가 있다면 이 경우에는 할 수 없이 애플리케이션 코드에서 정렬한다. | * 정렬이 필요한 경우가 있다면 이 경우에는 할 수 없이 애플리케이션 코드에서 정렬한다. | ||
* **즉 모든 데이터 조회는 상방이 무제한 커질 수 없게 제한을 걸어야한다. 그래야 서비스의 증가에 따라 장애가 나는 일이 없어진다.** | * **즉 모든 데이터 조회는 상방이 무제한 커질 수 없게 제한을 걸어야한다. 그래야 서비스의 증가에 따라 장애가 나는 일이 없어진다.** | ||
+ | * Soft Delete(삭제 여부를 나타내는 컬럼을 두고 마킹만 하기) / Hard Delete (실제로 삭제) | ||
+ | * Hard Delete 선호한다. | ||
+ | * unique index 등을 걸기도 편하다. | ||
+ | * 관건은 삭제된 데이터 히스토리를 남기는 것인데, Hard Delete 를 하고 history table 을 두는게 차라리 나아 보인다. [[java: | ||
+ | * Soft Delete 는 삭제 여부 컬럼을 '' | ||
+ | |||
===== 사용자에게 전달하는 메시징 솔루션 ===== | ===== 사용자에게 전달하는 메시징 솔루션 ===== | ||
* Email, SMS, Mobile Push 등의 Messaging은 초반에는 적을 수 있으나 서비스의 증가에 따라 시스템의 부하 요소가 될 수 있다. | * Email, SMS, Mobile Push 등의 Messaging은 초반에는 적을 수 있으나 서비스의 증가에 따라 시스템의 부하 요소가 될 수 있다. | ||
줄 267: | 줄 277: | ||
* **분산 캐시는 value type 이 배포중간에 바뀌는 경우 심각한 오류에 직면할 수 있다.** 이게 중요한 곳에는 분산 캐시를 사용하면 안 된다. | * **분산 캐시는 value type 이 배포중간에 바뀌는 경우 심각한 오류에 직면할 수 있다.** 이게 중요한 곳에는 분산 캐시를 사용하면 안 된다. | ||
* 분산 캐시의 캐시된 value 에 대한 type 은 DB schema 처럼 매우 중요하게 다뤄야한다. 변경된 캐시 value 타입이 배포되는 동안 에러가 발생하는 현상이 잦기 때문에, 호환성을 항상 염두에 둬야한다. | * 분산 캐시의 캐시된 value 에 대한 type 은 DB schema 처럼 매우 중요하게 다뤄야한다. 변경된 캐시 value 타입이 배포되는 동안 에러가 발생하는 현상이 잦기 때문에, 호환성을 항상 염두에 둬야한다. | ||
- | * [[java: | + | * [[java: |
* 가급적 JSON 등의 plain 한 방식을 취하고, 필드나 타입이 변경되면 단순히 null 로 처리하고 에러는 안내는 방식을 취해야 한다. | * 가급적 JSON 등의 plain 한 방식을 취하고, 필드나 타입이 변경되면 단순히 null 로 처리하고 에러는 안내는 방식을 취해야 한다. | ||
* 하지만 이 경우에도 문제가 있는데, 필드를 null 처리 할 경우 해당 필드를 꼭 사용해야하는 코드가 배포되는 중간에 있을 때 심각한 문제가 발생할 수 있다. 따라서 이 경우에는 cache key 자체를 변경해야 한다. | * 하지만 이 경우에도 문제가 있는데, 필드를 null 처리 할 경우 해당 필드를 꼭 사용해야하는 코드가 배포되는 중간에 있을 때 심각한 문제가 발생할 수 있다. 따라서 이 경우에는 cache key 자체를 변경해야 한다. | ||
줄 297: | 줄 307: | ||
* Jade/ | * Jade/ | ||
- | ===== 데이터와 HTML ===== | + | ===== 데이터와 |
* 데이터 저장소는 항상 원천 데이터포맷을 명확히 하고 해당 포맷으로만 저장한다. | * 데이터 저장소는 항상 원천 데이터포맷을 명확히 하고 해당 포맷으로만 저장한다. | ||
* 원천 데이터 포맷은 Text 라면 데이터 저장소에는 그냥 텍스트로 저장해야 한다. 이를 HTML 로 escape 해서 저장하지 말아야 한다. | * 원천 데이터 포맷은 Text 라면 데이터 저장소에는 그냥 텍스트로 저장해야 한다. 이를 HTML 로 escape 해서 저장하지 말아야 한다. | ||
줄 305: | 줄 315: | ||
* 이로 인해 가끔씩 앱이나 일부 웹 애플리케이션에서 ''& | * 이로 인해 가끔씩 앱이나 일부 웹 애플리케이션에서 ''& | ||
* HTML escape 의 책임은 데이터 저장소단이 아닌 View 단에서 해야한다. | * HTML escape 의 책임은 데이터 저장소단이 아닌 View 단에서 해야한다. | ||
+ | * **즉, 데이터는 그 데이터의 포맷에 적합하게 저장돼야 하며 view 에 의존적이면 안된다. 데이터 저장은 view 에 대해 독립적이어야 한다.** | ||
===== 보안 ===== | ===== 보안 ===== | ||
* [[https:// | * [[https:// | ||
줄 321: | 줄 332: | ||
* DDoS 공격 방어를 위해 WAF(Web Application Firewall, 웹방화벽) 설정을 해야한다. | * DDoS 공격 방어를 위해 WAF(Web Application Firewall, 웹방화벽) 설정을 해야한다. | ||
* 서비스 런칭 시점부터 하는게 좋다. 나중에 붙이다가 그동안 매우 많이 사용되던 막아서는 안되는 것을 막는 일이 일어나기 쉽다. | * 서비스 런칭 시점부터 하는게 좋다. 나중에 붙이다가 그동안 매우 많이 사용되던 막아서는 안되는 것을 막는 일이 일어나기 쉽다. | ||
+ | * 이 때 IP 차단시 동일 NAT 를 사용하는 사용자가 많이 존재할 수 있음을 염두에 두어야 한다. 명백하게 해당 NAT IP 를 사용하는 자가 공격일 경우에만 차단한다. | ||
+ | * 규모가 큰 시스템이고 보편적이지 않은 흐름에서 데이터 소유주 본인이 아닌 사용자에 의해 admin 등을 통한 데이터 조작 행위가 일어날 경우 이를 트래킹하는 저장소 시스템을 만들고, 각 admin 혹은 데이터 변경을 일으키는 시스템에서 해당 시스템으로 행위자와 행위 관련 데이터(뭐를 어떻게 언제 변경시켰는지)를 전송하고 트래킹할 수 있는 시스템을 구축하는 것이 좋다. | ||
===== 서버 운영 ===== | ===== 서버 운영 ===== | ||
* 절대로 여러 사람이 공유하는 공용 계정으로 서버를 관리하지 말라(AWS 등 포함). 이는 치명적인 보안 사고로 이어진다. | * 절대로 여러 사람이 공유하는 공용 계정으로 서버를 관리하지 말라(AWS 등 포함). 이는 치명적인 보안 사고로 이어진다. | ||
줄 345: | 줄 358: | ||
* 특정 서버에 접속해서 [[java: | * 특정 서버에 접속해서 [[java: | ||
* [[springframework: | * [[springframework: | ||
+ | * 모든 팀원은 주기적으로 장애상황에 대한 훈련을 해야하고 장애시 곧바로 모니터링 시스템을 활용할 수 있게, 각 서버에 접속하여 상황파악(dump 등)을 할 수 있게 익숙한 상태를 유지해야 한다. | ||
+ | * 반복적일 알람에 대해서 모니터링 알람, On Call (Opsgenie 등의 강력한 전화 알람기능)등이 갖춰져 있고, 작동여부 테스트도 돼 있어야 한다. | ||
+ | * 주문 지표 처럼 중요 비즈니스 지표가 전날 혹은 전주 동일요일 등을 기준으로 알람이 지정돼 있어야 한다. 비록 에러가 안 발생한 상황이더라도 지표가 급격히 떨어졌다면 문제 소지가 있는 것이다. | ||
===== Logging ===== | ===== Logging ===== | ||
* [[: | * [[: | ||
줄 420: | 줄 436: | ||
* [[https:// | * [[https:// | ||
* 필드 변경을 반영한 UI와 Presentation 계층 API가 동시 배포된다면 Presentation 계층에서는 괜찮을 수 있다. | * 필드 변경을 반영한 UI와 Presentation 계층 API가 동시 배포된다면 Presentation 계층에서는 괜찮을 수 있다. | ||
+ | * enum 에 대해 주의가 필요하다. | ||
+ | * Java Enum 으로 API 요청을 받는데, 해당 Enum 이 외부에서 관리되는 것이라면 배포 타이밍에 따라 Enum 값 갱신이 안 된 상태일 수 있다. | ||
+ | * Enum 공급자(변경자) 측은, enum 추가시 사용처를 모두 확인해서 공지해주고 배포 타이밍을 다른 팀에 모두 Enum 을 추가한 뒤로 맞춰줘야 한다. | ||
+ | * Enum 소비자측은 | ||
+ | * Enum 으로 뭔가 작업이 필요할 때는 해당 타입도 Enum 으로 하여 Enum 이 올바로 추가 안됐을 때 차라리 에러를 내는게 나을 수 있다. | ||
+ | * 혹은 String 으로 받되 해당 시스템이 파악하고 있는 Enum 인지 여부를 검사하고 정확한 에러를 내게 처리하는게 나을 수도 있다. | ||
+ | * enum 값을 단지 DB에 저장하거나 다른 API 호출에 사용만 하고 실제 이를 가지고 비즈니스 로직을 처리하지 않는 경우는 '' | ||
===== MQ 등을 통한 비동기 처리 / event driven ===== | ===== MQ 등을 통한 비동기 처리 / event driven ===== | ||
* 비동기 처리는 반응 속도를 높이고 전송 신뢰도를 높여주는 등 좋은 점이 있지만 단점들도 많으므로 확실히 이해해야 한다. | * 비동기 처리는 반응 속도를 높이고 전송 신뢰도를 높여주는 등 좋은 점이 있지만 단점들도 많으므로 확실히 이해해야 한다. | ||
줄 426: | 줄 449: | ||
* **비동기 타이밍 문제도 심각하다.** 이 경우 비동기를 사용하면 안되는데 비동기를 사용한 경우일 수 있다. 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 커넥션 쓰레드나, | ||
+ | * 모니터링 | ||
+ | * 메시지 발생 실패를 모니터링 / 알람 해야 한다. | ||
+ | * 발행은 성공했으나 consumer 처리 적체가 발생할 수 있으므로 Queue 에 대기중인 메시지가 너무 많을 경우에 대해서도 모니터링 알람해야한다. | ||
+ | |||
+ | |||
+ | ===== Event PayLoad 정책 ===== | ||
+ | ==== ᅟZero Payload ==== | ||
+ | * Consumer 측에서 이벤트에 대해서 Event Source 데이터를 최신화하기만 하면 되는 경우에는 zero payload 가 유리해 보임. | ||
+ | * 즉, 데이터의 최종 상태 동기화만 하면 되는 경우(Eventually Consistency 보장)다. | ||
+ | * 예시) 업체 정보, 고객 정보 등의 변경을 consumer 측에서 최신 데이터로 계속 갱신만 하면 되는 상황 | ||
* Event body 에 모든 데이터를 심는 방법은 이벤트 전송 부담을 키운다. 이벤트에는 이벤트를 발생시킨 데이터의 종류(상품, | * Event body 에 모든 데이터를 심는 방법은 이벤트 전송 부담을 키운다. 이벤트에는 이벤트를 발생시킨 데이터의 종류(상품, | ||
* zero payload 상황에서 consumer는 producer 에게 실제 데이터를 API로 요청해야하는데, | * zero payload 상황에서 consumer는 producer 에게 실제 데이터를 API로 요청해야하는데, | ||
* zero payload가 이벤트를 받는측에서 데이터를 조회해야해서 producer 측에 DB부담을 가중시킬 가능성도 있다. 혹은 어떤 상황에서는 이벤트 발행 그 시점의 데이터가 필요할 때도 있다. 따라서 데이터를 넣어서 전송해야 할 일이 있다면 그 정책을 producer가 payload 생성으로 인해 쓰레드가 길어지거나 너무 많은 데이터 조회로 | * zero payload가 이벤트를 받는측에서 데이터를 조회해야해서 producer 측에 DB부담을 가중시킬 가능성도 있다. 혹은 어떤 상황에서는 이벤트 발행 그 시점의 데이터가 필요할 때도 있다. 따라서 데이터를 넣어서 전송해야 할 일이 있다면 그 정책을 producer가 payload 생성으로 인해 쓰레드가 길어지거나 너무 많은 데이터 조회로 | ||
+ | |||
+ | ==== Full Payload ==== | ||
+ | * Consumer 측에서 event source의 상태 변경에 대해서 서로 다른 행위를 해야하는 경우에는 full payload 가 아니면 장애가 날 수 있다. | ||
+ | * 이 경우 **순서 보장도 매우 중요하다.** | ||
+ | * 보통 이 경우는 event source 데이터의 최신화는 목적이 아니다. | ||
+ | * 예시) 주문 정보의 변화 이벤트는 이 이벤트를 받는 측에서 주문 정보를 최신으로 저장하는 것에는 관심이 없고 주문이 생성되면 " | ||
+ | |||
===== Single Page Application? | ===== Single Page Application? | ||
* 2020년 현재 대부분의 Front End Framework 이 SPA 기반이다. SPA를 사용하지 말라는 것은 유효하지 않다. | * 2020년 현재 대부분의 Front End Framework 이 SPA 기반이다. SPA를 사용하지 말라는 것은 유효하지 않다. | ||
줄 478: | 줄 518: | ||
* HTTPS SSL 인증서의 경우 만료일 관리 스케줄링을 하고, 관리 주체를 명확히 가져가도록 한다. | * HTTPS SSL 인증서의 경우 만료일 관리 스케줄링을 하고, 관리 주체를 명확히 가져가도록 한다. | ||
+ | ===== Test 환경 ===== | ||
+ | * DB 테스트나 각종 솔루션에 대해 [[: | ||
+ | * DB 테스트를 실운영 DB가 아닌 embedded DB 로 하지 않는다. 실 DB로 해야 정확하게 테스트된다. embedded 에서 되게 맞추느라 불필요한 작업을 하거나 혹은 embedded 에서 잘 된다고 배포했다가 실DB 에서는 장애나는 경우가 있다. | ||
===== 신규 개발 조직 구축시 먼저 할 일 ===== | ===== 신규 개발 조직 구축시 먼저 할 일 ===== |