카프카 핵심 가이드 - 2. 카프카 설치하기
카프카를 설치하고 실행하는 방법부터 주요 설정까지 알아보았습니다. 주요 설정 중에는 브로커 ID, 리더 분산 설정, 메시지 보존 시간 등이 있습니다.
0개의 댓글
0개의 질문
염소
https://github.com/goathoon <- Github 주소 !
카프카를 설치하고 실행하는 방법부터 주요 설정까지 알아보았습니다. 주요 설정 중에는 브로커 ID, 리더 분산 설정, 메시지 보존 시간 등이 있습니다.
0개의 댓글
0개의 질문
기업에서 데이터는 중요한 부분이며, 카프카는 데이터를 효율적으로 다루기 위한 메시지 발행/구독 시스템으로 분산 커밋 로그와 스트리밍 플랫폼으로 사용됩니다. 카프카는 확장성과 성능 면에서 우수하며, 다중 클러스터 운용이 가능하고 안정적인 데이터 보관을 제공합니다.
1개의 댓글
0개의 질문
부동산 지수를 계산하기 위해 많은 양의 데이터를 처리하는 중에 메모리 문제와 연산 속도가 느린 문제가 발생했지만, 병렬 처리를 통해 프로세스 간 연산을 나눠서 진행하여 성능을 개선했다. 결과적으로 파일로 저장하면서 메모리 문제도 해결되었고, 멀티 프로세싱을 통해 CPU 자원을 효율적으로 사용하여 빠르게 연산이 가능해졌다.
1개의 댓글
0개의 질문
GCP의 Cloud Run 서비스는 ECS Fargate와 유사한 서버리스 애플리케이션 배포를 지원하며, 목표 컨테이너 수를 0개로 설정하여 요청 시 테스크를 띄우거나 warm start를 위한 비용이 적은 컨테이너를 유지하는 전략을 제공한다. AWS의 ECS Fargate에서는 이 기능을 제공하지 않지만, EKS(AWS Kubernetes)에서는 가능하다고 한다.
1개의 댓글
0개의 질문
FastAPI 도커 이미지 최적화를 위해 Base image를 python:3.12.2-slim에서 python:3.12.2-alpine로 변경하고, 불필요한 행을 제거하여 이미지 크기를 줄였으며, 필요없는 패키지들을 제거하고 poetry 대신 pip를 사용함으로써 총 0.44GB의 용량을 절약했다.
0개의 댓글
0개의 질문
리액트 쿼리에서는 api 응답 값으로 에러를 반환하더라도 onError에 적어놓은 에러 처리가 되지 않는 오류가 발생합니다. 이를 해결하기 위해서는 api fetch하는 코드에서 발생한 에러를 throw 해야 onError에서 잡을 수 있습니다.
0개의 댓글
0개의 질문
서브쿼리는 쿼리 안에 있는 쿼리로, 실제로 여러 번 실행되며 계산 필드를 구하기 위해서 자주 사용된다. 하지만 성능을 고려하여 join과 같은 다른 방법을 고려하는 것이 좋다. 도전 과제 중 4번과 5번의 서브쿼리에서는 GROUP BY 절이 불필요하다는 점이 틀린 부분이었다.
0개의 댓글
0개의 질문
(스크린샷은 향후 추가 예정) (틀린 점, 궁금한 점은 적극적으로 공유해주셔도 좋습니다!) 개발자분들이 늘 고민을 많이 하시는 부분이 개발 환경이라고 저는 종종 생각합니다. 그렇기에 개발 환경은 개발자들에게 항상 중요한 고민거리입니다. 저 역시 최대한 다양한 환경을 테스트해보고 내가 사용하기 좋은 환경일지 고민해보죠. 이 과정에서 새로이 쓰게 된 개발환경이 바로 Neovim과 NvChad 입니다. Vim? Neovim? Vim은 우리가 모두 들어봤을 거 같은데요, 대부분의 Linux/Unix 환경에 탑재되어 있는 친구가 바로 Vim입니다. 잘 쓰는 분들은 Vim으로 날라다니시지만, 저는 그러지 못해서, Neovim을 알기 전까지는 제대로 써보지 못했습니다. Neovim은 여러분이 잘 아시는 그 Vim에 확장성, 좀 더 향상된 UI 등을 접목한 Vim의 후예같은 친구입니다. Vim도 plugin 등을 적용할 수 있지만 Neovim은 더 사용하기 편안하도록 VSCode와 유사한 UI, Launguage Server Support 등을 지원합니다. 기존의 내장 기능만을 사용하는 Vim과는 어느정도 차이가 있죠. 왜 Vim? Vim을 선택한 건 갑작스러운 변덕이라기보다는, 하나의 불행에서 시작되었습니다. (제게는) VSCode의 필수 extension인 Remote-SSH가 먹통이 되었거든요. 물론 그 버그는 금방 해결되었습니다만... 하루를 생으로 날려보낼 수는 없던 제 입장에서는 이런 상황이 생길 때를 대비한 backup이 필요했고 그 과정에서 가볍지만 원하는 기능을 모두 제공하는 Vim을 사용해봤습니다. 다만 Vim만을 사용하지는 않았죠. NvChad? 앞에서 언급드렸다시피 Neovim은 확장성, 향상된 UI 등을 제공합니다. 하지만 Vim 초심자에게 있어 Neovim의 설정을 바로 하기에는 좀 (많이) 어렵습니다. 그래서, 초심자들을 위한 plugin과 설정의 집합?과 같은 녀석들이 등장했죠. NvChad, LunarVim 과 같은 친구들이 그 친구들이죠. (얼마나 꾸준히 작성할지는 잘 모르겠지만) 밑밥을 열심히 깔아 두었으니 이제부터 조금씩 설정하면서 삽질한 이야기들을 해보려고 합니다. 두서없는 글 봐주셔서 감사하고 만약 계속 따라오실 예정이시라면 앞으로 잘 부탁드립니다. Reference. https://github.com/NvChad/NvChad https://github.com/neovim/neovim
1개의 댓글
0개의 질문
Java String Pool Java에서 문자열을 표현하는 String은 불변객체다. String name = \"jeongyun\";\nname += \"eo\";\nSystem.out.println(name); // jeongyuneo 위 코드에서 name에 문자열을 더한다고 해서 문자열의 값이 바뀌는 것이 아니라, 새로운 객체를 만들어 그 참조값을 참조하게 된다. 만약 같은 값을 갖는 문자열을 여러 번 선언한다면, Heap 영역에 매번 새로운 객체를 생성하게 될 것이다. 이는 메모리 낭비로 이어진다. 따라서 Java는 문자열 객체를 캐싱(caching)한다. 💡 캐싱(caching) 데이터를 미리 복사해 임시 저장해놓는 것 데이터 접근 시간을 줄일 수 있음 String Pool Java의 Heap 영역에는 String Pool이 존재하고, String Pool이 String 객체들을 관리한다. String Pool은 HashTable 구조를 갖고 있다. 문자열 리터럴을 사용해 문자열 객체를 생성하면 String Pool에 같은 값을 가지는 String 객체가 있는지 검사하고 있다면 그 객체의 참조값을, 없다면 새로운 String 객체를 생성해 그 객체의 참조값을 반환한다. 이러한 과정을 ‘intern’이라고 한다. String 객체를 위 코드처럼 리터럴로 생성 시 내부적으로 intern() 이라는 메소드를 실행해 수행한다. 따라서 같은 문자열은 myPet과 hisPet 두 객체의 참조값을 비교하는 동일성 비교(==)에도 true 가 반환됨을 확인할 수 있다. 반대로 new String(”문자열”) 을 이용해 생성된 객체들은 String Pool이 아닌 Heap 영역에 생성된다. 각각의 객체들은 서로 다른 참조값을 갖고 있기 때문에 이런 방식으로 생성된 myPet과 hisPet 두 객체의 참조값을 비교하는 동일성 비교(==)에서 false 가 반환됨을 확인할 수 있다. Java 6까지 String Pool은 Heap 영역 안에서도 Perm 영역에 있었다. 이때문에 String Pool에 문자열 객체가 많이 생성되거나 다른 이유로 이 영역이 가득 차게되면, 런타임 환경에서 메모리를 동적으로 늘리지 못해 OutOfMemoryException 발생했다. Java 7에서는 다른 일반 객체들과 마찬가지로 Perm 영역이 아닌 Heap 영역에 String Pool을 생성해서 OutOfMemoryException이 발생했을 때의 위험성을 줄였다. Java 8부터는 고정 크기로 많은 문제를 일으켰던 Perm 영역은 Metaspace로 이름을 변경하고 동적크기 메모리 구성으로 변경되었다.
1개의 댓글
1개의 질문
아래 코드는 org.springframework.boot:spring-boot-autoconfigure 에 기본으로 설정된 쓰레드 풀 관련 필드이다. public static class Tomcat {\n private int maxConnections = 8192;\n\t\t private int acceptCount = 100;\n...\n}\n\npublic static class Threads {\n\t\t\tprivate int max = 200;\n\t\t\tprivate int minSpare = 10;\n...\n} 위 설정처럼 spring boot 는 기본적으로 최소 10개, 최대 200개의 쓰레드를 사용할 수 있고, 최대 8192개의 커넥션이 가능하고, 100 size의 큐를 갖고 있다. 그런데, WAS 에서 유저가 얼마 있지도 않음에도 다음과 같이 커넥션을 연결하지 못한 채 타임아웃이 나버렸다. java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available 기본적으로 HikariCP 는 최대 10개의 DB 커넥션을 지원하고 있다. 하나의 페이지에서 여러 API 를 요청함에 따라 Spring MVC 에서는 요청 별로 쓰레드를 할당하고, nginx를 통해 keep-alive를 90초로 설정해놓았기에 쓰레드에서 커넥션 풀을 잡고 놓아주지 않는 것은 아닐까? 라고 생각했다. 결론 JDBC Template 를 사용하고 있어, Connection 을 언제 꺼내고 반환하는 지 살펴보았다. template.query, template.update 와 같이 쿼리를 실행할 때 전후로 getConnection 과 closeConnection 을 호출하고 있었다. 따라서 쓰레드가 커넥션을 잡고 있는 것은 아닐 것이라 판단하였다. keep-alive 를 90초로 설정한 것은 불필요한 handshaking 을 줄여주는 것이지, 쓰레드를 잡고 있는 것이 아니다. 그렇다면 유저도 얼마 없는데 30초 씩이나 DB 커넥션을 얻지 못할 일이 뭐가 있을까? public static Array createSqlArray(JdbcTemplate template, List<String> tags) throws SQLException {\n Array stringArray = null;\n try {\n stringArray = template.getDataSource().getConnection().createArrayOf(\"varchar\", tags.toArray());\n } catch (SQLException e) {\n throw new SQLException(e);\n }\n return stringArray;\n } 위 코드는 template 에서 datasource를 직접 꺼내고 직접 커넥션을 얻어 사용하였는데, 끝나고 반환을 하지 않았다. 위 같은 경우에 finally 구문에서 close 를 해주거나, DataSource 를 커스터마이징하여 AutoClosable 를 구현하여 try-with-resources 를 사용하는 방법으로 해결할 수 있다. 근데 그냥 저 코드 자체가 문제인듯
0개의 댓글
0개의 질문
로그인을 직접 구현하면서 발생한 문제점을 정리해보겠다. 먼저, JWT 를 사용해 로그인을 구현하기로함 이유: 세션은 스케일아웃이 어려움, 쿠키에 user table의 pk 값만 담아도 충분함 엑세스 토큰, 리프레시 토큰을 어디에 두어야 하는가 검색해보니 블로그마다 구현한 방식이 다름 액세스 토큰은 일반 쿠키에 담자 - 보안에 좋지 않다. 그러므로, 유효시간을 짧게 둔다. 리프레시 토큰은 http only, secure, samsite=lax 쿠키에 담자 - 쿠키 중 가장 안전한 방식 Q. 그런데, 액세스 토큰 자체를 리프레시 토큰처럼 안전한 쿠키에 보관하면 되는것 아닌가? A. 그래도 보안에는 차이가 없지만, 액세스 토큰을 일반 쿠키로 두었을 때, next.js 와 같이 클라이언트와 백엔드 사이에서 쿠키를 사용할 일이 생기면 http only 쿠키는 중간에서 사용할 수 없다 . (수정) 도메인이 같다면 백엔드, next 서버 모두 쿠키를 사용할 수 있다. 따라서 액세스 토큰도 안전한 쿠키에 저장해도 된다. 그럼 리프레시 토큰은 절대 안털림? 절대 안털린다고는 당연히 말할 수 없다. 완벽한 보안이 존재하면 아무도 고민 안할듯 그래서 리프레시 토큰도 털릴 경우를 대비하면 좋다. RTR RTR 방식을 사용해서 리프레시 토큰이 털리는 것을 어느정도 방지해줄 수 있다. RTR은 처음 로그인 시 엑세스, 리프레시 토큰을 발급받고, 이후 액세스 토큰이 만료되면 리프레시 토큰을 사용해 새로운 리프레시, 액세스 토큰을 발급받는 방식이다. 이전에 발급된 리프레시 토큰은 쓸모가 없어진다. 자연스럽게 유저가 계속 서비스를 사용하면, 로그인이 영원히 유지된다. 시나리오 액세스토큰만 털어간다 30분 정도는 유저인척 할 수 있다. 이후 액세스 토큰 만료 시, 리프레시 토큰이 없기에 더이상 유저인척 할 수 없다. 액세스토큰, 리프레시 토큰 둘다 털어간다. 마찬가지로 30분 정도 유저인척한다. 이후 액세스 토큰 만료되면, 해커가 먼저 새로 발급받는다. -> 유저가 이후에 다시 로그인해, 새로운 리프레시, 액세스 토큰을 발급받고, 해커의 리프레시 토큰을 무효화 시킨다. 유저가 먼저 새로 발급받는다. -> 해커의 리프레시 토큰이 무효화된다. 물론, 리프레시, 액세스 토큰이 털렸는데 유저가 로그인을 하지 않는다면 해커는 영원히 유저인 척 할 수 있다.
0개의 댓글
0개의 질문
DELETE 쿼리 개선 0. 발생한 문제 장바구니에 존재하는 상품을 선택하여 주문하기 버튼을 클릭하면, 해당 상품을 주문 상태로 변경하고 장바구니에서 해당 상품들을 제거하는 것이었다. 문제는 장바구니에서 해당
0개의 댓글
0개의 질문
인프런은 하나의 거대한 레거시 프로젝트를 리펙토링하고 있었음. 하나의 서비스에 개발팀, PM팀, 디자이너 팀 등 큰 하나의 공동체로 조직화 되어 있었음 개발 속도 개선을 위해 5개의 팀으로 나누어 각각의 서비스를 개발함 문제: N개의 서비스가 생겨나면서, N배의 인프라가 필요 IaC(Infrastructure as Code) 를 통해 코드를 통해 아키텍쳐를 생성할 수 있도록 함. 이후 같은 코드를 실행하면 같은 아키텍쳐를 만들어낼 수 있음 문제: API 호출마다 퍼블릭 IP와 path를 이용한 분기를 이용하다보니 불필요한 네트워킹, 트래픽 비용이 발생 퍼블릭 도메인으로 요청을 하지 않고, Private Load Balancer 를 통해 내부적으로 API 통신하여 해결함. 문제: 내부 API 호출이 많아지면서 타 서비스의 로직까지 알아야하고, API 예외 로직을 추가로 만들어 처리해야함 타 서비스에 대한 API 요청은 우리 서비스가 알 필요 없음 따라서, SNS를 통해 API를 호출하겠다는 정보만 남김 이후, SQS를 통해 SNS를 구독하여 정보를 받아 API를 호출하도록 처리 비동기적으로 처리하여 서비스간 종속성을 제거하고, 빠른 처리가 가능함. SQS를 통한 api 호출은 re-try가 가능하므로 최종적 일관성이 보장됨. 문제: 서비스는 여러 개 있지만 단일 DB를 사용 파생되는 문제점 DB 정보에 대한 팀들간 정보의 공유가 필수적임 어느 서비스에서 에러 쿼리를 실행했는지 정확히 파악하기 힘듦 해결 DDL 마다 Slack에 연동하여 정보를 공유함 서비스마다 계정을 나누어 어느 서비스의 문제인지 확인함 어설픈 추상화/공통화 보다는 삭제하기 쉬운 중복이 낫다. 이외: 인증 인가를 서비스마다 처리해주어야하는 로직 중복 문제 => API 게이트웨이를 통해 하나의 엔드포인트에서 관리
0개의 댓글
0개의 질문