<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>시간과 공간 그리고 진실의 방</title>
    <link>https://remoted.tistory.com/</link>
    <description>Remoted's IT LAB &amp;amp; POST DATABASE</description>
    <language>ko</language>
    <pubDate>Thu, 7 May 2026 15:56:22 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>remoted</managingEditor>
    <image>
      <title>시간과 공간 그리고 진실의 방</title>
      <url>https://tistory1.daumcdn.net/tistory/2867029/attach/69fdfb646a074562931d200f71403e1c</url>
      <link>https://remoted.tistory.com</link>
    </image>
    <item>
      <title>일단 노리고 있던 비전덱의 용가리는 드디어 진화</title>
      <link>https://remoted.tistory.com/644</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;퇴근해서 근근히 스트레스 풀이용으로 돌아가는 나름 자동성장 게임인 그놈은 드래곤..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 용가리가 성장기로 진화했다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 유저들은? 분명히 돈을 여러모로 썻겠지만 나는 이걸 모으기 위해 한땀한땀 모아줫다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KNRHz/dJMcagdWYhO/f6HkCJwcHafCn7c8KOIN9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KNRHz/dJMcagdWYhO/f6HkCJwcHafCn7c8KOIN9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KNRHz/dJMcagdWYhO/f6HkCJwcHafCn7c8KOIN9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKNRHz%2FdJMcagdWYhO%2Ff6HkCJwcHafCn7c8KOIN9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;959&quot; height=&quot;536&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저기 중간에 보이는 '비전 중급 진화석' 이 6개가 들어가는데, 모으기 조금 쉬운 팁은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활동은 나름하는데, 길드경매에서 길드경매를 잘 안쓰는 길드를 고르면 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 길드경매에서 내가 사고싶은 물품을 독차지 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신화스킨 조각 3개는 2700 다이아에 이것저것 올라오긴 하는데 그런것들을 죄다 먼저 선점할 수 있다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 약간의 함정 중 하나는, 그런 길드에 들어가면 다른 길드와는 다르게 필드몬스터 사냥도 좀 느릴 것이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것저것 아쉬운 점이 많이 생기게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(그래서 최근에 다른 길드로 넘어왔다지.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진화를 누르면 왼쪽의 귀여운 킹가리가 아래의 킹가리로 변신한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cssjy3/dJMcadVLUq2/VCwMnQBkn13c42izqjWz0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cssjy3/dJMcadVLUq2/VCwMnQBkn13c42izqjWz0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cssjy3/dJMcadVLUq2/VCwMnQBkn13c42izqjWz0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcssjy3%2FdJMcadVLUq2%2FVCwMnQBkn13c42izqjWz0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;533&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중급 엘프드래곤 조각이 48개정도 있었어서 1성은 바로 뚫어줫는데, 이녀석 살펴보면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w1l5u/dJMcacCCvBI/nS5EWRR63Hldh1S6qLK4w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w1l5u/dJMcacCCvBI/nS5EWRR63Hldh1S6qLK4w1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w1l5u/dJMcacCCvBI/nS5EWRR63Hldh1S6qLK4w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw1l5u%2FdJMcacCCvBI%2FnS5EWRR63Hldh1S6qLK4w1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;959&quot; height=&quot;534&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은조각과 중급조각이 이제 동시에 들어간다;; 벌써부터 대 험난한 시대가 예상된다&lt;/p&gt;</description>
      <category>게임/그놈은 드래곤</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/644</guid>
      <comments>https://remoted.tistory.com/644#entry644comment</comments>
      <pubDate>Thu, 2 Apr 2026 13:59:27 +0900</pubDate>
    </item>
    <item>
      <title>[Trouble Shooting] ElasticSearch Mapping Collision II</title>
      <link>https://remoted.tistory.com/643</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;그런데? 인덱스를 밀어넣고 난 이후에도 데이터가 제대로 보이지 않는다는 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흠. 이 부분에 대해서 킹치만 많은 가설을 통해 검증을 시작하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774879270432&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;========================================
ubuntu@ip-172-31-40-155:~$ curl -X GET &quot;http://localhost:9200/_cat/indices?v&quot;
health status index                                        uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   moyamo_3                                     9bPawqGQTseRptxkTTsy-A   5   1    1576206          774      1.3gb          1.3gb
yellow open   net.infobank.moyamo.models.photorecentwriter bYxm8ozGSzOmC8LpV59oWg   5   1          0            0       810b           810b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 예상한 데이터와 다르게 얼마 안들어갔다는 것이다?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 26.7442%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.6047%;&quot;&gt;항목&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;수치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.6047%;&quot;&gt;기존 인덱싱&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;1,576,206&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.6047%;&quot;&gt;누락된 문서&lt;/td&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;14,759,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 계산해볼때 뭔가 이상한 느낌이 스물스물 나서 코드를 조사해봤는데&lt;/p&gt;
&lt;pre id=&quot;code_1774879391777&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SimdaSchedulerApplication.java:122
List&amp;lt;SimplePosting&amp;gt; postings = eventWorkRepositoryCustom.findPostingList(
    Posting.class, sinceId, maxId, 1000  // &amp;larr; 최대 1000개만 조회!
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1000개씩만 드신다는 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이걸 진짜로 9~10시간에 걸려서 삽질을 해야되냐? 댓츠논노&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 무적의 m5.xlarge를 사용하고 있기 때문에 더욱 공격적으로 병렬로 때려넣을 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774879452028&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash
# Elasticsearch 병렬 인덱싱 스크립트
# 8개의 프로세스로 병렬 처리 - m5.xlarge (4 vCPU, 16GB) 최적화
# 예상 소요 시간: 약 1시간

SCHEDULER_URL=&quot;http://localhost:8088&quot;
MAX_COMMENTS=200

# ID 범위를 n등분해서 처리
reindex_range() {
    local START=$1
    local END=$2
    local WORKER=$3
    local BATCH_SIZE=1000
    local CURRENT=$START
    local COUNT=0

    echo &quot;[Worker $WORKER] 시작: $START ~ $END&quot;

    while [ $CURRENT -le $END ]; do
        local BATCH_END=$((CURRENT + BATCH_SIZE - 1))
        if [ $BATCH_END -gt $END ]; then
            BATCH_END=$END
        fi

        curl -s -X POST &quot;$SCHEDULER_URL/indexing?sinceId=$CURRENT&amp;amp;maxId=$BATCH_END&amp;amp;max=$MAX_COMMENTS&quot; --max-time 300 &amp;gt; /dev/null

        CURRENT=$((BATCH_END + 1))
        COUNT=$((COUNT + 1))

        # 500 배치마다 진행상황 출력
        if [ $((COUNT % 500)) -eq 0 ]; then
            echo &quot;[Worker $WORKER] 진행 중... $CURRENT / $END&quot;
        fi
    done

    echo &quot;[Worker $WORKER] 완료!&quot;
}

echo &quot;========================================&quot;
echo &quot;병렬 인덱싱 시작 (8 workers)&quot;
echo &quot;서버: m5.xlarge (4 vCPU, 16GB RAM)&quot;
echo &quot;========================================&quot;

START_TIME=$(date +%s)

# 8개의 범위로 나눠서 병렬 실행 (각 약 2백만 건)
reindex_range 114 2000000 1 &amp;amp;
reindex_range 2000001 4000000 2 &amp;amp;
reindex_range 4000001 6000000 3 &amp;amp;
reindex_range 6000001 8000000 4 &amp;amp;
reindex_range 8000001 10000000 5 &amp;amp;
reindex_range 10000001 12000000 6 &amp;amp;
reindex_range 12000001 14000000 7 &amp;amp;
reindex_range 14000001 16335566 8 &amp;amp;

# 모든 백그라운드 작업 완료 대기
wait

END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
HOURS=$((DURATION / 3600))
MINUTES=$(( (DURATION % 3600) / 60 ))
SECS=$((DURATION % 60))

echo &quot;========================================&quot;
echo &quot;전체 인덱싱 완료!&quot;
echo &quot;소요 시간: ${HOURS}시간 ${MINUTES}분 ${SECS}초&quot;
echo &quot;========================================&quot;

# 최종 문서 수 확인
echo &quot;인덱싱된 문서 수:&quot;
curl -s &quot;http://localhost:9200/moyamo_3/_count&quot;
echo &quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇게 처리한 이후에 CPU는 영 좋지못한 상황으로 가버리는데&lt;/p&gt;
&lt;pre id=&quot;code_1774879529797&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ubuntu@ip-172-31-40-155:~$ chmod +x reindex-parallel.sh 
ubuntu@ip-172-31-40-155:~$ ./reindex-parallel.sh 
========================================
병렬 인덱싱 시작 (8 workers)
서버: m5.xlarge (4 vCPU, 16GB RAM)
========================================
[Worker 1] 시작: 114 ~ 2000000
[Worker 2] 시작: 2000001 ~ 4000000
[Worker 7] 시작: 12000001 ~ 14000000
[Worker 6] 시작: 10000001 ~ 12000000
[Worker 4] 시작: 6000001 ~ 8000000
[Worker 3] 시작: 4000001 ~ 6000000
[Worker 5] 시작: 8000001 ~ 10000000
[Worker 8] 시작: 14000001 ~ 16335566&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQaZT8/dJMcacigWfi/wBp9DdXN67VzXryfGIaow0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQaZT8/dJMcacigWfi/wBp9DdXN67VzXryfGIaow0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQaZT8/dJMcacigWfi/wBp9DdXN67VzXryfGIaow0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQaZT8%2FdJMcacigWfi%2FwBp9DdXN67VzXryfGIaow0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;257&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;괘..괜찮아.. 새벽에 돌리는 Scheduler니까 서비스는 영향받지 않는다굿!&lt;/p&gt;</description>
      <category>Java/Spring Boot JPA</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/643</guid>
      <comments>https://remoted.tistory.com/643#entry643comment</comments>
      <pubDate>Mon, 30 Mar 2026 23:48:55 +0900</pubDate>
    </item>
    <item>
      <title>[Trouble Shooting] ElasticSearch Mapping Collision Issue</title>
      <link>https://remoted.tistory.com/642</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제 상황&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략적으로 서술해보자면 서비스는 일단 502 Bad Gateway가 나면서 내려가고 식은땀이 줄줄 흐르는 상황이 발생한 것인데, 에러 로그만 수집해보면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Information Gathering&lt;/h4&gt;
&lt;pre id=&quot;code_1774875433078&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
[Rest][2026-03-30 03:49:03][ERROR][SpringApplication.java][reportFailure(860)] : Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:339)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1318)
        at net.infobank.moyamo.MoyamoApplication.main(MoyamoApplication.java:16)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
        at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:142)
        at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.&amp;lt;init&amp;gt;(TomcatWebServer.java:104)
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:450)
        at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:199)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:181)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:159)
        ... 17 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 2번째 놈의 로그&lt;/p&gt;
&lt;pre id=&quot;code_1774875475404&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tokenAuthorizationFilter' defined in URL [jar:file:/home/ubuntu/moyamo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/net/infobank/moyamo/configuration/TokenAuthorizationFilter.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authorizationService' defined in URL [jar:file:/home/ubuntu/moyamo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/net/infobank/moyamo/api/service/AuthorizationService.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userSecurityRepository' defined in net.infobank.moyamo.repository.UserSecurityRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot create inner bean '(inner bean)#59221b97' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#59221b97': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
        at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:212)
        at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:175)
        at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:170)
        at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addAdaptableBeans(ServletContextInitializerBeans.java:155)
        at org.springframework.boot.web.servlet.ServletContextInitializerBeans.&amp;lt;init&amp;gt;(ServletContextInitializerBeans.java:87)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:259)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:233)
        at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:53)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5161)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:829)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909)
        at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardService.startInternal(StandardService.java:433)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
        at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486)
        at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123)
        ... 22 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번째 로그와 4번째 로그&lt;/p&gt;
&lt;pre id=&quot;code_1774875498932&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'authorizationService' defined in URL [jar:file:/home/ubuntu/moyamo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/net/infobank/moyamo/api/service/AuthorizationService.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userSecurityRepository' defined in net.infobank.moyamo.repository.UserSecurityRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot create inner bean '(inner bean)#59221b97' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#59221b97': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
        ... 63 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userSecurityRepository' defined in net.infobank.moyamo.repository.UserSecurityRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot create inner bean '(inner bean)#59221b97' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#59221b97': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:389)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:134)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1689)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1434)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
        ... 77 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그로그&lt;/p&gt;
&lt;pre id=&quot;code_1774875531429&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#59221b97': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:693)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:510)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:374)
        ... 91 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
        ... 99 common frames omitted
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:421)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782)
        ... 106 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1774875557946&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Caused by: org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'moyamo_3'
        at org.hibernate.search.elasticsearch.schema.impl.DefaultElasticsearchSchemaMigrator.migrate(DefaultElasticsearchSchemaMigrator.java:77)
        at org.hibernate.search.elasticsearch.impl.ElasticsearchIndexManager.initializeIndex(ElasticsearchIndexManager.java:321)
        at org.hibernate.search.elasticsearch.impl.ElasticsearchIndexManager.initializeIndex(ElasticsearchIndexManager.java:266)
        at org.hibernate.search.elasticsearch.impl.ElasticsearchIndexManager.setSearchFactory(ElasticsearchIndexManager.java:257)
        at org.hibernate.search.indexes.impl.IndexManagerHolder.setActiveSearchIntegrator(IndexManagerHolder.java:150)
        at org.hibernate.search.engine.impl.MutableSearchFactoryState.setActiveSearchIntegrator(MutableSearchFactoryState.java:244)
        at org.hibernate.search.spi.SearchIntegratorBuilder.buildNewSearchFactory(SearchIntegratorBuilder.java:214)
        at org.hibernate.search.spi.SearchIntegratorBuilder.buildSearchIntegrator(SearchIntegratorBuilder.java:128)
        at org.hibernate.search.hcore.impl.HibernateSearchSessionFactoryObserver.boot(HibernateSearchSessionFactoryObserver.java:127)
        at org.hibernate.search.hcore.impl.HibernateSearchSessionFactoryObserver.sessionFactoryCreated(HibernateSearchSessionFactoryObserver.java:94)
        at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:35)
        at org.hibernate.internal.SessionFactoryImpl.&amp;lt;init&amp;gt;(SessionFactoryImpl.java:385)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1259)
        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409)
        ... 110 common frames omitted
        Suppressed: org.hibernate.search.exception.SearchException: HSEARCH400035: Could not update mappings in index 'net.infobank.moyamo.models.photorecentwriter'
                ... 127 common frames omitted
        Caused by: org.hibernate.search.exception.SearchException: HSEARCH400020: Could not create mapping for entity type net.infobank.moyamo.models.PhotoRecentWriter
                at org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaAccessor.putMapping(ElasticsearchSchemaAccessor.java:111)
                at org.hibernate.search.elasticsearch.schema.impl.DefaultElasticsearchSchemaMigrator.migrate(DefaultElasticsearchSchemaMigrator.java:73)
                ... 126 common frames omitted
        Caused by: org.hibernate.search.exception.SearchException: HSEARCH400007: Elasticsearch request failed.
