Skip to content

[UNI-377] refactor: 로컬캐시 도입 & 비동기 로깅 & Fastjson HTTP response 적용#242

Merged
mikekks merged 13 commits intobefrom
feat/UNI-377
Mar 28, 2025
Merged

[UNI-377] refactor: 로컬캐시 도입 & 비동기 로깅 & Fastjson HTTP response 적용#242
mikekks merged 13 commits intobefrom
feat/UNI-377

Conversation

@mikekks
Copy link
Collaborator

@mikekks mikekks commented Mar 25, 2025

📝 PR 타입

  • 기능 구현
  • 기능 수정
  • 버그 수정
  • 리팩토링
  • 인프라, 의존성, 환경 변수, 빌드 관련 코드 업데이트

🚀 변경 사항

자세한 내용 : https://gamxong.tistory.com/162 (이번엔 관련해서 내용 공유를 많이 못하다보니 여기에나마 최대한 자세하게 적어봤습니다!)

안녕하세요. 오랜만에 PR 올립니다..!
작업하다보니 이것저것 설정이 많아진 점 정말 죄송합니다,,

아무래도 이번 작업은 함께 많은 내용을 논의하지 못하다보니 궁금한거나 다른 제안이 있으시면 편하게 말씀주세요 :)
또는 더 작은 PR 단위를 원하시면 그런 방향도 가능할 것 같습니다!

1. Local cache

  • 더 좋은 서버로 이주함에 따라 로컬캐시로 변경하였습니다.
  • 로컬캐시는 가장 고성능인 caffeine를 사용했습니다.
  • 성능테스트 해본 결과 확실히 더 좋은 성능을 보여주는 것으로 확인되었습니다.
  • redis와 함께 사용하여 멀티레벨 캐시로 구현해볼까도 생각했지만 기술적으로 납득이 잘 가지 않아 해당 방식은 일단 보류중에 있습니다!

2. 비동기 로깅

  • 성능 테스트를 진행하다보니 저희 로깅 AOP에서도 병목이 생기는 것을 확인했습니다.
  • 이를 보완하고자 비동기 로깅을 도입하였고, 이전 코드 수정을 최소한으로 하여 구현하고자 했습니다.
  • 비동기 로거를 사용하기 위해 log4j.yml 파일이 추가되었고, 해당 파일에서 AsyncLogger 가 비동기 로거 관련 설정입니다.

3. Fastjson HTTP Response write 할 때도 사용

  • 기존에 해당 코드가 원래 있었는데 postman으로 테스트할 때 무한로딩이 생겨 해당 설정을 지웠었습니다.

  • 그 후애 다시 테스트를 해보니 Fastjson에 인간이 보기좋게 출력하는 옵션이 있는데 해당 옵션때문에 생긴 문제였습니다.

  • as-is

    • config.setWriterFeatures(JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.PrettyFormat);
  • to-be

    • config.setWriterFeatures(JSONWriter.Feature.WriteMapNullValue);
  • 해당 옵션을 삭제하니 postman에서도 정상적으로 동작하는 것을 확인했습니다.

  • 뿐만 아니라 관련 부하테스트를 진행해보니 유의미한 결과까지도 얻을 수 있었습니다.

4. 기타 수정 사항

  1. redis 의존성 삭제 : 일단 가까운 미래에는 redis를 사용할 이유가 없을 것 같아 관련 의존성을 삭제했습니다.
  2. 로깅쪽에서 SSE 통신하게 될 경우, 로직상 일부 로그가 안나오게 되어 AOP 클래스의 일부 수정했습니다.
  3. 이제 더이상 사용하지 않는 {domain}/{univId}/routes API 삭제했습니다.
  4. CacheService 레이어 : 제가 만들었지만 기존에 너무 통일성 없게 대충 만든 느낌이 들어 메서드나 동작을 명확히 하였습니다.
  5. redis 관련 이름 수정 : 변수명들이 너무 기술에 의존하는 것 같아 redis 관련된 이름을 모두 cache 로 수정했습니다.

💡 To Reviewer

🧪 테스트 결과

✅ 반영 브랜치

  • feat/

@mikekks mikekks added 🚀 feat 기능 개발 💡 refactor 기능 개선 🫀 be 백엔드 task labels Mar 25, 2025
@mikekks mikekks requested a review from thdgustjd1 March 25, 2025 07:32
@mikekks mikekks self-assigned this Mar 25, 2025
@coderabbitai
Copy link

coderabbitai bot commented Mar 25, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@mikekks mikekks changed the title refactor: 로컬캐시 도입 & 비동기 로깅 & Fastjson HTTP response 적용 [UNI-377] refactor: 로컬캐시 도입 & 비동기 로깅 & Fastjson HTTP response 적용 Mar 25, 2025
Copy link
Collaborator

@thdgustjd1 thdgustjd1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다~ 궁금한점 코멘트 달아두었습니다

