<?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>Sun, 21 Jun 2026 13:18:31 +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>[Moyamo] How to fix Google Cloud console 'suspending' issue</title>
      <link>https://remoted.tistory.com/645</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;바야흐로 문제를 정의하고 나니, 사태는 약 2월달 중후반으로 거슬러 올라가자면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아니 개발자님 앱 알림이 안오는데여?&lt;br /&gt;&lt;/span&gt;&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;/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/d94741/dJMcaijiZpW/SpOCQtEQjRaSIP7KHNKIn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d94741/dJMcaijiZpW/SpOCQtEQjRaSIP7KHNKIn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d94741/dJMcaijiZpW/SpOCQtEQjRaSIP7KHNKIn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd94741%2FdJMcaijiZpW%2FSpOCQtEQjRaSIP7KHNKIn1%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;422&quot; height=&quot;265&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;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;Google Cloud의 Firebase Messaging 이 작동할 수 없는 상태로 되어버린 거시고?&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;blockquote data-ke-style=&quot;style2&quot;&gt;님 프로젝트 API키가 노출되었거나 하이재킹 이용되고 있는데 왜 점검안함? 정신안차림?&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;ㅓ... 오만가지 생각이 지나가면서 나는 어디 부분에서 노출되었나 생각했고, 일단 Claim을 하면서 다음과 같이 문서를 보냈다.&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;span&gt;Dear Google Cloud Trust &amp;amp; Safety Team,&lt;/span&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;span&gt;Thank you for your response.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Unfortunately, because the project remains suspended, I have been unable to access the Google Cloud Console to review logs, inspect resources, or identify the exact activity that triggered the violation.&lt;/span&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;span&gt;However, after reviewing my development and deployment practices, I believe the most likely cause is that a service account credential or API key associated with the project may have been unintentionally exposed in the past. This project has been used for a mobile application backend and Firebase Cloud Messaging (FCM) related development and testing.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;I have not intentionally created any unauthorized resources, cryptocurrency mining workloads, automated abuse systems, or any activity that would violate Google Cloud policies. If unauthorized activity occurred, I believe it was performed by a third party using compromised credentials.&lt;/span&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;span&gt;Because access to the project is currently restricted, I am unable to verify which credentials or resources may have been affected. If access is restored, I will immediately:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Audit all service accounts and revoke any existing keys.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Rotate all credentials and API keys associated with the project.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Review IAM permissions and remove any unnecessary access.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Inspect all resources for unauthorized deployments and remove them.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Implement additional controls to prevent future credential exposure.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;If possible, I would appreciate any additional information regarding the specific resource, service, credential, or activity that triggered the violation, as this would help me investigate and remediate the issue more effectively.&lt;/span&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;span&gt;Thank you for your time and assistance. I am committed to resolving the issue and ensuring compliance with Google Cloud policies.&lt;/span&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;span&gt;Best regards,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TaeHwi Lee&lt;/span&gt;&lt;/p&gt;