Request: PUT /net.infobank.moyamo.models.photorecentwriter/net.infobank.moyamo.models.PhotoRecentWriter/_mapping with parameters {}
Response: 400 'Bad Request' with body
{
  &quot;error&quot;: {
    &quot;root_cause&quot;: [
      {
        &quot;type&quot;: &quot;illegal_argument_exception&quot;,
        &quot;reason&quot;: &quot;Mapper for [id] conflicts with existing mapping in other types:\n[mapper [id] has different [store] values]&quot;
      }
    ],
    &quot;type&quot;: &quot;illegal_argument_exception&quot;,
    &quot;reason&quot;: &quot;Mapper for [id] conflicts with existing mapping in other types:\n[mapper [id] has different [store] values]&quot;
  },
  &quot;status&quot;: 400
}
                at org.hibernate.search.elasticsearch.work.impl.SimpleElasticsearchWork.handleResult(SimpleElasticsearchWork.java:101)
                at org.hibernate.search.elasticsearch.work.impl.SimpleElasticsearchWork.lambda$execute$3(SimpleElasticsearchWork.java:63)
                at java.util.concurrent.CompletableFuture.uniCompose(CompletableFuture.java:966)
                at java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:940)
                at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488)
                at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1975)
                at org.hibernate.search.elasticsearch.client.impl.DefaultElasticsearchClient$1.onFailure(DefaultElasticsearchClient.java:120)
                at org.elasticsearch.client.RestClient$FailureTrackingResponseListener.onDefinitiveFailure(RestClient.java:857)
                at org.elasticsearch.client.RestClient$1.completed(RestClient.java:560)
                at org.elasticsearch.client.RestClient$1.completed(RestClient.java:537)
                at org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:122)
                at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:181)
                at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:448)
                at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:338)
                at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:265)
                at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
                at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
                at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:114)
                at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
                at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
                at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
                at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
                at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
                at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591)
                at java.lang.Thread.run(Thread.java:750)
        Caused by: org.hibernate.search.exception.SearchException: HSEARCH400090: Elasticsearch response indicates a failure.
                at org.hibernate.search.elasticsearch.work.impl.DefaultElasticsearchRequestSuccessAssessor.checkSuccess(DefaultElasticsearchRequestSuccessAssessor.java:107)
                at org.hibernate.search.elasticsearch.work.impl.DefaultElasticsearchRequestSuccessAssessor.checkSuccess(DefaultElasticsearchRequestSuccessAssessor.java:90)
                at org.hibernate.search.elasticsearch.work.impl.SimpleElasticsearchWork.handleResult(SimpleElasticsearchWork.java:92)
                ... 24 common frames omitted
Caused by: org.hibernate.search.exception.SearchException: HSEARCH400020: Could not create mapping for entity type net.infobank.moyamo.models.AdoptComment
        at org.hibernate.search.elasticsearch.schema.impl.ElasticsearchSchemaAccessor.putMapping(ElasticsearchSchemaAccessor.java:111)
        at org.hibernate.search.elasticsearch.schema.impl.DefaultElasticsearchSchemaMigrator.migrate(DefaultElasticsearchSchemaMigrator.java:73)
        ... 126 common frames omitted
Caused by: org.hibernate.search.exception.SearchException: HSEARCH400007: Elasticsearch request failed.
Request: PUT /moyamo_3/net.infobank.moyamo.models.AdoptComment/_mapping with parameters {}
Response: 400 'Bad Request' with body
{
  &quot;error&quot;: {
    &quot;root_cause&quot;: [
      {
        &quot;type&quot;: &quot;illegal_argument_exception&quot;,
        &quot;reason&quot;: &quot;mapper [relation.posting.title] of different type, current_type [text], merged_type [keyword]&quot;
      }
    ],
    &quot;type&quot;: &quot;illegal_argument_exception&quot;,
    &quot;reason&quot;: &quot;mapper [relation.posting.title] of different type, current_type [text], merged_type [keyword]&quot;
  },
  &quot;status&quot;: 400
}


        at org.hibernate.search.elasticsearch.work.impl.SimpleElasticsearchWork.handleResult(SimpleElasticsearchWork.java:101)
        at org.hibernate.search.elasticsearch.work.impl.SimpleElasticsearchWork.lambda$execute$3(SimpleElasticsearchWork.java:63)
        at java.util.concurrent.CompletableFuture.uniCompose(CompletableFuture.java:966)
        at java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:940)
        at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488)
        at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1975)
        at org.hibernate.search.elasticsearch.client.impl.DefaultElasticsearchClient$1.onFailure(DefaultElasticsearchClient.java:120)
        at org.elasticsearch.client.RestClient$FailureTrackingResponseListener.onDefinitiveFailure(RestClient.java:857)
        at org.elasticsearch.client.RestClient$1.completed(RestClient.java:560)
        at org.elasticsearch.client.RestClient$1.completed(RestClient.java:537)
        at org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:122)
        at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:181)
        at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:448)
        at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:338)
        at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:265)
        at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
        at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
        at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:114)
        at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
        at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
        at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591)
        at java.lang.Thread.run(Thread.java:750)
Caused by: org.hibernate.search.exception.SearchException: HSEARCH400090: Elasticsearch response indicates a failure.
        at org.hibernate.search.elasticsearch.work.impl.DefaultElasticsearchRequestSuccessAssessor.checkSuccess(DefaultElasticsearchRequestSuccessAssessor.java:107)
        at org.hibernate.search.elasticsearch.work.impl.DefaultElasticsearchRequestSuccessAssessor.checkSuccess(DefaultElasticsearchRequestSuccessAssessor.java:90)
        at org.hibernate.search.elasticsearch.work.impl.SimpleElasticsearchWork.handleResult(SimpleElasticsearchWork.java:92)
        ... 24 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대충 상황요약&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1774875753059&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HSEARCH400035: Could not update mappings in index 'moyamo_3'
Mapper for [id] conflicts with existing mapping in other types:
[mapper [id] has different [store] values]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ElasticSearch + Hibernate Search 관련 매핑 충돌 에러였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 왜 문제가 발생했냐면 PhotoRecentWriter 엔티티 id 필드 매핑이 기존 ElasticSearch 인덱스 매핑이랑 충돌한 것인데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쥔짜 식은땀을 흘렷는데 예전 개발자녀석 왜 이렇게 짜놧는지 이해가 안감. 대충 아래의 소스를 살펴보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774875831449&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package net.infobank.moyamo.models;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.NumericField;

import javax.persistence.*;
import java.time.ZonedDateTime;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Indexed
public class PhotoRecentWriter {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @NumericField
    private Long id;

    @NonNull
    @Embedded
    private UserPostingRelation relation;

    private ZonedDateTime createdAt;