Comment on lines +23 to +27
public Caffeine<Object, Object> caffeineConfig() {
return Caffeine.newBuilder()
.expireAfterWrite(12, TimeUnit.HOURS) // 12시간 후 캐시 만료
.maximumSize(3000) // 최대 3000개 저장
.recordStats(); // 캐시 통계 활성화
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 최대 3000개란 이중에 무엇을 의미하는지 궁금합니다!

  1. 학교 3000개
  2. lightRoute 객체 3000개
  3. lightRoute 2500개에 해당하는 key 3000개

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3번을 의미합니다 ! 이 부분도 어떻게 생각하시는지 궁금합니다 !

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최대 2500 * 3000 = 750만 개의 데이터는 1GB 이하니깐 메모리 관점에서는 괜찮다고 생각합니다. (현재 8GB 서버 기준)

그런데 전국 약 300개 대학의 길 데이터를 모두 합쳐도 750만개가 안될것 같습니다.
그 말은 곧 전국의 모든 데학교 데이터를 캐싱할 수 있다는 말인데, 모든 데이터를 캐싱할 수 있다면 TTL이 꼭 필요한가에 대해 논의해보면 좋을 것 같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 안그래도 저도 며칠전부터 그런 의문이 있었어서 공감이 되네요!
더 나아가 데이터가 수정될 때도, "캐시를 eviction 하지않고 수정할 때마다 업데이트 해주면 TTL은 의미가 없는게 아닌가?" 생각을 했습니다.

그래서 관련 자료들을 찾아봤는데여! 설득력이 있던 얘기는 "불필요한 데이터가 메모리에 너무 많이 올라가 있다." 였습니다. 정말 많은 사용자가 들어오게 된다면, 그에 따라 많은 메모리 공간이 필요하게 됩니다.

만약 1달 전에 사용했던 데이터도 로컬캐시에 올라와있으면 기본적으로 메모리 사용량이 높아져 TPS가 떨어지거나 OOM 발생 확률이 높아진다고 생각했습니다.
하지만 반대로 TTL이 있다면, 정말 "핫한" 데이터만 동적으로 메모리에 올라와있기 때문에 많은 사용자가 들어와도 유연하게 대처 && 조금 더 많은 사용자를 처리할 "수"(가능성이 높아진다) 있다고 생각했습니다.

Redis 와 같은 리모트 캐시에도 유효하다고 생각했습니다. 비슷한 이유로 필요없는 데이터가 메모리에 항상 올라와있다는 것이 불필요하고, 시스템의 여러 매트릭을 불필요하게 높이는 요인이라고 생각했습니다!

반대로 TTL를 도입하면 tradeoff로 말씀주신 것처럼 DB로의 접근은 늘어날 수 밖에 없습니다. 또한, TTL이 굉장히 짧게 설정되어 있다면 오히려 그 부분이 TPS를 떨어뜨리는 요인이 될 수도 있겠죠,,

이게 참 애매한게 실제 사용자 트래픽이 있다면, 그 트래픽을 기준으로 의사결정을 할 수 있을 것 같은데 그러지 못하는게 아쉽네요..
그래서 저도 댓글 적다가 생각이 든건데, 제가 한 번 실제 테스트를 해보면서 수치 결과를 통해 두 방식을 비교해보는 것도 좋겠다는 생각도 드네요!

안그래도 해당 내용으로 얘기를 하고 싶었는데 좋은 질문 감사드리고, 현성님 의견이 궁금하네요..ㅎ

Copy link
Collaborator

@thdgustjd1 thdgustjd1 Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀해주신대로 확실히 TTL없이 할 경우 메모리낭비가 될 수 있을것 같습니다. 그렇다면 TTL을 적절하게 설정하는게 좋을 것 같네요!

아직 트래픽이 있지 않아서 정확하진 않지만, 서비스 특성상 오전8시-오후6시 사이에 호출량이 많을것으로 예상됩니다. (이 오전8시-오후6시를 피크타임이라고 하겠습니다.) TTL이 12시간일 경우 오늘 캐시에 올라간 데이터는 밤-새벽 사이에 만료되어 다음날 피크타임에 호출할 땐 다시 DB접근이 이루어질 것 같습니다. (핫 키도 밤-새벽 사이에 만료됨)

이러한 상황에서는 TTL을 36시간 이상으로 늘리거나, TTL 없이 최근 며칠간 접근되지 않은것을 지우거나 하는 방향으로 가면 좋을 것 같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 일단 TTL을 36시간으로 설정하고, 추후에는 핫키에 대해서 동적으로 TTL을 갱신해보는 것을 고민해보겠습니다!

좋은 의견 감사합니다 :)

@mikekks mikekks merged commit c4407bc into be Mar 28, 2025
2 checks passed
@mikekks mikekks deleted the feat/UNI-377 branch March 28, 2025 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🫀 be 백엔드 task 🚀 feat 기능 개발 💡 refactor 기능 개선

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants