사용자 도구

사이트 도구


web:신규서비스

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
다음 판
이전 판
web:신규서비스 [2023/08/30 17:28]
kwon37xi
web:신규서비스 [2024/03/08 11:26] (현재)
kwon37xi [시간]
줄 277: 줄 277:
   * **분산 캐시는 value type 이 배포중간에 바뀌는 경우 심각한 오류에 직면할 수 있다.** 이게 중요한 곳에는 분산 캐시를 사용하면 안 된다.   * **분산 캐시는 value type 이 배포중간에 바뀌는 경우 심각한 오류에 직면할 수 있다.** 이게 중요한 곳에는 분산 캐시를 사용하면 안 된다.
   * 분산 캐시의 캐시된 value 에 대한 type 은 DB schema 처럼 매우 중요하게 다뤄야한다. 변경된 캐시 value 타입이 배포되는 동안 에러가 발생하는 현상이 잦기 때문에, 호환성을 항상 염두에 둬야한다.   * 분산 캐시의 캐시된 value 에 대한 type 은 DB schema 처럼 매우 중요하게 다뤄야한다. 변경된 캐시 value 타입이 배포되는 동안 에러가 발생하는 현상이 잦기 때문에, 호환성을 항상 염두에 둬야한다.
-  * [[java:serialization|Java Serialization 직렬화]]으로 분산 캐시 데이터를 저장할 경우 필드 변경, package 변경등의 문제가 지속적으로 발생한다.+  * [[java:serialization|Java Serialization 직렬화]]으로 분산 캐시 데이터를 저장할 경우 필드 변경, package 변경등의 문제가 지속적으로 발생한다. 또한 런타임 바이트코드를 변환하는 도구가 주입돼도 직렬화에 변경이 생겨서 문제가 되기도 했다.
   * 가급적 JSON 등의 plain 한 방식을 취하고, 필드나 타입이 변경되면 단순히 null 로 처리하고 에러는 안내는 방식을 취해야 한다.   * 가급적 JSON 등의 plain 한 방식을 취하고, 필드나 타입이 변경되면 단순히 null 로 처리하고 에러는 안내는 방식을 취해야 한다.
     * 하지만 이 경우에도 문제가 있는데, 필드를 null 처리 할 경우 해당 필드를 꼭 사용해야하는 코드가 배포되는 중간에 있을 때 심각한 문제가 발생할 수 있다. 따라서 이 경우에는 cache key 자체를 변경해야 한다.     * 하지만 이 경우에도 문제가 있는데, 필드를 null 처리 할 경우 해당 필드를 꼭 사용해야하는 코드가 배포되는 중간에 있을 때 심각한 문제가 발생할 수 있다. 따라서 이 경우에는 cache key 자체를 변경해야 한다.
줄 333: 줄 333:
     * 서비스 런칭 시점부터 하는게 좋다. 나중에 붙이다가 그동안 매우 많이 사용되던 막아서는 안되는 것을 막는 일이 일어나기 쉽다.     * 서비스 런칭 시점부터 하는게 좋다. 나중에 붙이다가 그동안 매우 많이 사용되던 막아서는 안되는 것을 막는 일이 일어나기 쉽다.
     * 이 때 IP 차단시 동일 NAT 를 사용하는 사용자가 많이 존재할 수 있음을 염두에 두어야 한다. 명백하게 해당 NAT IP 를 사용하는 자가 공격일 경우에만 차단한다.     * 이 때 IP 차단시 동일 NAT 를 사용하는 사용자가 많이 존재할 수 있음을 염두에 두어야 한다. 명백하게 해당 NAT IP 를 사용하는 자가 공격일 경우에만 차단한다.
 +  * 규모가 큰 시스템이고 보편적이지 않은 흐름에서 데이터 소유주 본인이 아닌 사용자에 의해 admin 등을 통한 데이터 조작 행위가 일어날 경우 이를 트래킹하는 저장소 시스템을 만들고, 각 admin 혹은 데이터 변경을 일으키는 시스템에서 해당 시스템으로 행위자와 행위 관련 데이터(뭐를 어떻게 언제 변경시켰는지)를 전송하고 트래킹할 수 있는 시스템을 구축하는 것이 좋다.
 ===== 서버 운영 ===== ===== 서버 운영 =====
   * 절대로 여러 사람이 공유하는 공용 계정으로 서버를 관리하지 말라(AWS 등 포함). 이는 치명적인 보안 사고로 이어진다.   * 절대로 여러 사람이 공유하는 공용 계정으로 서버를 관리하지 말라(AWS 등 포함). 이는 치명적인 보안 사고로 이어진다.