    public PhotoRecentWriter(@NonNull UserPostingRelation userPostingRelation, ZonedDateTime createdAt){
        this.relation = userPostingRelation;
        this.createdAt = createdAt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 저기 보이는 Indexed 어노테이션을 사용하면서 생기는 문제였다. 인덱스 이름을 지정하지 않아서 생기는 문제인 것인데, 그래서 기본 클래스명인 net.infobank.moyamo.models.photorecentwriter 으로 별도 인덱스가 만들어졌던거임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;근데? 에러 로그를 보면 다음과 같다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1774875940833&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Could not update mappings in index 'moyamo_3'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;moyamo_3 인덱스 내에서 PhotoRecentWriter의 id 필드가 다른 엔티티 의 id 필드 매핑이랑 store 값이 충돌하기 때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 차이점을 잡고가자면 이런 부분이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;User.java, Posting.java 의 id:@NumericFiled + @SortableField (store 속성 없음 = 기본값 Store.NO)&lt;/li&gt;
&lt;li&gt;PhotoRecentWriter.java의 id:@NumericField만 있다는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이 부분을 해결하려는 방법은 되게 간단했다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PhotoRecentWriter의 id 필드에 동일한 어노테이션을 적용하거나, 아예 ElasticSearch 인덱싱이 필요 없으면 Indexed 어노테이션을 제거하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1774876140153&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class PhotoRecentWriter {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NonNull
    @Embedded
    private UserPostingRelation relation;

    private ZonedDateTime createdAt;

    public PhotoRecentWriter(@NonNull UserPostingRelation userPostingRelation, ZonedDateTime createdAt){
        this.relation = userPostingRelation;
        this.createdAt = createdAt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 PhotoRecentWriter 가 검색기능에 사용되지 않으므로 제거하면되는 부분이므로 JPA엔티니니까 DB에서만 쓰는거임 ㅇㅇ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데? 난 사실 이걸 먼저하기보다 이 짓을 먼저했음&lt;/p&gt;
&lt;pre id=&quot;code_1774876191451&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -X DELETE &quot;localhost:9200/net.infobank.moyamo.models.photorecentwriter&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 502 Bad Gateway는 해결되서 올라오긴 하는데, 사람들이 예전에 쓴 글이 안올라온다고 하는 대략난감의 사태가 벌어졌다는 거쉼..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 영향이 있냐 없냐 고민을 하다보니 100% 있다는 것임!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;어머이건꼭구해야해.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lPDP6/dJMcagEZIAy/juh9QcLDos8UKKvFLzz9P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lPDP6/dJMcagEZIAy/juh9QcLDos8UKKvFLzz9P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lPDP6/dJMcagEZIAy/juh9QcLDos8UKKvFLzz9P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlPDP6%2FdJMcagEZIAy%2Fjuh9QcLDos8UKKvFLzz9P1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;433&quot; data-filename=&quot;어머이건꼭구해야해.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 60.9302%; height: 168px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;엔드포인트&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GET /v2/users/me/postings&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;내가 쓴 글 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GET /v2/users/me/comments&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;내가 댓글 단 글 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GET /v2/users/{id}/postings&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;특정 사용자가 쓴 글 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;GET /v2/users/{id}/comments&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;특정 사용자가 댓글 단 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그렇게 시작되었다. Hibernate Search에서 기존 DB 데이터를 ElasticSearch에 다시 인덱싱하는 &lt;s&gt;개&lt;/s&gt;삽질의 작업&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식은땀을 줄줄 흘리다가. 나자신 생각했다. 하늘이 무너져도 솟아날 구멍? 댓츠논노&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨋든 저놈들은 죄다 ElasticSearch 기반의 작업일꺼니까 인덱스만 다시 치면 된다는 생각이었음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 JPA 안에 본체가 있는데 ElasticSearch가 캐싱하는 데이터 구도라면? 캐싱만 치면 되는 부분임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어 찾아보니 땅굴을 좀 파놧는데 이런 것들이 있었음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Posting 인덱스 재구축&lt;/p&gt;
&lt;pre id=&quot;code_1774876485643&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# POST 요청 - sinceId부터 maxId까지 게시글 인덱싱
curl -X POST &quot;http://&amp;lt;scheduler-server&amp;gt;/indexing?sinceId=0&amp;amp;maxId=999999999&amp;amp;max=200&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 api-server 에서&lt;/p&gt;
&lt;pre id=&quot;code_1774876502920&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 특정 게시글 ID들 인덱싱
curl -X POST &quot;http://&amp;lt;api-server&amp;gt;/v2/postings/index?ids=1,2,3,4,5&amp;amp;max=200&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. User 인덱스 재구축&lt;/p&gt;
&lt;pre id=&quot;code_1774876515639&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# moyamo-api-server에서
curl -X GET &quot;http://&amp;lt;api-server&amp;gt;/v2/users/index&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 아무리 생각해봐도 API에다가 저짓을 하다가는 서버가 죽을 것이 뻔했음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 에서 데이터를 조사함&lt;/p&gt;
&lt;pre id=&quot;code_1774876589190&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- MySQL에서 게시글 ID 범위 확인
SELECT MIN(id), MAX(id) FROM posting WHERE is_delete = false;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDNEwM/dJMcad2uwkc/7vvyY0uhBMuKNtK8ZVka61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDNEwM/dJMcad2uwkc/7vvyY0uhBMuKNtK8ZVka61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDNEwM/dJMcad2uwkc/7vvyY0uhBMuKNtK8ZVka61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDNEwM%2FdJMcad2uwkc%2F7vvyY0uhBMuKNtK8ZVka61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1031&quot; height=&quot;95&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참으로 기모찌한 결과가 나온 것인데, 이걸 curl 로 나눠서 쏘다가는 꽤 귀찮을 것 같다는 거쉬..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 인덱스 스크립트를 만들어서 때려박기로 했다.&lt;/p&gt;
&lt;pre id=&quot;code_1774876654714&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash
# Elasticsearch 인덱스 재구축 스크립트 (Linux/Mac용)
# 게시글 ID 범위: 114 ~ 16,335,566

SCHEDULER_URL=&quot;http://localhost:8088&quot;  # moyamo-scheduler 포트: 8088
BATCH_SIZE=10000                        # 한 번에 처리할 ID 범위
MAX_COMMENTS=200                        # 댓글 수 제한
DELAY_SECONDS=2                         # 배치 간 대기 시간

MIN_ID=114
MAX_ID=16335566

CURRENT_ID=$MIN_ID
TOTAL_BATCHES=$(( (MAX_ID - MIN_ID + BATCH_SIZE - 1) / BATCH_SIZE ))
CURRENT_BATCH=0

echo &quot;========================================&quot;
echo &quot;Elasticsearch 인덱스 재구축 시작&quot;
echo &quot;총 배치 수: $TOTAL_BATCHES&quot;
echo &quot;ID 범위: $MIN_ID ~ $MAX_ID&quot;
echo &quot;배치 크기: $BATCH_SIZE&quot;
echo &quot;========================================&quot;

START_TIME=$(date +%s)

while [ $CURRENT_ID -le $MAX_ID ]; do
    CURRENT_BATCH=$((CURRENT_BATCH + 1))
    END_ID=$((CURRENT_ID + BATCH_SIZE - 1))
    if [ $END_ID -gt $MAX_ID ]; then
        END_ID=$MAX_ID
    fi

    PROGRESS=$(echo &quot;scale=1; $CURRENT_BATCH * 100 / $TOTAL_BATCHES&quot; | bc)
    echo &quot;[$CURRENT_BATCH/$TOTAL_BATCHES] ($PROGRESS%) 인덱싱 중: $CURRENT_ID ~ $END_ID&quot;

    RESPONSE=$(curl -s -X POST &quot;$SCHEDULER_URL/indexing?sinceId=$CURRENT_ID&amp;amp;maxId=$END_ID&amp;amp;max=$MAX_COMMENTS&quot; --max-time 300)

    if [ $? -eq 0 ]; then
        echo &quot;  완료: $RESPONSE&quot;
    else
        echo &quot;  오류 발생, 재시도 중...&quot;
        sleep 5
        RESPONSE=$(curl -s -X POST &quot;$SCHEDULER_URL/indexing?sinceId=$CURRENT_ID&amp;amp;maxId=$END_ID&amp;amp;max=$MAX_COMMENTS&quot; --max-time 300)
        if [ $? -eq 0 ]; then
            echo &quot;  재시도 완료: $RESPONSE&quot;
        else
            echo &quot;  재시도 실패, 다음 배치로 진행&quot;
        fi
    fi

    CURRENT_ID=$((END_ID + 1))

    if [ $CURRENT_ID -le $MAX_ID ]; then
        sleep $DELAY_SECONDS
    fi
done

END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
HOURS=$((DURATION / 3600))
MINUTES=$(( (DURATION % 3600) / 60 ))
SECONDS=$((DURATION % 60))

echo &quot;========================================&quot;
echo &quot;인덱싱 완료!&quot;
echo &quot;소요 시간: ${HOURS}시간 ${MINUTES}분 ${SECONDS}초&quot;
echo &quot;========================================&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 테스트도 완료했겠다 신나게 돌려본다는 것인데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 주머니에서 주섬주섬 moyamo-common 부터 말은 이후에 api-server를 말아서 build.jar로 만든다음에 배포 했다는 스토리는 생략하도록 하고, 저게 돌아가는건 결국 스케쥴러가 돌아가는 인스턴스에서 돌아가고 있는 부분이었으니까 포트부터 조사하면&lt;/p&gt;
&lt;pre id=&quot;code_1774876752221&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;스크립트 &amp;rarr; moyamo-scheduler &amp;rarr; Elasticsearch
              (/indexing API)      (내부적으로 연결)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 구조가 나온다는 것이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해보니 Tools 서버를 껏다키면서 ElasticSearch 때문에 잘 안올라오는 다는 부분을 생각해보면서 볼륨 detach 했다가 다시 attach 하고 그런 부분 와중에 데몬을 제대로 안살렸었더라는 기억이 있었으므로 스케쥴러부터 살려줌&lt;/p&gt;
&lt;pre id=&quot;code_1774876865907&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ubuntu@ip-172-31-40-155:~/workspace/scheduler/logs$ ps -ef | grep scheduler
ubuntu   15665  6442  0 12:34 pts/1    00:00:00 grep --color=auto scheduler
ubuntu@ip-172-31-40-155:~/workspace/scheduler/logs$ cd ..
ubuntu@ip-172-31-40-155:~/workspace/scheduler$ ls -alk
total 40
drwxrwxr-x 5 ubuntu ubuntu  4096 Oct  7  2024 .
drwxrwxr-x 4 ubuntu ubuntu  4096 Mar 30  2021 ..
drwxrwxr-x 2 ubuntu ubuntu  4096 Oct 21  2024 bin
drwxrwxr-x 2 ubuntu ubuntu 16384 Mar 30 12:32 logs
-rwxrwxr-x 1 ubuntu ubuntu   253 Oct 13  2023 start.sh
drwxrwxr-x 3 ubuntu ubuntu  4096 Sep  7  2020 static
-rwxrwxr-x 1 ubuntu ubuntu    58 Apr 16  2021 stop.sh
ubuntu@ip-172-31-40-155:~/workspace/scheduler$ vi start.sh 
ubuntu@ip-172-31-40-155:~/workspace/scheduler$ vi start.sh 
ubuntu@ip-172-31-40-155:~/workspace/scheduler$ ./start.sh 
ubuntu@ip-172-31-40-155:~/workspace/scheduler$ ps -ef | grep scheduler
ubuntu   18233     1 99 12:36 pts/1    00:00:11 java -Xmx1500m -Xms1500m -jar -Dspring.profiles.active=product -Dmoyamo.jobs.rankings.cron=0 */1 * * * * -Dmoyamo.jobs.statistics.cron=0 */1 * * * * /home/ubuntu/workspace/scheduler/bin/moyamo-scheduler-0.0.1-SNAPSHOT.jar
ubuntu   18373  6442  0 12:36 pts/1    00:00:00 grep --color=auto scheduler&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 언제 살아날지 모르는 대망의 작업을 시작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1774876897147&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ubuntu@ip-172-31-40-155:~$ chmod +x reindex-elasticsearch.sh 
ubuntu@ip-172-31-40-155:~$ ./reindex-elasticsearch.sh 
========================================
Elasticsearch 인덱스 재구축 시작
총 배치 수: 1634
ID 범위: 114 ~ 16335566
배치 크기: 10000
========================================
[1/1634] (0%) 인덱싱 중: 114 ~ 10113
  완료: end
[2/1634] (.1%) 인덱싱 중: 10114 ~ 20113
  완료: end
[3/1634] (.1%) 인덱싱 중: 20114 ~ 30113
  완료: end
[4/1634] (.2%) 인덱싱 중: 30114 ~ 40113
  완료: end
[5/1634] (.3%) 인덱싱 중: 40114 ~ 50113
  완료: end
[6/1634] (.3%) 인덱싱 중: 50114 ~ 60113
  완료: end
[7/1634] (.4%) 인덱싱 중: 60114 ~ 70113
  완료: end
[8/1634] (.4%) 인덱싱 중: 70114 ~ 80113
  완료: end
[9/1634] (.5%) 인덱싱 중: 80114 ~ 90113
  완료: end
[10/1634] (.6%) 인덱싱 중: 90114 ~ 100113
  완료: end
[11/1634] (.6%) 인덱싱 중: 100114 ~ 110113
  완료: end
[12/1634] (.7%) 인덱싱 중: 110114 ~ 120113
  완료: end
[13/1634] (.7%) 인덱싱 중: 120114 ~ 130113
  완료: end
[14/1634] (.8%) 인덱싱 중: 130114 ~ 140113
  완료: end
[15/1634] (.9%) 인덱싱 중: 140114 ~ 150113
  완료: end
[16/1634] (.9%) 인덱싱 중: 150114 ~ 160113&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;849&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B2zIU/dJMcaivY3He/lQyBi1Qp07O8RAitlJJEbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B2zIU/dJMcaivY3He/lQyBi1Qp07O8RAitlJJEbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B2zIU/dJMcaivY3He/lQyBi1Qp07O8RAitlJJEbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB2zIU%2FdJMcaivY3He%2FlQyBi1Qp07O8RAitlJJEbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1915&quot; height=&quot;849&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;849&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Java/Spring Boot JPA</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/642</guid>
      <comments>https://remoted.tistory.com/642#entry642comment</comments>
      <pubDate>Mon, 30 Mar 2026 22:36:30 +0900</pubDate>
    </item>
    <item>
      <title>[Apache/Nginx] Emergency Restart Setting</title>
      <link>https://remoted.tistory.com/641</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;서두&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx에서 &quot;emergency restart&quot;에 대한 개념은 일반적으로 특정 상황에서 Nginx 서비스를 빠르게 재시작하거나 복구해야 할 때 사용됩니다. 하지만 Nginx 자체에는 &quot;emergency restart&quot;라는 특정 명령어나 기능이 명시적으로 정의되어 있지는 않습니다. 대신, 이는 운영 환경에서 특정 문제를 해결하기 위해 관리자가 수행하는 비상 조치로 해석될 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;비상 재시작의 의미&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비상 재시작은 Nginx가 비정상적으로 동작하거나, 설정 오류, 메모리 누수, 프로세스 충돌 등의 문제로 인해 즉각적인 재시작이 필요한 상황을 의미합니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 웹 서버가 응답하지 않거나, 잘못된 설정 파일로 인해 서버가 제대로 작동하지 않을 때 관리자가 빠르게 조치해야 할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로 NginX 에서 의미하는 비상 재시작 조치라는 것은, 상황이 닥쳤을 때 비상 재시작을 하는 것을 의미하는데, 오늘 글에서 다룰 이야기는 이런 NginX의 수동적인 재시작의 의미가 아니라, &lt;u&gt;&lt;b&gt;PHP-FPM에서 제공하는 emergency_restart에 관한 이야기&lt;/b&gt;&lt;/u&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PHP-FPM의 emergency_restart 관련 옵션은 &lt;u&gt;PHP-FPM 프로세스가 비정상적인 상황(예: 메모리 누수, 세그먼테이션 오류 등)에서 자동으로 재시작하도록 설정하는 데 사용되는 부분&lt;/u&gt;입니다. 이 옵션들은 주로 &lt;b&gt;php-fpm.conf 파일의 [global] 섹션에서 설정&lt;/b&gt;된다. 아래는 관련 옵션들과 설정 방법에 대한 자세한 설명 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;간단하게 추가 이야기를 다루자면, 대부분의 SE 사이에서는 당연한 부분일 수 있겠지만 LAMP 스택과 LEMP 스택에 관련된 이야기이다. LEMP 스택에서는 NginX + MySQL(MariaDB) + PHP-FPM 을 조합하여 쓰기 때문에 이 부분에서 NginX를 언급하지 않을 수 없는 것입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PHP-FPM의 Emergency Restart 옵션&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;emergency_restart_threshold&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설명&lt;/b&gt;: 지정된 시간 간격 내에 특정 수의 자식 프로세스가 &lt;span&gt;SIGSEGV&lt;/span&gt;(세그먼테이션 오류) 또는 &lt;span&gt;SIGBUS&lt;/span&gt;(버스 오류)로 종료되면 PHP-FPM이 자동으로 재시작됩니다. 이 설정은 비정상적인 종료가 빈번할 경우 메모리 누수나 기타 문제를 해결하는 데 유용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본값&lt;/b&gt;: &lt;span&gt;0&lt;/span&gt; (비활성화)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: &lt;span&gt;emergency_restart_threshold = 10&lt;/span&gt; (10개의 자식 프로세스가 비정상 종료 시 재시작 트리거)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참고&lt;/b&gt;: 이 설정은 &lt;span&gt;[global]&lt;/span&gt; 섹션에 추가해야 하며, 풀별 설정 파일(예: &lt;span&gt;www.conf&lt;/span&gt;)에 추가하면 오류가 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;emergency_restart_interval&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설명&lt;/b&gt;: &lt;span&gt;emergency_restart_threshold&lt;/span&gt;에서 지정한 비정상 종료 횟수가 발생해야 하는 시간 간격을 정의합니다. 이 시간 내에 지정된 수의 자식 프로세스가 비정상 종료되면 재시작이 트리거됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본값&lt;/b&gt;: &lt;span&gt;0&lt;/span&gt; (비활성화)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 가능한 단위&lt;/b&gt;: &lt;span&gt;s&lt;/span&gt;(초), &lt;span&gt;m&lt;/span&gt;(분), &lt;span&gt;h&lt;/span&gt;(시간), &lt;span&gt;d&lt;/span&gt;(일)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: &lt;span&gt;emergency_restart_interval = 1m&lt;/span&gt; (1분 내에 지정된 횟수의 오류 발생 시 재시작)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참고&lt;/b&gt;: 이 설정은 메모리 누수나 공유 메모리 손상 같은 문제를 해결하는 데 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;process_control_timeout&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설명&lt;/b&gt;: 자식 프로세스가 마스터 프로세스로부터 받은 신호(예: 종료 신호)에 반응할 때까지 대기하는 시간 제한을 설정합니다. 이 시간이 초과되면 자식 프로세스가 강제로 종료되고 새로운 프로세스로 대체됩니다. 이는 자식 프로세스가 응답하지 않는 상황에서 시스템 안정성을 보장합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본값&lt;/b&gt;: &lt;span&gt;0&lt;/span&gt; (비활성화)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용 가능한 단위&lt;/b&gt;: &lt;span&gt;s&lt;/span&gt;(초), &lt;span&gt;m&lt;/span&gt;(분), &lt;span&gt;h&lt;/span&gt;(시간), &lt;span&gt;d&lt;/span&gt;(일)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;: &lt;span&gt;process_control_timeout = 10s&lt;/span&gt; (10초 동안 신호에 응답하지 않으면 강제 종료)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참고&lt;/b&gt;: 이 설정은 자식 프로세스가 작업을 완료할 기회를 주되, 무한정 대기하지 않도록 합니다..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설정 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;/etc/php/7.x/fpm/php-fpm.conf&lt;/span&gt; 파일의 &lt;span&gt;[global]&lt;/span&gt; 섹션에 아래와 같이 추가할 수 있습니다:&lt;/p&gt;
&lt;div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;pre id=&quot;code_1756226195160&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[global]
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 설정은 1분 내에 10개의 자식 프로세스가 &lt;span&gt;SIGSEGV&lt;/span&gt; 또는 &lt;span&gt;SIGBUS&lt;/span&gt;로 종료되면 PHP-FPM이 자동으로 재시작되며, 자식 프로세스가 10초 동안 마스터의 신호에 응답하지 않으면 강제로 종료됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설정 시 주의사항&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;설정 파일 위치&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;emergency_restart_threshold&lt;/span&gt;&lt;/b&gt;와 &lt;b&gt;&lt;span&gt;emergency_restart_interval&lt;/span&gt;&lt;/b&gt;은 &lt;b&gt;&lt;span&gt;[global]&lt;/span&gt;&lt;/b&gt; 섹션에 추가해야 합니다. 풀 설정 파일(예: &lt;b&gt;&lt;span&gt;/etc/php/7.x/fpm/pool.d/www.conf&lt;/span&gt;&lt;/b&gt;)에 추가하면 &lt;b&gt;&lt;span&gt;unknown entry&lt;/span&gt;&lt;/b&gt; 오류가 발생할 수 있습니다.&lt;/li&gt;
&lt;li&gt;예를 들어, Ubuntu 16.04에서 PHP 7.0을 사용할 경우 &lt;b&gt;&lt;span&gt;/etc/php/7.0/fpm/php-fpm.conf&lt;/span&gt;&lt;/b&gt;에 설정해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로그 확인&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비정상 종료의 원인을 파악하려면 PHP-FPM 로그를 활성화하고 확인해보죠. 예:
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756226312434&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[global]
error_log = /var/log/php-fpm.log
log_level = notice&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
로그 파일을 확인하려면:
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756226361415&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;tail -f /var/log/php-fpm.log&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;적절한 값 설정&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;emergency_restart_threshold&lt;/span&gt;&lt;/b&gt;와 &lt;b&gt;&lt;span&gt;emergency_restart_interval&lt;/span&gt;&lt;/b&gt;은 서버 부하와 애플리케이션 특성에 따라 조정해야 합니다. 값이 너무 낮으면 불필요한 재시작이 빈번해지고, 너무 높으면 비정상 상황을 감지하지 못할 수 있습니다.&lt;/li&gt;
&lt;li&gt;예: 고트래픽 사이트에서는 &lt;span&gt;emergency_restart_threshold = 10&lt;/span&gt;과 &lt;span&gt;emergency_restart_interval = 1m&lt;/span&gt;이 적절할 수 있습니다. (고트래픽 사이트가 뭔진 모르겠지만 그렇게 번역할 것이니까 그런거로 하죠)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Graceful 재시작&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 옵션들은 PHP-FPM의 재시작이 기존 요청을 중단시킬 수 있으므로, 가능하면 &lt;span&gt;reload&lt;/span&gt;를 사용해 부드러운 재시작을 시도합시다:
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756226416853&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;sudo systemctl reload php7.x-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제 해결&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;emergency_restart_threshold&lt;/span&gt;가 작동하지 않는 경우, 자식 프로세스가 &lt;span&gt;SIGSEGV&lt;/span&gt;나 &lt;span&gt;SIGBUS&lt;/span&gt; 외의 다른 신호(예: &lt;span&gt;SIGTERM&lt;/span&gt;)로 종료되고 있을 수 있습니다. 로그를 확인해 정확한 종료 원인을 파악합시다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모니터링&lt;/b&gt;: PHP-FPM 상태 페이지를 활성화하여 프로세스 상태를 모니터링 할 수 있습니다:
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756226467787&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[www]
pm.status_path = /status&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
Nginx에서 이를 설정하려면:
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756226490377&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;location /status {
    fastcgi_pass unix:/var/run/php/php7.x-fpm.sock;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제 원인 분석&lt;/b&gt;: 메모리 누수나 비정상 종료가 자주 발생한다면, &lt;span&gt;slowlog&lt;/span&gt;와 &lt;span&gt;request_slowlog_timeout&lt;/span&gt;을 설정해 느린 스크립트를 추적하거나, &lt;span&gt;pm.max_requests&lt;/span&gt;를 낮춰 자식 프로세스를 자주 재생성하도록 설정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PHP-FPM의 &lt;b&gt;&lt;span&gt;emergency_restart&lt;/span&gt; &lt;/b&gt;옵션(&lt;b&gt;&lt;span&gt;emergency_restart_threshold&lt;/span&gt;&lt;/b&gt;, &lt;b&gt;&lt;span&gt;emergency_restart_interval&lt;/span&gt;&lt;/b&gt;, &lt;b&gt;&lt;span&gt;process_control_timeout&lt;/span&gt;&lt;/b&gt;)은 비정상적인 상황에서 자동 재시작을 통해 시스템 안정성을 유지하는 데 유용합니다. 이 옵션들은 &lt;span&gt;[global]&lt;/span&gt; 섹션에 설정해야 하며, 서버 환경과 트래픽 패턴에 맞게 값을 조정하는 것이 중요합니다. 설정 후에는 로그를 모니터링하여 예상대로 동작하는지 확인해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데? 우리가 살펴볼 것은 당연하게도 NginX 에서 살펴볼 PHP-FPM 의 옵션이 아니다. 정확하게는 Apache 에서 이 부분을 조질 수 없냐는 것인데, &lt;b&gt;당연하게도 없을 줄 알았지만 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;Apache와 PHP-FPM, MySQL 환경에서도 PHP-FPM의 &lt;b&gt;emergency_restart&lt;/b&gt; 옵션을 설정할 수 있습니다. PHP-FPM은 웹 서버(Nginx 또는 Apache)와 독립적으로 동작하는 PHP FastCGI 프로세스 매니저이기 때문에, Apache를 사용하더라도 PHP-FPM의 설정은 동일하게 적용됩니다. &lt;br /&gt;&lt;br /&gt;emergency_restart 관련 옵션(emergency_restart_threshold, emergency_restart_interval, process_control_timeout)은 PHP-FPM의 설정 파일(php-fpm.conf)에서 관리되며, 웹 서버가 Apache이든 Nginx이든 상관없이 동일하게 작동합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;다만, Apache와 PHP-FPM을 함께 사용할 때는 몇 가지 추가적인 설정과 주의사항이 필요하다.&amp;nbsp;&lt;/u&gt;&lt;u&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1756227050365&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[global]
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
error_log = /var/log/php-fpm.log
log_level = notice&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;Apache와 PHP-FPM 연동 확인&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache에서 PHP-FPM을 사용하려면 &lt;span&gt;mod_fastcgi&lt;/span&gt; 또는 &lt;span&gt;mod_proxy_fcgi&lt;/span&gt; 모듈을 통해 PHP 요청을 PHP-FPM으로 전달하도록 설정해야 합니다. &lt;span&gt;emergency_restart&lt;/span&gt; 옵션이 제대로 작동하려면 Apache와 PHP-FPM 간의 연결이 올바르게 설정되어 있는지 확인해야 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Apache 설정 예시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ubuntu/Debian 시스템에서 PHP-FPM과 Apache를 연동하는 일반적인 설정은 다음과 같습니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 모듈을 활성화 한 이후에&lt;/p&gt;
&lt;pre id=&quot;code_1756227089828&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo a2enmod proxy proxy_fcgi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache 설정 파일 수정: /etc/apache2/sites-available/000-default.conf (또는 사용 중인 가상 호스트 파일)에 다음을 추가합니다:&lt;/p&gt;
&lt;pre id=&quot;code_1756227111964&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName example.com
    DocumentRoot /var/www/html

    &amp;lt;FilesMatch \.php$&amp;gt;
        SetHandler &quot;proxy:unix:/var/run/php/php7.x-fpm.sock|fcgi://localhost/&quot;
    &amp;lt;/FilesMatch&amp;gt;
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 설마 아직도 VirtualHost 기능을 모르는 사람은 없겠죠? 는 있을 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;/var/run/php/php7.x-fpm.sock&lt;/span&gt;는 PHP-FPM 소켓 경로로, PHP 버전에 따라 &lt;span&gt;7.x&lt;/span&gt;는 실제 버전(예: &lt;span&gt;7.4&lt;/span&gt;, &lt;span&gt;8.0&lt;/span&gt;)으로 대체됩니다.&lt;/li&gt;
&lt;li&gt;TCP 포트를 사용하는 경우 &lt;span&gt;proxy:fcgi://127.0.0.1:9000/&lt;/span&gt;처럼 설정할 수도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정을 해 줬으면 당연하게 apache랑 php-fpm 데몬을 재시작 시켜줘야 적용된다 ^^&lt;/p&gt;
&lt;pre id=&quot;code_1756227174796&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl restart apache2
sudo systemctl restart php7.x-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;중론&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgmSmY/btsP8fe492B/YB0lQeUTyJ9tmOGBa9WEf1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgmSmY/btsP8fe492B/YB0lQeUTyJ9tmOGBa9WEf1/img.webp&quot; data-alt=&quot;그런데 말입니다?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgmSmY/btsP8fe492B/YB0lQeUTyJ9tmOGBa9WEf1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgmSmY%2FbtsP8fe492B%2FYB0lQeUTyJ9tmOGBa9WEf1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;245&quot; height=&quot;327&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그런데 말입니다?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 제가 궁금했던 것은 망할놈의 emergency_restart를 흔하게 nginx 에서 조진다거나 apache에서 php-fpm과 함께 조지는 것에 대한 내용이 아닙니다. &lt;u&gt;&lt;b&gt;그럼 무엇이냐구요? PHP-FPM이 없을 때를 이야기 하는 것&lt;/b&gt;&lt;/u&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 그러냐구요? &lt;u&gt;PHP-FPM을 추가적으로 설정하고 모듈을 설정하는 것은 매우매우 귀찮은 일인 것&lt;/u&gt;이거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Apache, PHP, MySQL 스택에서 PHP-FPM을 사용하지 않는다면, PHP는 일반적으로 Apache의 mod_php 모듈을 통해 실행됩니다. 이 경우 PHP-FPM의 emergency_restart 옵션(emergency_restart_threshold, emergency_restart_interval, process_control_timeout)은 사용할 수 없습니다. 이는 PHP-FPM 전용 설정이기 때문입니다. &lt;br /&gt;&lt;br /&gt;mod_php는 Apache 프로세스 내에서 PHP를 직접 실행하므로 PHP-FPM의 프로세스 관리 기능과 같은 자동 재시작 메커니즘이 없습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;mod_php&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;환경에서도 비정상적인 상황(예: 메모리 누수, 세그먼테이션 오류 등)에서 Apache를 재시작하거나 문제를 완화할 수 있는 대안적인 방법이 있습니다. 아래에서 이를 자세히 설명하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;&lt;span&gt;mod_php&lt;/span&gt; 환경에서 비상 재시작 대안&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;mod_php&lt;/span&gt;는 Apache 워커 프로세스 내에서 PHP를 실행하므로, PHP 관련 문제를 해결하려면 Apache 자체를 관리하거나 외부 스크립트 및 모니터링 도구를 활용해야 합니다. 다음은 대안적인 접근법입니다:&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) &lt;b&gt;Apache 재시작&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache 프로세스가 비정상적으로 동작하거나 PHP 스크립트로 인해 메모리 사용량이 비정상적으로 증가할 경우, Apache를 재시작하여 문제를 해결할 수 있습니다. (아 이런 허접한 방법 말구요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Graceful Reload&lt;/b&gt;:&lt;/p&gt;
&lt;pre id=&quot;code_1756227459015&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apachectl graceful&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 명령은 기존 연결을 유지하면서 Apache 워커 프로세스를 새로고침합니다.&lt;/li&gt;
&lt;li&gt;클라이언트 연결이 끊기지 않으므로 다운타임을 최소화할 수 있습니다.&lt;/li&gt;
&lt;li&gt;PHP 스크립트의 메모리 누수가 워커 프로세스에 영향을 미쳤다면, 이 방법으로 새로운 워커 프로세스를 생성하여 문제를 완화할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hard Restart&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 아래놈 중 한놈으로 조질 수 있는 것은 모두가 다 알고있는 사실일 것 입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756227493030&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl restart apache2

sudo service apache2 restart&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;강제 종료 후 재시작&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간혹 뒤지지 않는다면 강제로 죽이는 방법도 있죠&lt;/p&gt;
&lt;pre id=&quot;code_1756227534122&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo killall -9 apache2
sudo systemctl start apache2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) &lt;b&gt;&lt;span&gt;MaxRequestsPerChild&lt;/span&gt; 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache의 MPM(Module Processing Model) 설정에서 &lt;span&gt;MaxRequestsPerChild&lt;/span&gt;를 조정하여 PHP 스크립트로 인한 메모리 누수를 방지할 수 있습니다. 이 설정은 각 워커 프로세스가 처리할 수 있는 최대 요청 수를 제한하여, 일정 요청 후 프로세스를 종료하고 새 프로세스로 교체합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설정 방법&lt;/b&gt;: Apache 설정 파일(예: &lt;span&gt;/etc/apache2/apache2.conf&lt;/span&gt; 또는 &lt;span&gt;/etc/httpd/conf/httpd.conf&lt;/span&gt;)의 MPM 모듈 설정에 추가합니다. 예를 들어, &lt;span&gt;mpm_prefork&lt;/span&gt;를 사용하는 경우:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1756227574259&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;IfModule mpm_prefork_module&amp;gt;
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxClients          150
    MaxRequestsPerChild  500
&amp;lt;/IfModule&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;MaxRequestsPerChild 500&lt;/span&gt;: 각 워커 프로세스가 500개의 요청을 처리한 후 종료되고 새 프로세스로 교체됩니다.&lt;/li&gt;
&lt;li&gt;이 설정은 PHP-FPM의 &lt;span&gt;pm.max_requests&lt;/span&gt;와 유사한 역할을 하며, 메모리 누수로 인한 문제를 줄이는 데 효과적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 mpm 모듈에 따라서도 다른 것을 쓰고 있는 경우도 있을겁니다. 그건 당연히 바꿔치기 술법을 써야겠죠. 여하튼 저걸 적용시키면 재시작 시키는건 당연한겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1756227640032&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apachectl configtest
sudo systemctl reload apache2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) &lt;b&gt;외부 모니터링 스크립트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PHP-FPM의 &lt;span&gt;emergency_restart&lt;/span&gt;와 같은 자동 재시작 기능을 구현하려면 외부 스크립트나 모니터링 도구를 사용하여 Apache 프로세스의 상태를 감시하고 필요 시 재시작하도록 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간단한 Bash 스크립트 예시&lt;/b&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756227700037&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash
# /usr/local/bin/monitor_apache.sh

# 메모리 사용량 체크 (예: 1GB 초과 시 재시작)
MEMORY_USAGE=$(ps -C apache2 -o %mem | awk '{sum += $1} END {print sum}')
THRESHOLD=1000  # 메모리 사용량 임계값 (MB)

if (( $(echo &quot;$MEMORY_USAGE &amp;gt; $THRESHOLD&quot; | bc -l) )); then
    echo &quot;Memory usage exceeded threshold: $MEMORY_USAGE MB&quot;
    sudo systemctl restart apache2
    echo &quot;Apache restarted at $(date)&quot; &amp;gt;&amp;gt; /var/log/apache_monitor.log
fi&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스크립트를 크론잡으로 주기적으로 실행하도록 설정:&lt;/p&gt;
&lt;pre id=&quot;code_1756227723628&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;crontab -e
* * * * * /bin/bash /usr/local/bin/monitor_apache.sh&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모니터링 도구&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Monit&lt;/b&gt;: Apache 프로세스의 메모리 사용량이나 CPU 사용량을 감시하고, 임계값 초과 시 자동으로 재시작하도록 설정할 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Monit 설정 예시 (&lt;span&gt;/etc/monit/monitrc&lt;/span&gt;)&lt;br /&gt;
&lt;pre id=&quot;code_1756227826783&quot; class=&quot;maxima&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;check process apache2 with pidfile /var/run/apache2.pid
    start program = &quot;/bin/systemctl start apache2&quot;
    stop program = &quot;/bin/systemctl stop apache2&quot;
    if totalmem &amp;gt; 1000 MB for 5 cycles then restart
    if cpu &amp;gt; 80% for 5 cycles then restart&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Monit 설치 및 실행:&lt;br /&gt;
&lt;pre id=&quot;code_1756227826783&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get install monit
sudo systemctl enable monit
sudo systemctl start monit&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 PHP 의 설정을 조정해서 memory_limit 를 기본적으로 128M 정도로 잡는 다던지 max_execution_time을 잡는다는지의 설정 방법이 있다. 문제는? 사이트가 돌아가는 메모리 자체가 크고 max_execution_time이 원래부터 길어야 한다면? 이 방법은 틀린 방법이라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 내 경우는 t2.micro 로 스펙을 설정해서 시작했는데, 이 경우는 셋팅을 좀 바꿔줘야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1756227940715&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;IfModule mpm_prefork_module&amp;gt;
    StartServers          2
    MinSpareServers      2
    MaxSpareServers      4
    MaxClients          20
    MaxRequestsPerChild  200
&amp;lt;/IfModule&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 메모리 사용량을 확인해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1756227955889&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;free -m
top&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Monit의 경우도 t2.micro에 맞게 이렇게 설정을 고쳐줬다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1756228169762&quot; class=&quot;maxima&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;check process apache2 with pidfile /var/run/apache2.pid
    start program = &quot;/bin/systemctl start apache2&quot;
    stop program = &quot;/bin/systemctl stop apache2&quot;
    if totalmem &amp;gt; 600 MB for 3 cycles then restart
    if cpu &amp;gt; 70% for 3 cycles then restart&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 t2.micro 같은 경우는 메모리를 지나치게 잡아먹는 부분이 있으므로 128MB를 64MB로 설정하고 crontab 에서 주기도 5분마다 한번 씩 돌리는 것으로 바꿔줘야 하는 이슈가 있었다. &lt;i&gt;&lt;b&gt;하지만 그럼에도 다시한번 다운이 발생하는 이슈가 발생했다.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹사이트가 만약 WordPress 기반이라면?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다. WordPress는 MySQL에 크게 의존하고, 이에 따라 설정해줘야 하는 값이 좀 달라진다. 특히 t2.micro 부분에서도 96MB로 설정해주고 innoDB 의 값도 설정해줘야 하는 약간의 추가 셋팅이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Information Gathering&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 로그 분석 및 메모리 용량 추정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커널에서 수집한 로그의 일부를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1756228234355&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257121] [ 13548] 33 13548 106257 5889 585728 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257121] [ 13551] 33 13551 105608 2870 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257122] [ 13556] 33 13556 106257 5888 585728 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257123] [ 13557] 33 13557 106257 5887 585728 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257124] [ 13558] 33 13558 106257 5889 585728 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257125] [ 13559] 33 13559 105646 2841 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257125] [ 13624] 33 13624 105646 2842 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257126] [ 13625] 33 13625 105646 2839 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257127] [ 13633] 33 13633 105646 2839 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257128] [ 13634] 33 13634 105608 2870 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257129] [ 13635] 33 13635 105608 2870 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257129] [ 13655] 33 13655 105600 2677 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257130] [ 13657] 33 13657 105600 2432 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257131] [ 13680] 33 13680 105600 2760 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257132] [ 13681] 33 13681 105600 2768 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257132] [ 13683] 33 13683 105602 2678 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257133] [ 13697] 33 13697 105600 2432 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257134] [ 13711] 0 13711 14806 115 155648 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257135] [ 13712] 33 13712 105600 2678 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257136] [ 13714] 33 13714 105602 2673 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257136] [ 13715] 33 13715 105602 2758 561152 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257137] [ 13716] 33 13716 105598 2753 552960 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257138] [ 13721] 0 13721 14806 116 155648 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257139] [ 13722] 0 13722 5955 107 86016 0 0 apport
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257139] [ 13728] 0 13728 14806 116 155648 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257140] [ 13731] 33 13731 105582 1632 536576 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257141] [ 13732] 0 13732 14806 116 155648 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257142] [ 13733] 33 13733 105504 1339 528384 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257143] [ 13737] 33 13737 105586 1579 548864 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257143] [ 13738] 33 13738 105586 1579 548864 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257144] [ 13739] 33 13739 105582 1632 536576 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257145] [ 13741] 0 13741 14806 116 155648 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257146] [ 13769] 1000 13769 1159 16 57344 0 0 sh
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257147] [ 13770] 1000 13770 3330 61 65536 0 0 bash
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257148] [ 13772] 1000 13772 1159 17 53248 0 0 sh
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257148] [ 13773] 1000 13773 1159 17 53248 0 0 sh
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257149] [ 13774] 1000 13774 1159 16 57344 0 0 sh
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257150] [ 13775] 1000 13775 1159 16 57344 0 0 sh
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257151] [ 13776] 1000 13776 3330 57 69632 0 0 bash
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257152] [ 13777] 1000 13777 3330 56 65536 0 0 bash
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257152] [ 13778] 1000 13778 3330 56 69632 0 0 bash
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257153] [ 13779] 1000 13779 3330 57 65536 0 0 bash
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257154] [ 13780] 0 13780 12162 93 135168 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257155] [ 13791] 1000 13791 3330 61 61440 0 0 bash
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257156] [ 13792] 1000 13792 6363 45 86016 0 0 ps
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257156] [ 13793] 1000 13793 5651 36 77824 0 0 awk
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257157] [ 13795] 0 13795 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257158] [ 13796] 0 13796 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257159] [ 13797] 0 13797 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257159] [ 13798] 0 13798 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257160] [ 13799] 0 13799 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257161] [ 13800] 0 13800 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257161] [ 13801] 0 13801 105495 1308 516096 0 0 apache2
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257162] [ 13803] 0 13803 9077 79 110592 0 0 cron
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257163] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/system.slice/apache2.service,task=apache2,pid=13142,uid=33
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257170] Out of memory: Killed process 13142 (apache2) total-vm:429472kB, anon-rss:12732kB, file-rss:0kB, shmem-rss:20288kB, UID:33 pgtables:592kB oom_score_adj:0
Aug 8 10:17:33 ip-172-31-44-66 kernel: [ 0.000000] Linux version 5.4.0-1103-aws (buildd@lcy02-amd64-028) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 (Ubuntu 5.4.0-1103.111~18.04.1-aws 5.4.233)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 커널에서 수집한 로그의 일부이지만, 대충 살펴보자면 결과적으로 OOM Killer 로 인해 발생한 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 줄은 Apache 프로세스(&lt;span&gt;apache2&lt;/span&gt;)의 메모리 사용량을 나타냅니다. 예를 들어, 프로세스 ID 13548의 경우:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;total-vm: 106257&lt;/span&gt; (약 426MB)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;anon-rss: 5889&lt;/span&gt; (약 24MB)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;file-rss: 0&lt;/span&gt;, &lt;span&gt;shmem-rss: 585728&lt;/span&gt; (약 572MB)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다수의 Apache 프로세스가 각각 400~500MB 이상의 가상 메모리(&lt;span&gt;total-vm&lt;/span&gt;)를 사용하고 있으며, 공유 메모리(&lt;span&gt;shmem-rss&lt;/span&gt;)가 상당히 큽니다. 이는 WordPress의 PHP 스크립트(&lt;span&gt;mod_php&lt;/span&gt;)가 Apache 워커 프로세스 내에서 실행되면서 메모리를 많이 소모하고 있음을 나타냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 부분에서 t2.micro 로는 부족한 부분이 있어, &lt;b&gt;T3.medium 으로 인스턴스 스펙을 변경&lt;/b&gt;해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T4g 시리즈를 고려할 수도 있었고 AWS Graviton2(ARM) 프로세서로 40% 더 나은 가격/성능 비율을 자랑하지만, 기존에 사용하던 것에서 아키텍쳐를 변경해야 하고 플러그인 다수 사용시 OOM위험이나 플러그인 호환성을 확인해야 하기 때문에 안정성 선택에서는 배제하고 5$가 비싼 T3.Medium으로 선택했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 &lt;b&gt;T3.Medium의 경우&lt;/b&gt;는 최신 AWS Nitro 시스템, t2.micro보다 나은 CPU 성능(최대 3.1GHz Intel Xeon). Unlimited 모드 기본 활성화로 CPU 크레딧 고갈 시 추가 요금($0.04/vCPU-시간)으로 버스팅 가능. 기능이 달려있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 전체 커널로그를 다시 분석한 이후에 아래와 같은 결론을 내렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 메모리 상태&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1756229253830&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.256965] 262045 pages RAM
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.256956] Node 0 DMA: ... = 4456kB
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.256959] Node 0 DMA32: ... = 44100kB
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.256964] Free swap = 0kB
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.256964] Total swap = 0kB&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;총 RAM: &lt;span&gt;262045 pages * 4kB = 약 1,048,180kB &amp;asymp; 1GB&lt;/span&gt; (t2.micro의 기본 메모리).&lt;/li&gt;
&lt;li&gt;사용 가능한 메모리: &lt;span&gt;4456kB(DMA) + 44100kB(DMA32) = 약 48.5MB&lt;/span&gt;로, 거의 모든 메모리가 소진됨.&lt;/li&gt;
&lt;li&gt;스왑 없음: &lt;span&gt;Free swap = 0kB, Total swap = 0kB&lt;/span&gt;. 스왑 공간이 없어 OOM Killer가 즉시 작동.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Apache 프로세스의 메모리 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1756229300732&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257013] [ 13142] 33 13142 107368 8255 606208 0 0 apache2
...
Aug 8 03:07:01 ip-172-31-44-66 kernel: [90625.257120] [ 13546] 33 13546 105646 2839 561152 0 0 apache2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Apache 프로세스(약 70개 이상)가 실행 중이며, 각 프로세스의 메모리 사용량:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;total-vm&lt;/span&gt;: 약 105,600~124,777 pages (420~500MB).&lt;/li&gt;
&lt;li&gt;&lt;span&gt;rss&lt;/span&gt; (Resident Set Size): 약 1,339~8,255 pages (5~33MB).&lt;/li&gt;
&lt;li&gt;&lt;span&gt;pgtables_bytes&lt;/span&gt;: 약 516,096~606,208kB (500~600kB).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;평균적으로 각 Apache 프로세스가 약 20~30MB RSS를 사용하며, 70개 프로세스는 약 1.4~2.1GB의 실제 메모리를 소모. 이는 &lt;span&gt;t2.micro&lt;/span&gt;의 1GB 메모리를 초과.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기타 프로세스&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL (&lt;span&gt;mysqld&lt;/span&gt;는 로그에 없지만 WordPress에 필수)과 기타 서비스(&lt;span&gt;systemd&lt;/span&gt;, &lt;span&gt;cron&lt;/span&gt;, &lt;span&gt;varnishd&lt;/span&gt; 등)가 추가 메모리를 사용.&lt;/li&gt;
&lt;li&gt;예: &lt;span&gt;amazon-ssm-agen&lt;/span&gt; (PID 791, 약 8MB RSS), &lt;span&gt;cache-main&lt;/span&gt; (PID 993, 약 3MB RSS).&lt;/li&gt;
&lt;li&gt;총 기타 프로세스 메모리: 약 50~100MB 추정.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) &lt;b&gt;필요한 메모리 용량 추정&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Apache 워커 프로세스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그에서 약 70개의 Apache 프로세스가 실행 중이었으나, 이는 &lt;span&gt;MaxClients 10&lt;/span&gt; 설정이 반영되지 않은 상태로 보임 (설정 미적용 또는 트래픽 급증).&lt;/li&gt;
&lt;li&gt;WordPress 사이트의 일반적인 동시 접속을 10~20명으로 가정하면, &lt;span&gt;MaxClients 15~20&lt;/span&gt;으로 설정 시 각 프로세스가 평균 25MB RSS를 사용한다고 가정:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;20 프로세스 &amp;times; 25MB = 약 500MB.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MySQL&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WordPress의 MySQL은 &lt;span&gt;innodb_buffer_pool_size=100M&lt;/span&gt;, &lt;span&gt;query_cache_size=4M&lt;/span&gt;, &lt;span&gt;max_connections=30&lt;/span&gt; 설정 기준 약 150~200MB 사용 추정.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기타 서비스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;systemd&lt;/span&gt;, &lt;span&gt;cron&lt;/span&gt;, &lt;span&gt;varnishd&lt;/span&gt;, &lt;span&gt;amazon-ssm-agent&lt;/span&gt; 등 약 100MB.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 예약 및 여유&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안정적인 운영을 위해 최소 200~300MB의 여유 메모리 필요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;총 필요 메모리&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Apache(500MB) + MySQL(200MB) + 기타(100MB) + 여유(300MB) = 약 &lt;b&gt;1.1~1.3GB&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;트래픽 급증(예: 50 동시 접속) 시 Apache 프로세스 증가로 최대 &lt;b&gt;2~3GB&lt;/b&gt; 필요.&lt;/li&gt;
&lt;li&gt;WordPress의 플러그인(예: WooCommerce)이나 복잡한 테마 사용 시 추가로 500MB~1GB 필요 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OOM 재발 방지 설정&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;어머이건꼭구해야해.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0GeUq/btsP7B3JhLU/0V6w5NlNATgMWLh9eFu6s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0GeUq/btsP7B3JhLU/0V6w5NlNATgMWLh9eFu6s0/img.png&quot; data-alt=&quot;네이버 웹툰 - 호랑이 형님 中 &amp;quot;어멋 이건 꼭 해야해!&amp;quot;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0GeUq/btsP7B3JhLU/0V6w5NlNATgMWLh9eFu6s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0GeUq%2FbtsP7B3JhLU%2F0V6w5NlNATgMWLh9eFu6s0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;433&quot; data-filename=&quot;어머이건꼭구해야해.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네이버 웹툰 - 호랑이 형님 中 &quot;어멋 이건 꼭 해야해!&quot;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) &lt;b&gt;Apache 설정&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756229640454&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;IfModule mpm_prefork_module&amp;gt;
    StartServers          2
    MinSpareServers      2
    MaxSpareServers      4
    MaxClients          15
    MaxRequestsPerChild  100