&lt;p 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;span&gt;대충 요약 =&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;형들이 조지라 그래서 조지러 갔는데 막혀있다고 현기증난다구요!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v2gcq/dJMcaccjL6Z/G7WRuoZaJXox9Ekj6EpvM0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v2gcq/dJMcaccjL6Z/G7WRuoZaJXox9Ekj6EpvM0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v2gcq/dJMcaccjL6Z/G7WRuoZaJXox9Ekj6EpvM0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv2gcq%2FdJMcaccjL6Z%2FG7WRuoZaJXox9Ekj6EpvM0%2Fimg.jpg&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;376&quot; height=&quot;311&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;523&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대충 위와 같이 보내고 사건은 일단락 되었었는데, 약 1주일이 걸렸었더랬다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 이후로 IAM 들어가서 권한 조절하고&lt;/li&gt;
&lt;li&gt;Logging 들어가서 이상한거 있나 살펴보고&lt;/li&gt;
&lt;li&gt;Key Rotation 시키고&lt;/li&gt;
&lt;li&gt;신기한건 여기서 Gemini API 가 실패율이 95%가 떳었다는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;(내가 구현한 챗봇은 잘 작동 중인데??? 여하튼 대표님에게 연락해보니 API Key도 문제없다함.) &lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;(심지어 2FA 계정으로 로그인하는데 이런일이 생긴다고?)&lt;/span&gt;&lt;/span&gt;&lt;/div&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 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;대략 2개의 API를 발급해서 사용하고 있었던 것 같은데, 이 때문인지 몰라도 또다시 Violation 으로 인하여 중지되었다는 알림이 5월 말 떠버리기 시작한 것&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;
&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;결국 나는 마지막 술수를 쓰기에 이르렀는데&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;b&gt;이른바 Google Cloud Community에 가서 어그로 끌기 작전이다.&lt;/b&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;왜 그런고 하니? 내가 왜때문에 처리안해줌? 하면서 티켓을 여러개 따니까&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;님 ㅅㄱ 안해줌. 말이 너무 많음&quot;&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;
&lt;p style=&quot;text-align: center;&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;1271&quot; data-origin-height=&quot;1471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKOOHb/dJMcaiXQAu3/tKxt42SpCuDfn51inROT4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKOOHb/dJMcaiXQAu3/tKxt42SpCuDfn51inROT4K/img.png&quot; data-alt=&quot;대충 눈나 도와줘 뀨우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKOOHb/dJMcaiXQAu3/tKxt42SpCuDfn51inROT4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKOOHb%2FdJMcaiXQAu3%2FtKxt42SpCuDfn51inROT4K%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;634&quot; height=&quot;734&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;1471&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 기적적으로 봉인 해제에 들어갔고, 금일 부로 FCM Push 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;그리하여 API Key Service 관리를 들어가보니? 왜때문에 예전에 한번 발급하고 사용하지 않는 키가 돌아다니고 있는것이 아닌가?&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;2253&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nY84B/dJMcaaew82V/yc2aEY3qGaHDti7EPfEMn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nY84B/dJMcaaew82V/yc2aEY3qGaHDti7EPfEMn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nY84B/dJMcaaew82V/yc2aEY3qGaHDti7EPfEMn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnY84B%2FdJMcaaew82V%2Fyc2aEY3qGaHDti7EPfEMn0%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;2253&quot; height=&quot;348&quot; data-origin-width=&quot;2253&quot; data-origin-height=&quot;348&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;그리고 Logging 을 돌아다니면서 처리하고 Rotate를 시작한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1780933587702&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;insertId&quot;: &quot;4381327247975676422&quot;,
  &quot;jsonPayload&quot;: {
    &quot;remediationLink&quot;: &quot;https://cloud.google.com/docs/security/respond-to-abuse-misuse&quot;,
    &quot;@type&quot;: &quot;type.googleapis.com/google.cloud.abuseevent.logging.v1.AbuseEvent&quot;,
    &quot;reinstatementEvent&quot;: {},
    &quot;reason&quot;: &quot;No new abuse findings on the projects have been detected on the monitored resource, but its state may have been updated (eg: reinstated).&quot;,
    &quot;detectionType&quot;: &quot;NO_ABUSE&quot;,
    &quot;action&quot;: &quot;REINSTATE&quot;
  },
  &quot;resource&quot;: {
    &quot;type&quot;: &quot;abuseevent.googleapis.com/Location&quot;,
    &quot;labels&quot;: {
      &quot;resource_container&quot;: &quot;projects/399395864699&quot;,
      &quot;location&quot;: &quot;global&quot;
    }
  },
  &quot;timestamp&quot;: &quot;2026-06-08T06:23:45.649531945Z&quot;,
  &quot;severity&quot;: &quot;ALERT&quot;,
  &quot;logName&quot;: &quot;projects/moyamo-plus/logs/abuseevent.googleapis.com%2Fabuse_events&quot;,
  &quot;receiveTimestamp&quot;: &quot;2026-06-08T06:23:46.578221266Z&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;대충 Cloud Logging 에서 찾아보면 위의 경보에서 찾을 수 있는 것인데, 예전에는 무슨일이 있었는지 찾아보았는데&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;여하튼 이것으로 더이상 나의 FCM Push notification을 건들지 말아다오..&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;추가적으로 Gemini API 만을 사용하기 위한 별도의 Google Cloud Console의 Credential 을 만들어주고 바인딩 해줬다. 그 이후에 서버 안에다가 살포시 파킹시킨 뒤에 데몬을 재시작 시켰다&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;혹시모르니까&amp;nbsp; FCM의 Topic이 한두개로 고정되있는걸 수정해야 할 지도 모르겠다.&lt;/p&gt;</description>
      <category>Cloud/Google</category>
      <author>remoted</author>
      <guid isPermaLink="true">https://remoted.tistory.com/645</guid>
      <comments>https://remoted.tistory.com/645#entry645comment</comments>
      <pubDate>Tue, 9 Jun 2026 00:49:06 +0900</pubDate>
    </item>
    <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>
  </channel>
</rss>