줄 435: 줄 436:
     * [[https://jsonpatch.com/|JSON Patch]] 혹은 [[https://www.rfc-editor.org/rfc/rfc7386|JSON Merge Patch]] 를 사용하는게 낫다.     * [[https://jsonpatch.com/|JSON Patch]] 혹은 [[https://www.rfc-editor.org/rfc/rfc7386|JSON Merge Patch]] 를 사용하는게 낫다.
     * 필드 변경을 반영한 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 호출에 사용만 하고 실제 이를 가지고 비즈니스 로직을 처리하지 않는 경우는 ''String'' 으로 받아서 불필요하게 의존성이 안생기게 하는게 낫다.
 ===== MQ 등을 통한 비동기 처리 / event driven ===== ===== MQ 등을 통한 비동기 처리 / event driven =====
   * 비동기 처리는 반응 속도를 높이고 전송 신뢰도를 높여주는 등 좋은 점이 있지만 단점들도 많으므로 확실히 이해해야 한다.   * 비동기 처리는 반응 속도를 높이고 전송 신뢰도를 높여주는 등 좋은 점이 있지만 단점들도 많으므로 확실히 이해해야 한다.
줄 441: 줄 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 커넥션 쓰레드나, 애플리케이션 쓰레드를 점유해버릴 경우 API가 원인 모르게 느려지고 작동을 안하는 현상이 발생한다. 이 둘을 분리해서 장애시 원인이 MQ Consumer 인지, 특정 API 호출인지를 명확히 구분할 수 있다.   * MQ Consumer 서버를 API 서버와 분리한다. MQ Consumer 가 DB 커넥션 쓰레드나, 애플리케이션 쓰레드를 점유해버릴 경우 API가 원인 모르게 느려지고 작동을 안하는 현상이 발생한다. 이 둘을 분리해서 장애시 원인이 MQ Consumer 인지, 특정 API 호출인지를 명확히 구분할 수 있다.
-  * Event body 에 모든 데이터를 심는 방법은 이벤트 전송 부담을 키운다. 이벤트에는 이벤트를 발생시킨 데이터의 종류(상품,사용자,..)와 해당 Primary Key, 그리고 이벤트 발생 요인(생성,수정,삭제)만 전달하고, 실제 데이터는 이벤트를 받은 시스템에서 API 등으로 호출하여 확인하게 한다. 그리고 상황에 따라 API로 봐야하는 데이터가 너무 크다면 그 중에 어떤 데이터가 변경됐는지(상품중에서 가격이 변경 됐는지 여부?)를 함께 담아 보낸다(zero payload). 
-  * zero payload 상황에서 consumer는 producer 에게 실제 데이터를 API로 요청해야하는데, 이 때 DB replication이 돼 있을 경우 replica 에 데이터 복제 지연이 발생해서 못 읽는 경우가 있을 수 있다. MQ의 전송지연 기능으로 3~5초 정도 지연해서 메시지를 받게 해주면 이 문제가 줄어든다. 
-  * zero payload가 이벤트를 받는측에서 데이터를 조회해야해서 producer 측에 DB부담을 가중시킬 가능성도 있다. 혹은 어떤 상황에서는 이벤트 발행 그 시점의 데이터가 필요할 때도 있다. 따라서 데이터를 넣어서 전송해야 할 일이 있다면 그 정책을 producer가 payload 생성으로 인해 쓰레드가 길어지거나 너무 많은 데이터 조회로  부담되지 않게 잘 정의해줘야 한다. 
   * 모니터링   * 모니터링
     * 메시지 발생 실패를 모니터링 / 알람 해야 한다.     * 메시지 발생 실패를 모니터링 / 알람 해야 한다.
     * 발행은 성공했으나 consumer 처리 적체가 발생할 수 있으므로 Queue 에 대기중인 메시지가 너무 많을 경우에 대해서도 모니터링 알람해야한다.     * 발행은 성공했으나 consumer 처리 적체가 발생할 수 있으므로 Queue 에 대기중인 메시지가 너무 많을 경우에 대해서도 모니터링 알람해야한다.
 +
 +
 +===== Event PayLoad 정책 =====
 +==== ᅟZero Payload ====
 +  * Consumer 측에서 이벤트에 대해서 Event Source 데이터를 최신화하기만 하면 되는 경우에는 zero payload 가 유리해 보임.
 +  * 즉, 데이터의 최종 상태 동기화만 하면 되는 경우(Eventually Consistency 보장)다.
 +  * 예시) 업체 정보, 고객 정보 등의 변경을 consumer 측에서 최신 데이터로 계속 갱신만 하면 되는 상황
 +  * Event body 에 모든 데이터를 심는 방법은 이벤트 전송 부담을 키운다. 이벤트에는 이벤트를 발생시킨 데이터의 종류(상품,사용자,..)와 해당 Primary Key, 그리고 이벤트 발생 요인(생성,수정,삭제)만 전달하고, 실제 데이터는 이벤트를 받은 시스템에서 API 등으로 호출하여 확인하게 한다. 그리고 상황에 따라 API로 봐야하는 데이터가 너무 크다면 그 중에 어떤 데이터가 변경됐는지(상품중에서 가격이 변경 됐는지 여부?)를 함께 담아 보낸다(zero payload).
 +  * zero payload 상황에서 consumer는 producer 에게 실제 데이터를 API로 요청해야하는데, 이 때 DB replication이 돼 있을 경우 replica 에 데이터 복제 지연이 발생해서 못 읽는 경우가 있을 수 있다. MQ의 전송지연 기능으로 3~5초 정도 지연해서 메시지를 받게 해주면 이 문제가 줄어든다.
 +  * 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를 사용하지 말라는 것은 유효하지 않다.
줄 465: 줄 487:
     * 누군가가 실수로 batch job 실행시간을 잘못된 시간으로 옮겨버리는 행위 등을 감지할 수 있어야 한다.     * 누군가가 실수로 batch job 실행시간을 잘못된 시간으로 옮겨버리는 행위 등을 감지할 수 있어야 한다.
   * 배치 실행 실간을 가정으로 만들지 말 것. 예를들어 앞선 배치가 1시간 걸릴테니 그에 관한 후속 배치는 2시간 이후 실행되게 했는데, 앞선 배치가 2시간이 넘게 걸리는 등의 현상 발생. Job 들간 의존 관계가 있을 경우 명확하게 의존 관계를 코드나 스케줄로 표현할 것.   * 배치 실행 실간을 가정으로 만들지 말 것. 예를들어 앞선 배치가 1시간 걸릴테니 그에 관한 후속 배치는 2시간 이후 실행되게 했는데, 앞선 배치가 2시간이 넘게 걸리는 등의 현상 발생. Job 들간 의존 관계가 있을 경우 명확하게 의존 관계를 코드나 스케줄로 표현할 것.
-===== 기타 =====+===== 날짜 / 시간 ===== 
 +  * **한 달(28일, 29일, 30일, 31일)**, **1년(365일, 366일)** 이라는 용어는 매우 주의가 필요하다. 상황에 따라 실질 날수가 달라지기 때문이다. 
 +    * 가급적 의사 소통을 월/년 으로 하지말고 **날짜수**로 해야한다. 
 +    * 1 주는 7일 고정이라 무관. 
 +    * 정말로 의도가 월/년이 맞는 경우에는 항상 로직을 작성할때 ''+- month'', ''+- year'' 로직으로 짜야지 ''+- 30'', ''+-365'' 이런식으로 작성하면 안된다.
   * 날짜 <-> 문자열간 변환이 많이 필요한데, 처음부터 포맷을 결정하고 간다.    * 날짜 <-> 문자열간 변환이 많이 필요한데, 처음부터 포맷을 결정하고 간다. 
     * 날짜시간, 날짜, 시간 세가지 종류가 필요하다.     * 날짜시간, 날짜, 시간 세가지 종류가 필요하다.
     * 가급적, 밀리초까지 포함한다. 초까지만 지정하면 추후에 밀리초를 사용할 일이 생겼을 때 매우 당황스러워질 수 있다.     * 가급적, 밀리초까지 포함한다. 초까지만 지정하면 추후에 밀리초를 사용할 일이 생겼을 때 매우 당황스러워질 수 있다.
 +  * 시각(시분초) 만으로 기간을 설정해야하는 경우가 있다면 시작과 끝을 시각으로 만들면 큰 혼란이 온다.
 +    * ''10:00~10:00'', ''10:00~03:00'' 를 어떻게 해석해야할까? (다음날 10시, 다음날 3시 등의 표현)
 +    * 이렇게 되면 이 범위를 다루는 코드가 시작시각보다 종료시각이 더 큰 값인 경우는 당일 처리, 더 작은 값이나 같은 값인 경우는 익일 처리 로직을 짜야한다.
 +    * 더 심각한 것은 시작은 ''10:00~11:00'' 인데 데이터 입력자의 의도가 **다음날** ''11:00'' 인 경우가 발생할 수도 있다.
 +    * 시각기준의 범위를 지정할 때는 **시작 시각 + 유지 시간 형태로 하는게 나아보임.**
 +
 +===== 기타 =====
   * 네트워크 연결 되는 설정의 경우 **Connection Timeout과 Read Timeout** 두 가지가 존재한다. 항상 이 둘을 적절히 설정해야 한다.   * 네트워크 연결 되는 설정의 경우 **Connection Timeout과 Read Timeout** 두 가지가 존재한다. 항상 이 둘을 적절히 설정해야 한다.
   * UI 에 페이징을 사용하지 않는 것이 좋다. 페이징은 전체 결과 갯수를 필요로 하는데 이로 인해 DB 부하가 매우 크다. [[search:elasticsearch|Elastic Search]] 같은 검색엔진 기반이라면 써도 된다. 하지만 DB 기반으로 하는 대부분의 애플리케이션은 페이징 UI 말고 offset/limit 방식을 사용해서 페이징을 구현한다. 안그러면 서비스가 성장했을 때 UI가 사용이 불가능할 정도로 느려진다.   * UI 에 페이징을 사용하지 않는 것이 좋다. 페이징은 전체 결과 갯수를 필요로 하는데 이로 인해 DB 부하가 매우 크다. [[search:elasticsearch|Elastic Search]] 같은 검색엔진 기반이라면 써도 된다. 하지만 DB 기반으로 하는 대부분의 애플리케이션은 페이징 UI 말고 offset/limit 방식을 사용해서 페이징을 구현한다. 안그러면 서비스가 성장했을 때 UI가 사용이 불가능할 정도로 느려진다.
web/신규서비스.1693384103.txt.gz · 마지막으로 수정됨: 2023/08/30 17:28 저자 kwon37xi