&amp;lt;/IfModule&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;MaxClients 15&lt;/span&gt;: 각 프로세스 약 25MB RSS 가정 시 15 &amp;times; 25MB = 375MB. 4GB 메모리에서 충분한 여유 제공.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;MaxRequestsPerChild 100&lt;/span&gt;: 메모리 누수 방지.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1756229656689&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo nano /etc/apache2/apache2.conf
sudo apachectl configtest
sudo systemctl reload apache2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) &lt;b&gt;PHP 설정&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756229686527&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;memory_limit = 96M
max_execution_time = 30
error_log = /var/log/php_errors.log
log_errors = On
error_reporting = E_ALL&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용하기 위한 데몬 재시&lt;/p&gt;
&lt;pre id=&quot;code_1756229701736&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo nano /etc/php/7.x/apache2/php.ini
sudo systemctl restart apache2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) &lt;b&gt;MySQL 설정&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756229725907&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[mysqld]
innodb_buffer_pool_size = 128M
query_cache_size = 8M
tmp_table_size = 8M
max_connections = 40&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;innodb_buffer_pool_size = 128M&lt;/span&gt;: 4GB 메모리에서 적절한 데이터베이스 성능 제공.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) &lt;b&gt;스왑 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그에서 스왑이 없었으므로, 1GB 스왑 파일 추가:&lt;/p&gt;
&lt;pre id=&quot;code_1756229745452&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(5) &lt;b&gt;WordPress 최적화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;wp-cron 을 꺼주고 플러그인 정리를 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(6) &lt;b&gt;모니터링&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Monit 설정:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1756229794167&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;check process apache2 with pidfile /var/run/apache2.pid
    start program = &quot;/bin/systemctl start apache2&quot;
    stop program = &quot;/bin/systemctl stop apache2&quot;
    if totalmem &amp;gt; 2500 MB for 2 cycles then restart
    if cpu &amp;gt; 60% for 2 cycles then restart&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재시작&lt;/p&gt;
&lt;pre id=&quot;code_1756229802906&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo nano /etc/monit/monitrc
sudo systemctl restart monit&lt;/code&gt;&lt;/pre&gt;</description>
      <category>WEB/NginX</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/641</guid>
      <comments>https://remoted.tistory.com/641#entry641comment</comments>
      <pubDate>Wed, 27 Aug 2025 02:37:53 +0900</pubDate>
    </item>
    <item>
      <title>[Moyamo] EMMA with Aurora RDS 8.0</title>
      <link>https://remoted.tistory.com/640</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 서론적으로 표현하자면 EMMA 는 인포뱅크에서 만든 문자메세지 발송 서비스이다. AWS aurora RDS 8.0 으로 버전업그레이드를 하게 되면서 여러가지 불편한 사항이 많았는데, 특히 이번 문제는 추가적으로 전체적인 시스템을 간과하지 못해서 일어났던 실수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 moyamo 의 내부 instance를 모듈별로 나눠보자면 아래와 같은데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;moyamo-rest (주로 API 에 대한 부분을 전반적으로 담당하고 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;moyamo-tools (ElasticSearch 라던지, EMMA (Client), EMMA-Server, &lt;s&gt;Scheduler&lt;/s&gt; 를 통합 담당한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특히 이 친구의 경우 moyamo-schedule 인스턴스에서 모듈이 동시에 돌아가게 되는 경우에는 망할놈의 랭킹을 2배로 집계시킨다거나 하는 비정상적인 현상을 발현시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아직까지도 그 퇴사한 개발자들이 해당 인스턴스를 Deprecated 시키고 퇴역시키지 않고, History 조차 남기지 않아서 혼란을 주게 하는 이유는 아직도 파악할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐 등등의 인스턴스가 있지만 대충 이 정도로 포함해본다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Information gathering&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 의아했던것은, moyamo-tools 가 예전에 한번 말썽을 일으킨 적이 있기도 하고 Volume 확장의 문제가 있기도 했어서 재부팅이 한번 들어갔던 적이 있었다. (그 뒤로는 HA 구성을 잡았지만.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 뒤에도 이 안에 있던 EMMA 라는 문자 메세지 발송 서비스는 정상적으로 작동되고 있었는데, 언제인가부터 문자 메세지 발송 서비스가 정상적으로 작동하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 위에서도 써놨지만 이 EMMA 라는 놈의 구조는 총 2가지로 나뉘어져 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;EMMA-Server 라고 불리는 Server 와, 그냥 EMMA로 표시되어 있는 Client&lt;/u&gt; 로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 Server는 정상적으로 작동하고 있는데 (가끔 포트 부분에서 Duplicated 문제가 발생하긴 했지만) Client 에서 다음과 같은 에러를 뿜으면서 작동하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인스턴스 내의 syscheck 라는 shell 을 가동했을 시&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1753578102672&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ubuntu@ip-172-31-40-155:~/workspace/emma$ ./syscheck 
DB[jdbc:mysql://moyamo-product.cluster-c7mmfvbcxzve.ap-northeast-2.rds.amazonaws.com:3306/emma_db?useUnicode=true&amp;amp;noAccessToProcedureBodies=true] Check [NOK]
ib.frame.exception.DBException: Unknown initial character set index '255' received from server. Initial client character set can be forced via the 'characterEncoding' property.||Unknown initial character set index '255' received from server. Initial client character set can be forced via the 'characterEncoding' property.
        at ib.emma.db.GDBConnector.getConnection(GDBConnector.java:159)
        at ib.emma.main.DBCheck.connect(DBCheck.java:75)
        at ib.emma.main.SysCheck.main(SysCheck.java:75)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.exe4j.runtime.LauncherEngine.launch(Unknown Source)
        at com.install4j.runtime.Launcher.main(Unknown Source)
java.sql.SQLException: Unknown initial character set index '255' received from server. Initial client character set can be forced via the 'characterEncoding' property.
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:910)
        at com.mysql.jdbc.Connection.configureClientCharacterSet(Connection.java:2412)
        at com.mysql.jdbc.Connection.initializePropsFromServer(Connection.java:4139)
        at com.mysql.jdbc.Connection.createNewIO(Connection.java:2789)
        at com.mysql.jdbc.Connection.&amp;lt;init&amp;gt;(Connection.java:1555)
        at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:285)
        at java.sql.DriverManager.getConnection(DriverManager.java:664)
        at java.sql.DriverManager.getConnection(DriverManager.java:247)
        at ib.emma.db.GDBConnector.getConnection(GDBConnector.java:155)
        at ib.emma.main.DBCheck.connect(DBCheck.java:75)
        at ib.emma.main.SysCheck.main(SysCheck.java:75)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.exe4j.runtime.LauncherEngine.launch(Unknown Source)
        at com.install4j.runtime.Launcher.main(Unknown Source)
-----------------------------
log4j:WARN No appenders could be found for logger (ib.emma.db.GDBConnector).
log4j:WARN Please initialize the log4j system properly.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 로그에서 저 오류는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;은 &lt;b&gt;MySQL 클라이언트 드라이버와 서버 간의 문자셋 호환 문제에 기반한다.&lt;/b&gt; 구체적으로는, JDBC 드라이버가 서버에서 보낸 문자셋 인덱스 255를 인식하지 못해 생기는 오류다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법으로는 아래와 같은 접근이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;251&quot; data-start=&quot;209&quot; data-ke-size=&quot;size20&quot;&gt;✅ 1. JDBC URL에 characterEncoding 추가&lt;/h4&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;JDBC 연결 문자열에 characterEncoding=UTF-8 또는 useUnicode=true&amp;amp;characterEncoding=UTF-8을 명시적으로 추가&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;- 이미 해당하는 경우에는 EMMA 에 대해서 잘 아는 것은 아니지만 EMMA 가 불러다 사용하는 db.cnf 파일 안에 정의가 되어 있는 것을 확인할 수 있었다.&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;351&quot; data-start=&quot;253&quot; data-ke-size=&quot;size16&quot;&gt;정확하게는 character Set은 EUC-KR 을 사용중이였다. 해당 부분을 바꾸면 안되는 이유는 아마도 추가적으로 통신하는 인포뱅크의 내부 시스템이 EUC-KR을 사용하고 있는 것을 생각해볼 수 있을 것 같다.&lt;/p&gt;
&lt;hr data-end=&quot;463&quot; data-start=&quot;460&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;495&quot; data-start=&quot;465&quot; data-ke-size=&quot;size20&quot;&gt;✅ 2. JDBC 드라이버 버전 확인 및 교체&lt;/h4&gt;
&lt;p data-end=&quot;558&quot; data-start=&quot;497&quot; data-ke-size=&quot;size16&quot;&gt;이 문제는 &lt;b&gt;구형 MySQL JDBC 드라이버&lt;/b&gt;에서 종종 발생한다. 드라이버를 최신 버전으로 교체해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;715&quot; data-start=&quot;560&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;638&quot; data-start=&quot;560&quot;&gt;예를 들어 mysql-connector-java-3.x 또는 5.1.x를 사용 중이라면, &lt;b&gt;8.0.x 이상&lt;/b&gt;으로 교체&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 부분에서 가장 크게 의심했던 것이 Aurora RDS 에 대한 버전 업그레이드 이슈와 동일 선상에 있다고 판단했다. 생각해보면 Aurora RDS의 버전 업그레이드 이후에 moyamo-product(REST) 쪽은 전부다 수정했지만, EMMA 쪽에 대해서는 내가 손댈 수 있는 것을 생각해본 적이 없기에 (정확히는 몰랐다.) 라이브러리 업데이트가 필요하다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 추가적으로 생각했던 부분은 해당하는 EMMA 에 대해서 직접적으로 컴파일을 할 수 없는 상황이기에 lib 에 추가하고 클래스패스 내에서 갱신하는 방법을 고려했다.&lt;/p&gt;
&lt;hr data-end=&quot;720&quot; data-start=&quot;717&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;746&quot; data-start=&quot;722&quot; data-ke-size=&quot;size20&quot;&gt;✅ 3. MySQL 서버 설정 확인&lt;/h4&gt;
&lt;p data-end=&quot;796&quot; data-start=&quot;748&quot; data-ke-size=&quot;size16&quot;&gt;MySQL 서버의 문자셋 설정이 너무 생소한 설정일 수 있을 가능성.&lt;/p&gt;
&lt;p data-end=&quot;796&quot; data-start=&quot;748&quot; data-ke-size=&quot;size16&quot;&gt;확인해 보니 다음과 같았다.&lt;/p&gt;
&lt;p data-end=&quot;796&quot; data-start=&quot;748&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;892&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LhU2W/btsPAwJgCIt/lfZE6wn1biK9mPD8sZwXD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LhU2W/btsPAwJgCIt/lfZE6wn1biK9mPD8sZwXD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LhU2W/btsPAwJgCIt/lfZE6wn1biK9mPD8sZwXD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLhU2W%2FbtsPAwJgCIt%2FlfZE6wn1biK9mPD8sZwXD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;892&quot; height=&quot;161&quot; data-origin-width=&quot;892&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 나의 감대로 버전 이슈가 매우매우 눈에 들어오는 것이 아주 강한 냄새를 날려주고 있었다.&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;진격의 시작&lt;/h2&gt;
&lt;pre id=&quot;code_1753578724211&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;################################################################################
#------------------------------------------------------------------------------# 
# Emma Database Configuration File                                             #
# EMMA Database &amp;Egrave;&amp;macr;&amp;deg;&amp;aelig; &amp;frac14;&amp;sup3;&amp;Aacute;&amp;curren; &amp;AElig;&amp;Auml;&amp;Agrave;&amp;Iuml;                                                 #
# &amp;AElig;&amp;Auml; &amp;Agrave;&amp;Iuml; &amp;cedil;&amp;iacute; : db.cf                                                             #
#------------------------------------------------------------------------------#
# NOTE: &amp;Agrave;&amp;Igrave; &amp;Egrave;&amp;shy;&amp;Agrave;&amp;Iuml;&amp;Agrave;&amp;raquo; &amp;frac14;&amp;ouml;&amp;Aacute;&amp;curren;&amp;Ccedil;&amp;Iuml;&amp;deg;&amp;iacute; &amp;sup1;&amp;Yacute;&amp;iquest;&amp;micro;&amp;micro;&amp;Ccedil;&amp;plusmn;&amp;acirc;&amp;cedil;&amp;brvbar; &amp;iquest;&amp;oslash;&amp;Ccedil;&amp;Iuml;&amp;cedil;&amp;eacute; EMMA&amp;cedil;&amp;brvbar; &amp;raquo;&amp;otilde;&amp;middot;&amp;Icirc; &amp;plusmn;&amp;acirc;&amp;micro;&amp;iquest;&amp;Ccedil;&amp;Oslash;&amp;frac34;&amp;szlig; &amp;Ccedil;&amp;Ntilde;&amp;acute;&amp;Ugrave;.        #
#------------------------------------------------------------------------------#
################################################################################


#*******************************************************************************
# Database Connection Information
#*******************************************************************************

#-------------------------------------------------------------------------------
# &amp;iquest;&amp;not;&amp;deg;&amp;aacute;&amp;Ccedil;&amp;Ograve; DBMS &amp;deg;&amp;sup3;&amp;frac14;&amp;ouml;
#-------------------------------------------------------------------------------
db.count = 1

#-------------------------------------------------------------------------------
# &amp;micro;&amp;yen;&amp;Agrave;&amp;Igrave;&amp;Aring;&amp;Iacute;&amp;ordm;&amp;pound;&amp;Agrave;&amp;Igrave;&amp;frac12;&amp;ordm; &amp;iquest;&amp;not;&amp;deg;&amp;aacute;&amp;Agrave;&amp;raquo; &amp;Agrave;&amp;sect;&amp;Ccedil;&amp;Ntilde; &amp;frac14;&amp;sup3;&amp;Aacute;&amp;curren; 
# (db0.type : 1-Oracle, 2-MSSQL, 3-MySQL, 6-DB2, 7-Tibero, 8-Maria, 9-Sybase)
#-------------------------------------------------------------------------------
db0.type        = 3
db0.driver      = org.gjt.mm.mysql.Driver
#db0.url         = jdbc:mysql://172.27.218.169:3306/emma_db?useUnicode=true&amp;amp;noAccessToProcedureBodies=true
db0.url         = jdbc:mysql://moyamo-product.cluster-c7mmfvbcxzve.ap-northeast-2.rds.amazonaws.com:3306/emma_db?useUnicode=true&amp;amp;noAccessToProcedureBodies=true
db0.charset     = EUC-KR
db0.monum      =&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 대충 해당하는 내용의 일부인데, 딱 보면 알겠지만 드라이버가 굉장히 구식 버전을 사용하고 있다. 해당 드라이버는 2002년에 단종된 드라이버인데, 이걸 아직까지 쓰고 있었다는게 좀 많이 놀라운 부분이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당하는 부분을 다음과 같은 드라이버 클래스로 변경해줬다.&lt;/p&gt;
&lt;pre id=&quot;code_1753578822565&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;db0.driver = com.mysql.cj.jdbc.Driver&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;dbcheck&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 dbcheck 라고 되어있는 shell 파일을 실행했다. (내용도 다 까본건 안비밀)&lt;/p&gt;
&lt;pre id=&quot;code_1753578922379&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ubuntu@ip-172-31-40-155:~/workspace/emma$ ./dbcheck 
ib.frame.exception.DBException: com.mysql.cj.jdbc.Driver||com.mysql.cj.jdbc.Driver
        at ib.emma.db.GDBConnector.getConnection(GDBConnector.java:157)
        at ib.emma.main.DBCheck.connect(DBCheck.java:75)
        at ib.emma.main.DBCheck.main(DBCheck.java:267)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.exe4j.runtime.LauncherEngine.launch(Unknown Source)
        at com.install4j.runtime.Launcher.main(Unknown Source)
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
        at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at ib.emma.db.GDBConnector.getConnection(GDBConnector.java:154)
        at ib.emma.main.DBCheck.connect(DBCheck.java:75)
        at ib.emma.main.DBCheck.main(DBCheck.java:267)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.exe4j.runtime.LauncherEngine.launch(Unknown Source)
        at com.install4j.runtime.Launcher.main(Unknown Source)
-----------------------------
log4j:WARN No appenders could be found for logger (ib.emma.db.GDBConnector).
log4j:WARN Please initialize the log4j system properly.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예상은 했지만 못찾는 문제가 발생했다. 당연히 구식 드라이버를 명시해주고 있었으니, 컴파일을 할 당시에 구식 드라이버를 포함시키는 컴파일을 해서 라이브러리 안쪽에 구식으로 올라가 있을 것이 분명했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753579012775&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;drwxrwxr-x  2 ubuntu ubuntu    4096 Sep  2  2020 .
drwxrwxr-x 13 ubuntu ubuntu    4096 May 23 09:35 ..
-rw-r--r--  1 ubuntu ubuntu 1627539 Sep  2  2020 bcprov-jdk16-138.jar
-rw-r--r--  1 ubuntu ubuntu  121757 Sep  2  2020 commons-dbcp-1.2.2.jar
-rw-r--r--  1 ubuntu ubuntu  261809 Sep  2  2020 commons-lang-2.4.jar
-rw-r--r--  1 ubuntu ubuntu   87077 Sep  2  2020 commons-pool-1.4.jar
-rw-r--r--  1 ubuntu ubuntu  155858 Sep  2  2020 cubrid_jdbc.jar
-rw-r--r--  1 ubuntu ubuntu 2833724 Sep  2  2020 db2jcc.jar
-rw-r--r--  1 ubuntu ubuntu    1015 Sep  2  2020 db2jcc_license_cu.jar
-rw-r--r--  1 ubuntu ubuntu    7192 Sep  2  2020 dbguard_mob.jar
-rw-r--r--  1 ubuntu ubuntu  168644 Sep  2  2020 eb-standard-billing-1.2.15.jar
-rw-r--r--  1 ubuntu ubuntu  910690 Sep  2  2020 emma-3.4.12.jar
-rw-r--r--  1 ubuntu ubuntu   28067 Sep  2  2020 emma-bridge-alerter-1.0.0.jar
-rw-r--r--  1 ubuntu ubuntu   34147 Sep  2  2020 emma-bridge-custom-emma1-1.0.0.jar
-rw-r--r--  1 ubuntu ubuntu   62642 Sep  2  2020 emma-bridge-custom-emma3-1.0.0.jar
-rw-r--r--  1 ubuntu ubuntu     679 Sep  2  2020 emma-was-1.0.0.jar
-rw-r--r--  1 ubuntu ubuntu  481220 Sep  2  2020 google-collect-snapshot-20080820.jar
-rw-r--r--  1 ubuntu ubuntu  190418 Sep  2  2020 gson-2.2.4.jar
-rw-r--r--  1 ubuntu ubuntu  227991 Sep  2  2020 ibframe-1.1.4.jar
-rw-r--r--  1 ubuntu ubuntu  447867 Sep  2  2020 ibpdu-1.1.3.jar
-rw-r--r--  1 ubuntu ubuntu  301946 Sep  2  2020 jtds-1.2.8.jar
-rw-r--r--  1 ubuntu ubuntu  391834 Sep  2  2020 log4j-1.2.15.jar
-rw-r--r--  1 ubuntu ubuntu  287022 Sep  2  2020 msbase.jar
-rw-r--r--  1 ubuntu ubuntu   67115 Sep  2  2020 mssqlserver.jar
-rw-r--r--  1 ubuntu ubuntu   59074 Sep  2  2020 msutil.jar
-rw-r--r--  1 ubuntu ubuntu  540852 Sep  2  2020 mysql-connector-java-5.0.8-bin.jar
-rw-r--r--  1 ubuntu ubuntu 1555682 Sep  2  2020 ojdbc14.jar
-rw-r--r--  1 ubuntu ubuntu  448141 Sep  2  2020 postgresql-8.3-604.jdbc3.jar
-rw-r--r--  1 ubuntu ubuntu  475580 Sep  2  2020 postgresql-8.3-604.jdbc4.jar
-rw-r--r--  1 ubuntu ubuntu   22338 Sep  2  2020 slf4j-api-1.5.6.jar
-rw-r--r--  1 ubuntu ubuntu    9678 Sep  2  2020 slf4j-log4j12-1.5.6.jar
-rw-r--r--  1 ubuntu ubuntu  583286 Sep  2  2020 sqljdbc.jar
-rw-r--r--  1 ubuntu ubuntu  584207 Sep  2  2020 sqljdbc4.jar
-rw-r--r--  1 ubuntu ubuntu  725602 Sep  2  2020 tibero4-jdbc.jar
-rw-r--r--  1 ubuntu ubuntu  137211 Sep  2  2020 unisqljdbc3_0_7.jar&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1주일 굶은 곰마냥 무언가 단서를 찾아서 찾아 해매다가 꿀단지를 발견했다. 그리고 다음과 같은 조치를 취해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 멀쩡하게 살고있던 녀석은 backup 본으로 밀어넣어주고&lt;/p&gt;
&lt;pre id=&quot;code_1753579173023&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mv ~/workspace/emma/lib/mysql-connector-java-5.0.8-bin.jar ~/workspace/emma/lib/mysql-connector-java-5.0.8-bin.jar.bak&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 드라이버를 낼름 가져와서 클래스패스 내에서 다시 연결시켜줬다.&lt;/p&gt;
&lt;pre id=&quot;code_1753579137280&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~/workspace/emma/lib

wget https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.3.0/mysql-connector-j-8.3.0.jar

ln -s mysql-connector-j-8.3.0.jar mysql-connector-java.jar

cd ~/workspace/emma
java -cp &quot;.:./lib/*&quot; ib.emma.main.DBCheck&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;UTF-8을 못알아 든는 친구가 존재했다.&lt;/h4&gt;
&lt;pre id=&quot;code_1753579255847&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ubuntu@ip-172-31-40-155:~/workspace/emma$ java -cp &quot;.:./lib/*&quot; ib.emma.main.DBCheck
log4j:WARN No appenders could be found for logger (ib.emma.db.GDBConnector).
log4j:WARN Please initialize the log4j system properly.
Console 한글 테스트
Driver Version: mysql-connector-j-8.3.0 (Revision: 805f872a57875f311cb82487efcfb070411a3fa0)
Server Version: 8.0.32
DB connection check is completed.
DB privileges check is completed.
query :  call sp_em_smt_tran_select(?, ?, ?, ?, ?); 
55987 / 01066814446 / [???] ???? 942677? ??? ???.
55988 / 01066814446 / [???] ???? 282570? ??? ???.
55989 / 01025617240 / [???] ???? 874947? ??? ???.
55990 / 01031871559 / [???] ???? 380585? ??? ???.
55991 / 01027772119 / [???] ???? 821225? ??? ???.
55992 / 01027772119 / [???] ???? 940578? ??? ???.
55993 / 01027772119 / [???] ???? 558572? ??? ???.
55994 / 01037710374 / [???] ???? 278919? ??? ???.
55995 / 01033570189 / [???] ???? 674359? ??? ???.
55996 / 01033570189 / [???] ???? 763137? ??? ???.
55997 / 01033570189 / [???] ???? 360590? ??? ???.
55998 / 01039008813 / [???] ???? 720691? ??? ???.
55999 / 01039008813 / [???] ???? 542344? ??? ???.
56000 / 01039008813 / [???] ???? 463278? ??? ???.
56001 / 01039008813 / [???] ???? 905421? ??? ???.
56002 / 01047992956 / [???] ???? 351778? ??? ???.
56003 / 01047992956 / [???] ???? 929949? ??? ???.
SMSMT check is completed.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 데이터베이스 체크는 신박하게 잘 돌아갔기 때문에, 돌아갈 것으로 예상하고 있었는데 db.cnf 파일 안에 EUC-KR 을 UTF-8 로 바꿔주었더니 문자를 받을 때에 한글이 ??? 로 오는 문제가 발생됬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 EUC-KR로 재변경을 하는 부분이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 shell로 만들어진 파일이 2가지가 존재했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;emma 와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;emmasvc 라는 파일 이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;emma의 경우 데몬화시키지 않은 파일로써, 해당 쉘 파일을 실행시키면 컴파일된 프로그램이 프로세스가 되어 가동되고 화면에 그대로 보여지는 파일을 작성해 놓은 것이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 emmasvc 의 경우 start, stop, status 인 추가적인 options 를 포함하고 있는데, start를 시키면 nohup 이 걸리면서 데몬화가 되어지고 서비스로 가동되게 되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다만 왜때문에 로그가 안남았는지는 모르겠으나 log4j에 대한 적절한 설정이 없었던 것 같은 느낌이 스물스물?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 = 문자메세지 잘 오게 정상적으로 잘 고쳤다.&lt;/p&gt;</description>
      <category>Java</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/640</guid>
      <comments>https://remoted.tistory.com/640#entry640comment</comments>
      <pubDate>Sun, 27 Jul 2025 10:26:32 +0900</pubDate>
    </item>
    <item>
      <title>[Android/2023-06-09] Shop login Failure issue</title>
      <link>https://remoted.tistory.com/639</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음-2025-04-03-1117.png&quot; data-origin-width=&quot;7870&quot; data-origin-height=&quot;3680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MNIVN/btsNFAS4prp/M4l35KBTborCI3IFeKVERK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MNIVN/btsNFAS4prp/M4l35KBTborCI3IFeKVERK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MNIVN/btsNFAS4prp/M4l35KBTborCI3IFeKVERK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMNIVN%2FbtsNFAS4prp%2FM4l35KBTborCI3IFeKVERK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;7870&quot; height=&quot;3680&quot; data-filename=&quot;제목 없음-2025-04-03-1117.png&quot; data-origin-width=&quot;7870&quot; data-origin-height=&quot;3680&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;고도몰 기반으로 된 홈페이지에서 로그인이 지속적으로 풀리는 이슈가 발생했었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;안드로이드도 파보고, Spring쪽도 파보고 하다가 결국은 알고보니&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;고도몰 내의 js 가 잘못된 것이였고 (하지만 Shop은 웹뷰 형태로 고도몰을 불러다가 쓰는 것이였기에)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;고도몰에서 소스코드가 잘못된 부분을 찾아 해매다가 찾아내서 해결한 이후에 샵 로그인이 해결되었던 문제가 있었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(그래서 결국 구매하기 시에 로그인 풀렸던 이슈를 고쳤더랬다.)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아무래도 샵에서 씨앗을 판매하는데 씨앗을 못팔으니 서비스에 원활하지 않은 문제가 매우매우 컷다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ANDROID</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/639</guid>
      <comments>https://remoted.tistory.com/639#entry639comment</comments>
      <pubDate>Tue, 29 Apr 2025 23:05:58 +0900</pubDate>
    </item>
    <item>
      <title>[FCM HTTP v1]  Push Notification Payload 와 문제 해결</title>
      <link>https://remoted.tistory.com/638</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;400 Bad Request 가 나면서 지속적으로 망할놈의 Bad Request 만 발견되던 상황이였고, 이런 부분은 아래와 같이 해결할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?hl=ko&amp;amp;_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22alt%22%3A%22json%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22data%22%3A%7B%22title%22%3A%22%3C%EA%B0%80%EC%9D%84%EC%97%90%20%EC%8B%AC%EB%8A%94%20%EA%B5%AC%EA%B7%BC%3E%20%EC%95%8C%EB%A6%AC%EC%9B%80%202%EA%B0%9C%20%ED%92%88%EC%A2%85%22%2C%22description%22%3A%22test%20data%20close%22%2C%22id%22%3A%2215170295%22%2C%22photoUrl%22%3A%22%22%2C%22referenceId%22%3A%2215170295%22%2C%22referenceType%22%3A%22question%22%2C%22resourceType%22%3A%22question%22%2C%22resourceId%22%3A%2215170295%22%7D%2C%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%7D%2C%22validate_only%22%3Afalse%7D%7D&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729367074252&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Method: projects.messages.send &amp;nbsp;|&amp;nbsp; Firebase Cloud Messaging REST API&quot; data-og-description=&quot;&quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?hl=ko&amp;amp;_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22alt%22%3A%22json%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22data%22%3A%7B%22title%22%3A%22%3C%EA%B0%80%EC%9D%84%EC%97%90%20%EC%8B%AC%EB%8A%94%20%EA%B5%AC%EA%B7%BC%3E%20%EC%95%8C%EB%A6%AC%EC%9B%80%202%EA%B0%9C%20%ED%92%88%EC%A2%85%22%2C%22description%22%3A%22test%20data%20close%22%2C%22id%22%3A%2215170295%22%2C%22photoUrl%22%3A%22%22%2C%22referenceId%22%3A%2215170295%22%2C%22referenceType%22%3A%22question%22%2C%22resourceType%22%3A%22question%22%2C%22resourceId%22%3A%2215170295%22%7D%2C%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%7D%2C%22validate_only%22%3Afalse%7D%7D&quot; data-og-url=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?hl=ko&amp;amp;_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22alt%22%3A%22json%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22data%22%3A%7B%22title%22%3A%22%3C%EA%B0%80%EC%9D%84%EC%97%90%20%EC%8B%AC%EB%8A%94%20%EA%B5%AC%EA%B7%BC%3E%20%EC%95%8C%EB%A6%AC%EC%9B%80%202%EA%B0%9C%20%ED%92%88%EC%A2%85%22%2C%22description%22%3A%22test%20data%20close%22%2C%22id%22%3A%2215170295%22%2C%22photoUrl%22%3A%22%22%2C%22referenceId%22%3A%2215170295%22%2C%22referenceType%22%3A%22question%22%2C%22resourceType%22%3A%22question%22%2C%22resourceId%22%3A%2215170295%22%7D%2C%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%7D%2C%22validate_only%22%3Afalse%7D%7D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?hl=ko&amp;amp;_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22alt%22%3A%22json%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22data%22%3A%7B%22title%22%3A%22%3C%EA%B0%80%EC%9D%84%EC%97%90%20%EC%8B%AC%EB%8A%94%20%EA%B5%AC%EA%B7%BC%3E%20%EC%95%8C%EB%A6%AC%EC%9B%80%202%EA%B0%9C%20%ED%92%88%EC%A2%85%22%2C%22description%22%3A%22test%20data%20close%22%2C%22id%22%3A%2215170295%22%2C%22photoUrl%22%3A%22%22%2C%22referenceId%22%3A%2215170295%22%2C%22referenceType%22%3A%22question%22%2C%22resourceType%22%3A%22question%22%2C%22resourceId%22%3A%2215170295%22%7D%2C%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%7D%2C%22validate_only%22%3Afalse%7D%7D&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Method: projects.messages.send &amp;nbsp;|&amp;nbsp; Firebase Cloud Messaging REST API&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 위의 해당하는 URL로 가게 되면 우측 창에 Payload 를 전개할 수 있는 창이 있는데, 해당하는 부분에 파라미터들을 추가하면서 실험해볼 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 해결하기 전까지는 어떤 삽질들을 했을까?&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Postman을 이용한 삽질&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 Payload&amp;nbsp; 를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST 에 소스코드에서 추가했던 바처럼 message 의 send 를 보낼 수 있는 엔드포인트를 postman의 상단에 정의한다&lt;/p&gt;
&lt;pre id=&quot;code_1729367345957&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;POST https://fcm.googleapis.com/v1/projects/moyamo-plus/messages:send&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Request Body 를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FCM HTTP v1 Payload 에서는 공통 부분을 정의할 때에는 (안드로이드와 iOS에 대해서 동시에 발송할 때에는) 반드시 message 하부에 notification 의 body가 정의되어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1729367256914&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;message&quot;:{
        &quot;notification&quot;:{
            &quot;title&quot;:&quot;이름이 뭘까요?&quot;,
            &quot;body&quot;:&quot;알림테스트에 들어갑니다&quot;
        },
        &quot;token&quot;:&quot;fG1sB-i_TRWsI1W9vjL0ql:APA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL&quot;,
        &quot;android&quot;:{
            &quot;notification&quot;:{
                &quot;click_action&quot;:&quot;.MainActivity&quot;,
                &quot;sound&quot;:&quot;default&quot;
            }
        }
    },
    &quot;validate_only&quot;:false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;android의 경우에는 notification 이 있고 title 과 body가 있을 경우 해당하는 속성을 override 해서 사용하므로 해당하는 부분만 참고하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;주의해야 할 부분에 대한 정의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Common Notification에 대한 Payload&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FCM HTTP v1 Payload 에서는 공통 부분을 정의할 때에는 (안드로이드와 iOS에 대해서 동시에 발송할 때에는) 반드시 message 하부에 notification 의 body가 정의되어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Android Notification 과 Common Notification의 Conflict&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;message의 common noficatication field 와 android 에서 해당하는 부분을 동시에 정의했을 경우 Push Notification 이 발송되었을 때, Android 내에서 Main Activity 로 가서 intent-filter 에 의해서 발동하는 clickAction 이 정상적으로 발동되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Main Activity 로 향하는 부분에 대한 정의만 필요하다면 굳이 Android 에 대한 부분을 정의하면서 최상단에 있는 Common Notification field 를 정의하진 말자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Custom Notication 에 대한 가능 여부&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확하게는 clickAction에 대한 유도라기 보다, Push Notification 에 대한 Custom Notification의 가능 여부는 당연히 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 부분에 대한 사용 중에서 Data property 를 사용하면 되고, Payload 는 다음과 같이 전개하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1729367696671&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;message&quot;: {
    &quot;data&quot;: {
      &quot;title&quot;: &quot;&amp;lt;가을에 심는 구근&amp;gt; 알리움 2개 품종&quot;,
      &quot;description&quot;: &quot;test data close&quot;,
      &quot;id&quot;: &quot;15170295&quot;,
      &quot;photoUrl&quot;: &quot;&quot;,
      &quot;referenceId&quot;: &quot;15170295&quot;,
      &quot;referenceType&quot;: &quot;question&quot;,
      &quot;resourceType&quot;: &quot;question&quot;,
      &quot;resourceId&quot;: &quot;15170295&quot;
    },
    &quot;token&quot;: &quot;fG1sB-i_TRWsI1W9vjL0ql:APA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL&quot;
  },
  &quot;validate_only&quot;: false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이와같이 정의했을 경우 안드로이드에서 받아서 처리하는 Json에 대한 처리는 Android 내부에서 담당하게 되어있다.&lt;/p&gt;</description>
      <category>Java/Spring Boot JPA</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/638</guid>
      <comments>https://remoted.tistory.com/638#entry638comment</comments>
      <pubDate>Sun, 20 Oct 2024 04:56:34 +0900</pubDate>
    </item>
    <item>
      <title>[FCM HTTP v1] 400 Bad Request 와 문제 해결</title>
      <link>https://remoted.tistory.com/637</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 상황 요약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FCM 이 deprecated 되면서 2024년 6월 4일부로 완전히 종료되었다고 하지만 최종적으로 Firebase 내에서는 9월 4일날 완전히 공식 Support 가 종료된 것을 확인함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 = 푸시 데이터 알림이 작동하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 예전에 사용하던 FCM 에 대한 부분을 드러내고 FCM HTTP v1 을 강제적으로 사용해야 할 수 밖에 없는 상황에 놓으게 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;중간 삽질&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Firebase 에서 Cloud Function 이나 Google Cloud Console 에서 이것 저것을 실어서 product 를&amp;nbsp; 가동중인 사용자라면 모를까 일반적인 사용자라면 해당하는 방법으로 가동되지 않는다. 따라서 Firebase 내에서 비공개 키 (private key) 에 관련된 json 파일을 받아서 importing 해야하고, 이 부부을 통해서 OAuth2 token 을 따다가 Credential token으로 넣어줘야 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 앱에서 푸시 알림을 보내려면 2가지의 토큰이 준비되어야 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 앱 내에서 사용자마다 사용하는 push Token. 이 경우는 Firebase 에서 getInstance 에 의하여 토큰을 제공해주고, 해당 부분은 repository 에 정상적으로 저장되는 부분을 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Bearer 로 Firebase와 연동해서 Oauth2 에 대한 토큰을 딴 뒤에 해당 부분을 통하여 키 인증을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 아래와 같은 상황이 발생하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1728222761090&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Admin][2024-10-06 13:04:22][DEBUG][FcmPushModule.java][sendPushMsg(370)] : Send : {&quot;message&quot;:{&quot;notification&quot;:{&quot;title&quot;:&quot;아이리스(경기용인)님이 새 댓글을 남겼습니다.&quot;,&quot;body&quot;:&quot;#가우라&quot;},&quot;token&quot;:&quot;ePk90xxfSTKDpaKZQPC22_:APA91bF_4nVQWJgeX50szAta-VD6R1mXrKH552DIVPXQUuosdwSINXjd8PgIBd2_zpIKE4yjpSV5adUIqo50h0uhN_T-63_S2poVVQB9eFRivxZdiADLj0RqFxfnjZ1ycwZJefxKbQVl&quot;,&quot;android&quot;:{&quot;notification&quot;:{&quot;click_action&quot;:&quot;.MainActivity&quot;,&quot;sound&quot;:&quot;default&quot;}}},&quot;validate_only&quot;:false}, topic null
[Admin][2024-10-06 13:04:22][DEBUG][FcmPushModule.java][sendPushMsg(390)] : Sending 'POST' request to URL : https://fcm.googleapis.com/v1/projects/moyamo-plus/messages:send
[Admin][2024-10-06 13:04:22][DEBUG][FcmPushModule.java][sendPushMsg(391)] : Post parameters : &quot;{\&quot;message\&quot;:{\&quot;notification\&quot;:{\&quot;title\&quot;:\&quot;아이리스(경기용인)님이 새 댓글을 남겼습니다.\&quot;,\&quot;body\&quot;:\&quot;#가우라\&quot;},\&quot;token\&quot;:\&quot;ePk90xxfSTKDpaKZQPC22_:APA91bF_4nVQWJgeX50szAta-VD6R1mXrKH552DIVPXQUuosdwSINXjd8PgIBd2_zpIKE4yjpSV5adUIqo50h0uhN_T-63_S2poVVQB9eFRivxZdiADLj0RqFxfnjZ1ycwZJefxKbQVl\&quot;,\&quot;android\&quot;:{\&quot;notification\&quot;:{\&quot;click_action\&quot;:\&quot;.MainActivity\&quot;,\&quot;sound\&quot;:\&quot;default\&quot;}}},\&quot;validate_only\&quot;:false}&quot;
[Admin][2024-10-06 13:04:22][ERROR][FcmPushModule.java][sendPushMsg(399)] : ChatPushModule
java.io.IOException: Server returned HTTP response code: 400 for URL: https://fcm.googleapis.com/v1/projects/moyamo-plus/messages:send
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1902)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1500)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268)
        at net.infobank.moyamo.push.module.FcmPushModule.responseBodyLog(FcmPushModule.java:259)
        at net.infobank.moyamo.push.module.FcmPushModule.sendPushMsg(FcmPushModule.java:392)
        at net.infobank.moyamo.service.PushNotificationServiceImpl.lambda$sendRequest$0(PushNotificationServiceImpl.java:194)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:750)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 요약하자니 여러 부분에 있어서 Payload 구성이 잘못된 것이냐 아니냐에 대한 판단 1과 파라미터에 대한 판단 2가 이루어지는데, 코드를 뜯어보면서 본 결과로는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Android 에 실리는 Notification 에 대한 부분에서 data 에 대한 부분을 보낼 필요가 없을 경우에 맘대로 보내게 되면 신나게 에러를 뱉게 된다. 따라서 data : null 로 보내기 보다는, 실험한다고 해서 data : null로 보내지 말 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Firebase 쪽에서 제공해주는 부분에 의해서 clickAction 과 click_action, validateOnly 와 validate_only&amp;nbsp; 버전으로 두 개의 property 가 정상적으로 똑같이 Response 를 보내주고 있으나 references 에 있는 대로 validate_only 를 사용하는 것이 나을 것 같아 그렇게 사용하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 나오는 Bad Request 400 덕에 본능적으로 싸한 부분을 느끼고 여러 부분을 검토하다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Firebase SDK 가 Google Cloud Messaging API 에 대한 role 을 가지고 있지 않을 것 같기에 확인하는 목적용으로 아래와 같이 role을 수정해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lyuAL/btsJU9NkY42/GwfkMrmw8Kt7rEFKT0SyZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lyuAL/btsJU9NkY42/GwfkMrmw8Kt7rEFKT0SyZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lyuAL/btsJU9NkY42/GwfkMrmw8Kt7rEFKT0SyZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlyuAL%2FbtsJU9NkY42%2FGwfkMrmw8Kt7rEFKT0SyZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;257&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Service Account 를 확인한 뒤에 Google Cloud Console에서 &quot;IAM &amp;amp; Admin.&quot; 을 찾아낸다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-10-06 222132.png&quot; data-origin-width=&quot;1465&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lEpiT/btsJV6IOnW7/kSAJMCgzfVcgDaWT2JbX50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lEpiT/btsJV6IOnW7/kSAJMCgzfVcgDaWT2JbX50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lEpiT/btsJV6IOnW7/kSAJMCgzfVcgDaWT2JbX50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlEpiT%2FbtsJV6IOnW7%2FkSAJMCgzfVcgDaWT2JbX50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1465&quot; height=&quot;850&quot; data-filename=&quot;스크린샷 2024-10-06 222132.png&quot; data-origin-width=&quot;1465&quot; data-origin-height=&quot;850&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 아직 log에서 Bad Request 가 확인되지 않았기 때문에 Log 가 뜨면 또 확인해줘야한다 ^^...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여하튼 Issue Tracking 의 단계는 아래와 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Invalid FCM Token&lt;/b&gt;: Ensure the token &quot;eK-yrDlcTrqwDKeBpRdldR:APA91bHjBPJfZuuGWQpQh0uAW2nf_2S-f5OF4nocBrgV9IRada4L609ftVKr8ocTChCaE5Bb6rTzH9LJcrL11ovOoLI9OPFhoFNWGWZMQW9B6Qmtio0wl4ZFrLGi3Om1kUu_wdoX_HFc&quot; is valid and not expired or malformed.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Missing Permissions&lt;/b&gt;: Ensure your Firebase Cloud Messaging (FCM) API key and server credentials are correctly set up in your project.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Incorrect URL&lt;/b&gt;: Double-check that the request is being sent to the correct FCM endpoint (&lt;a href=&quot;https://fcm.googleapis.com/v1/projects/&quot;&gt;https://fcm.googleapis.com/v1/projects/&lt;/a&gt;{project_id}/messages:send).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째로 확인사살한 부분은 FCM Token 에 대한 부분이고 이 부분은 당연히 작동했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이후에 Missing Permission을 잡았고, Incorrect URL 에 대한 부분은 당연히 문제가 없는 부분인데 이래도 문제가 있으면 진짜 음..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/Spring Boot JPA</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/637</guid>
      <comments>https://remoted.tistory.com/637#entry637comment</comments>
      <pubDate>Sun, 6 Oct 2024 23:02:51 +0900</pubDate>
    </item>
    <item>
      <title>Method: projects.messages.send</title>
      <link>https://remoted.tistory.com/636</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-text=&quot;Authorization scopes&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;FCM HTTP v1 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Def&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;http-request&quot; data-text=&quot;HTTP request&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;HTTP request&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST &lt;a href=&quot;https://fcm.googleapis.com/v1/&quot;&gt;https://fcm.googleapis.com/v1/&lt;/a&gt;{parent=projects/*}/messages:send&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The URL uses&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://google.aip.dev/127&quot;&gt;gRPC Transcoding&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;syntax.&lt;/p&gt;
&lt;h3 id=&quot;path-parameters&quot; data-text=&quot;Path parameters&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Path parameters&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;Parameters
&lt;table id=&quot;body.PATH_PARAMETERS-table&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;body.PATH_PARAMETERS.parent&quot;&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;parent&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span&gt;string&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Required. It contains the Firebase project id (i.e. the unique identifier for your Firebase project), in the format of&lt;span&gt;&amp;nbsp;&lt;/span&gt;projects/{project_id}. For legacy support, the numeric project number with no padding is also supported in the format of&lt;span&gt;&amp;nbsp;&lt;/span&gt;projects/{project_number}.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&quot;request-body&quot; data-text=&quot;Request body&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Request body&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The request body contains data with the following structure:&lt;/p&gt;
&lt;div&gt;JSON representation
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;Fields
&lt;table id=&quot;body.request_body.FIELDS-table&quot; style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr id=&quot;body.request_body.FIELDS.validate_only&quot;&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;validate_only&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Flag for testing the request without actually delivering the message.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;body.request_body.FIELDS.message&quot;&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;message&lt;/td&gt;
&lt;td style=&quot;text-align: left;&quot;&gt;&lt;span&gt;object (&lt;a style=&quot;color: #000000;&quot; href=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Message&quot;&gt;Message&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Required. Message to send.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 id=&quot;response-body&quot; data-text=&quot;Response body&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Response body&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;If successful, the response body contains an instance of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Message&quot;&gt;Message&lt;/a&gt;.&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-text=&quot;Authorization scopes&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-text=&quot;Authorization scopes&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 id=&quot;authorization-scopes&quot; style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-text=&quot;Authorization scopes&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Authorization scopes&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Requires one of the following OAuth scopes:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.googleapis.com/auth/firebase.messaging&quot;&gt;https://www.googleapis.com/auth/firebase.messaging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.googleapis.com/auth/cloud-platform&quot;&gt;https://www.googleapis.com/auth/cloud-platform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;For more information, see the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://cloud.google.com/docs/authentication/&quot;&gt;Authentication Overview&lt;/a&gt;.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Test - Try this method in right side bar&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%2C%22notification%22%3A%7B%22title%22%3A%22fasdfadsfadsf%22%2C%22body%22%3A%22adfadfadsfadsf%22%7D%7D%2C%22validateOnly%22%3Afalse%7D%7D&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%2C%22notification%22%3A%7B%22title%22%3A%22fasdfadsfadsf%22%2C%22body%22%3A%22adfadfadsfadsf%22%7D%7D%2C%22validateOnly%22%3Afalse%7D%7D&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727719351118&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Method: projects.messages.send &amp;nbsp;|&amp;nbsp; Firebase Cloud Messaging REST API&quot; data-og-description=&quot;&quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%2C%22notification%22%3A%7B%22title%22%3A%22fasdfadsfadsf%22%2C%22body%22%3A%22adfadfadsfadsf%22%7D%7D%2C%22validateOnly%22%3Afalse%7D%7D&quot; data-og-url=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%2C%22notification%22%3A%7B%22title%22%3A%22fasdfadsfadsf%22%2C%22body%22%3A%22adfadfadsfadsf%22%7D%7D%2C%22validateOnly%22%3Afalse%7D%7D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send?_gl=1*zoh55r*_up*MQ..*_ga*MTU1Nzk1ODEwNS4xNzI3NzE1NjM0*_ga_CW55HF8NVT*MTcyNzcxNTYzNC4xLjAuMTcyNzcxNTYzNC4wLjAuMA..&amp;amp;apix_params=%7B%22parent%22%3A%22projects%2Fmoyamo-plus%22%2C%22resource%22%3A%7B%22message%22%3A%7B%22token%22%3A%22fG1sB-i_TRWsI1W9vjL0ql%3AAPA91bFq8CvJ14HqaWDBDO7b4qNwk3avS4_RP849X-s801cIjXgRgfTHLULLpojpXI9tACW1hDmZEkINjXJpU6oh4y4YTIEm3k7LvYQO8Z0zOrkYEAIY1E3bbPtB77y3YhjALR0JF8XL%22%2C%22notification%22%3A%7B%22title%22%3A%22fasdfadsfadsf%22%2C%22body%22%3A%22adfadfadsfadsf%22%7D%7D%2C%22validateOnly%22%3Afalse%7D%7D&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Method: projects.messages.send &amp;nbsp;|&amp;nbsp; Firebase Cloud Messaging REST API&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;</description>
      <category>Java</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/636</guid>
      <comments>https://remoted.tistory.com/636#entry636comment</comments>
      <pubDate>Tue, 1 Oct 2024 03:03:07 +0900</pubDate>
    </item>
    <item>
      <title>FCM HTTP v1 Firewall Port bound</title>
      <link>https://remoted.tistory.com/635</link>
      <description>&lt;h2 id=&quot;messaging-ports-and-your-firewall&quot; style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-text=&quot;FCM ports and your firewall&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;span&gt;FCM&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;ports and your firewall&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;If your organization has a firewall to restrict traffic to or from the Internet, you need to configure it to allow mobile devices to connect with&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;FCM&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;in order for devices on your network to receive messages.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;FCM&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;typically uses port 5228, but it sometimes uses 443, 5229, and 5230.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;For devices connecting on your network,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;FCM&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;doesn't provide specific IPs because our IP range changes too frequently and your firewall rules could get out of date, impacting your users' experience. Ideally, allowlist ports 5228-5230 &amp;amp; 443 with no IP restrictions. However, if you must have an IP restriction, you should allowlist all of the IP addresses listed in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://cloud.google.com/vpc/docs/configure-private-google-access#ip-addr-defaults&quot;&gt;goog.json&lt;/a&gt;. This large list is updated regularly, and you are recommended to update your rules on a monthly basis. Problems caused by firewall IP restrictions are often intermittent and difficult to diagnose.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;We do offer a set of domain names that can be allowlisted instead of IP addresses. Those hostnames are listed below. If we start using additional hostnames, we will update the list here. Using domain names for your firewall rule may or may not be functional in your firewall device.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP ports to open:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;5228&lt;/li&gt;
&lt;li&gt;5229&lt;/li&gt;
&lt;li&gt;5230&lt;/li&gt;
&lt;li&gt;443&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hostnames to open:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mtalk.google.com&lt;/li&gt;
&lt;li&gt;mtalk4.google.com&lt;/li&gt;
&lt;li&gt;mtalk-staging.google.com&lt;/li&gt;
&lt;li&gt;mtalk-dev.google.com&lt;/li&gt;
&lt;li&gt;alt1-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt2-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt3-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt4-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt5-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt6-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt7-mtalk.google.com&lt;/li&gt;
&lt;li&gt;alt8-mtalk.google.com&lt;/li&gt;
&lt;li&gt;android.apis.google.com&lt;/li&gt;
&lt;li&gt;device-provisioning.googleapis.com&lt;/li&gt;
&lt;li&gt;firebaseinstallations.googleapis.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Network Address Translation and/or Stateful Packet Inspection firewalls:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;If your network implements Network Address Translation (NAT) or Stateful Packet Inspection (SPI), implement a 30 minute or larger timeout for our connections over ports 5228-5230. This enables us to provide reliable connectivity while reducing the battery consumption of your users' mobile devices.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;In normally, Do not define especially hostname without ports.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/635</guid>
      <comments>https://remoted.tistory.com/635#entry635comment</comments>
      <pubDate>Mon, 30 Sep 2024 17:06:19 +0900</pubDate>
    </item>
  </channel>
</rss>