묻고 답해요
167만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결"AI 딸깍의 시대" 원리로 돌파하는 Node.js와 CS Part1: V8과 코어 해체기
3강 질문
💡[CS 실무 Point: OS 계층의 역량 활용 (epoll / kqueue)] 단일 스레드라고 해서 컴퓨터가 정말로 혼자 일하는 것은 아닙니다. 파일 읽기나 네트워크 통신 같은 무거운 작업은 Node.js가 직접 처리하지 않고, 운영체제 커널이 제공하는 고성능 이벤트 통지 API(Linux의 epoll, macOS의 kqueue 등 시스템 콜)를 통해 운영체제에게 철저하게 위임(Offloading)합니다. 즉, Node.js의 메인 스레드는 교통정리만 아주 빠르게 수행할 뿐, 실제 무거운 짐은 OS 커널이 백그라운드에서 나르고 있는 것입니다. 안녕하세요, 위 설명에서 질문이 있습니다.운영체제에 위임하는 작업과 libuv 스레드 풀의 워커 스레드가 어떤 연관이 있고 어떻게 유기적으로 동작하는지 궁금합니다.
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
강의 듣는 중인데,
1강에서 자료 다운받기? 한 것은 언제쯤 보는 걸까요?? 강의 다 끝나고 혼자서 공부하는건가요?? 어떤 순서로 공부를 해야하는지요?
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
36강 오탈자가 있는 거 같습니다.
안녕하세요,36강 1분 10초쯤에AWS Glue의 ETL에서 Tarnsform > Transform 오타인 거 같습니다.
-
미해결스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 캐시 전략
Service Create/Update Record 운용과 Delete Record 미운용의 차이 질문
안녕하세요, 선생님! 강의 들으면서 Service 및 Cache Handler 구성간 Create/Update <-> Delete 간의 Return Record 여부 차이에 대해 질문드리고자 합니다. 서비스도 그렇고, 핸들러도 그렇고, Return type이 Create/Update는 전달받은 Record를 Entity Context에 적용한 객체인데, delete의 경우 void로 운용하시는 것을 보고 어떤 차이점이 있는지 궁금하여 질문드리게 되었습니다. create, update 모두 반영 이후의 내역을 바로 반환하여 보여준다는 의미로 생각하였는데, delete를 보면 그런 것 같지는 않아서 따로 다른 의미가 있는지(실무에서 이렇게 많이 사용한다던가), 별 의미가 없는지 구체적으로 문의드리고자 합니다. 감사합니다.
-
미해결"AI 딸깍의 시대" 원리로 돌파하는 Node.js와 CS Part1: V8과 코어 해체기
2강 nodejs 3단계 설명 질문
2.4 Node.js의 3단계 분업 아키텍처 자바스크립트 코드가 운영체제를 움직이는 과정은 세 단계의 협업으로 이루어집니다.자바스크립트 코드 작성: 개발자가 비즈니스 로직을 작성합니다.V8 엔진의 통역: 자바스크립트를 C++가 이해할 수 있는 형태로 통역합니다.C++ 코어 및 바인딩(Bindings): 통역된 지시를 받아 운영체제(OS)에 직접 명령을 내립니다. 이때 C++는 현장의 작업 반장 역할을 수행하며 실제 파일이나 네트워크를 제어합니다.위 내용에서 v8의 통역 이후 부분이 이해가 잘 가지 않습니다. v8 엔진의 결과물은 C++과 관계없이 바이트코드나 기계어가 되지 않나요? 그리고 js만으로 불가능한 os 작업이 나오면 v8 실행 중에 미리 C++로 만들어 놓은 모듈을 호출하는 식으로 동작하는게 아닌지 문의드립니다.감사합니다.
-
미해결제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
Sequence 관련 질문
저는 review image reordering을 염두에 두고 sequence를 계속 가져가는 방향으로 결정했습니다.제미니님은 실무에서 이렇게 염두에 두고 구현이 조금 더 복잡해지더라도 이런 특정 필드나 기능을 가져가는것을 오버엔지니어링이라고 생각하여 피하시는 편인가요? 어떤 기준으로 결정하시는지 궁금합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
Image Only Query
image only query를 설명해주실때 stable pagination 때문에 조인을 사용하신다고 이해했습니다. 저는 다른방식으로 구현해보았는데 제미니님의 의견이 궁금합니다. 코드를 보면 나중에 image를 fetch 또 하게 되는데 이렇게되면 image only query를 ReviewImageEntity에 reviewId, status 인덱스를 걸고SELECT review FROM ReviewEntity review WHERE review.targetType = :targetType AND review.targetId = :targetId AND review.status = :status AND EXISTS ( SELECT image.id FROM ReviewImageEntity image WHERE image.reviewId = review.id AND image.status = :status 이렇게 구현하는 방식이 데이터량이 많아진다면 효율적이지 않을까 싶어서 구현해봤습니다.
-
미해결10,000++억의 데이터를 다루는 카카오 면접관의 MySQL
라이브 운영중인 환경의 테이블에 인덱스 추가시 고려사항
hong님 안녕하세요! 라이브 운영중인 테이블에 인덱스 추가시 고려할 사항이 궁금합니다! psotgresql이긴 하지만 금일 오전에 데이터 1800만건이 있는 테이블에 인덱스 추가를 했더니 cpu 100% 치솟는 장애 직겨탄을 맞았습니다.. (15분간 앱 사용 중단 ㅠㅠ)뒤늦게 찾아보니 락을 잡지 않는 옵션을 추가했어야 하더군요. 새벽에 작업, 일시적인 디비 스펙업 정도만 떠오르네요. 몇천만건 ~ N억건 데이터가 있는 테이블에 인덱스 생성시 고려할 사항이 무엇들이 있는지 궁금합니다!
-
해결됨Spring Boot DDD 실전: 주문 시스템으로 배우는 도메인 설계
DDD 는 마이바티스와 잘 맞지 않는건가요?
안녕하세요.DDD 관련 강의나 블로그를 보면대부분 JPA 로 설명해주시더라구요. 마이바티스도 실무에서 오히려 더 폭 넒게 쓰이는 것 같은데 마이바티스로는 DDD 를 적용하기 어려운걸까요?
-
해결됨Spring Boot DDD 실전: 주문 시스템으로 배우는 도메인 설계
스프링부트 버전 문의드립니다.
안녕하세요. 부트버전을 3.5 로 설정해서 수강해도 괜찮을까요. 회사에서 아직 4.x 버전 업 계획이 없어서요.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
Json 요청 처리
형 나 지금 너무 재밌어서 잘 따라하던중 별거 아닌거에서 막혀서 좀 힘들어형이 알려준 json 파라미터 넘기는 방법으로 해도 안되고 gpt 찾아서 진행 한거도 다 안돼는데 윈도우 환경에서 좀 힘든걸까 ?? 다른 수강생분이 올려준거도 봤는데 답변에 달아준 방법도 동작하지 않아 @Bean public JsonJobParametersConverter jobParametersConverter() { return new JsonJobParametersConverter(); } @Bean @StepScope public Tasklet terminatorTasklet( @Value("#{jobParameters['infiltrationTargets']}") String infiltrationTargets ) { return (contribution, chunkContext) -> { String[] targets = infiltrationTargets.split(","); log.info("⚡ 침투 작전 개시"); log.info("첫 번째 타겟: {} 침투 시작", targets[0]); log.info("마지막 타겟: {} 에서 집결", targets[1]); log.info("🎯 임무 전달 완료"); return RepeatStatus.FINISHED; }; }
-
해결됨카카오, 토스 개발자가 알려주는 수백개의 MSA 환경에서의 성능 보장을 위한 RPC 처리 기법
gRPC 실무에서 질문
이제 앞으로 3개만 더 들으면 완강이네요! 빠르게 gRPC를 공부할수 있어서 좋았습니다. 강의를 마무리해가니 궁금한 점이있어 질문 남깁니다.마이크로서비스가 1000개 이상되는 회사에서 데이터팀 백엔드 인턴으로 근무를 할 예정인데 데이터팀이다 보니 서비스들 전체를 아우르는 일을 해야한다고 들었습니다. 그래서 gRPC에 대해서 공부해오면 좋다고 해서 강의를 수강하게 되었습니다. 처음에 회사에 들어가면 어떤식으로 서비스들의 gRPC를 분석해야할까요? 혹시 추천해주시는 순서가 있으실까요? 예를 들어서 .proto파일을 먼저 확인한다 -> 등등성공적인 백엔드 인턴을 위해서 추가적인 조언이 있으시다면 감사하겠습니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
다양한 관점의 코드 경험을 위해 개선하지 않은 코드
안녕하세요. 제미니님 유튜브 부터 인프런까지 참여하며 굉장히 많은 인사이트를 얻고있어 무한한 감사 인사를 올립니다. 질문강의를 수강하며 제미니님이 던져준 키워드를 어떻게 곱씹어야하지? 라는 생각을 하며 두 가지 정도 질문을 드리게 되었습니다. Q1. "저같은 경우는 뭐 컴포넌트 같은 걸 좀 쪼개서 만들고 싶은데, 일단은 여러분들이 좀 혼합된 걸 느끼게 하려고 제가 풀어 놨어요" - 결제 코드 느끼기 13:17이렇게 제미니님이 생각했던 코드를 보고 싶은데, 이 코드는 신규 강의였던 "레거시 다루기" 에서 개선 작업을 하나요? 아니면 저희에게 열린 사고를 던져주고 넘어가는걸까요? Q2. "success 메서드에 트랜잭셔널을 사용하는 것도 할 말이 많은데 기본적인 로직에서는 문제는 없다." - 결제 코드 느끼기 13:58이 내용에서도 혹시 개선하는 부분도 질문 1번과 같이 레거시 다루기 강의에서 개선 하시나요?개인적으로 success 에서 트랜잭션 어노테이션을 빼고, 저장하는 로직을 한 군데 모아서 거기 사용할 것 같은데 제미니님은 어떻게 하시는지 궁금하네요!
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
[건의][6장][작전1] deprecated 메소드
형 ... @Bean public Step threatAnalysisStep( JpaPagingItemReader<Human> humanThreatDataReader, ItemProcessor<Human, TargetPriorityResult> threatAnalysisProcessor, FlatFileItemWriter<TargetPriorityResult> targetListWriter ) { return new StepBuilder("threatAnalysisStep") .<Human, TargetPriorityResult>chunk(10, transactionManager) .reader(humanThreatDataReader) .processor(threatAnalysisProcessor) .writer(targetListWriter) .taskExecutor(taskExecutor()) // deprecated 되어서 안씀 // .throttleLimit() .build(); } ... 에서 .throttleLimit() 부분이 5 이후로 deprecated 된다고 명시되어 있어. 관심사 분리로 인해서 taskExecutor 정의 부분에서 설정하라고 권장하는 것을 확인했거든. 현재 강의가 사실상 Spring Batch 5.x 까지의 기본 내용과 원리를 살펴봤잖아 ? 그렇다 하더라도 혼란을 줄 수 있기 때문에 해당 부분은 삭제하던지 아니면 추가 내용을 기재해야 할 것으로 보여.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
[예제][3장][작전2] windows 에서 마지막 예제
... @Slf4j @Configuration @RequiredArgsConstructor public class LogProcessingJobConfig { private final JobRepository jobRepository; private final PlatformTransactionManager transactionManager; private final String BASE_PATH = "C:\\Users\\user\\Desktop\\batch\\section3\\flatfileitemwriter"; @Bean public Job logProcessingJob( Step createDirectoryStep, Step logCollectionStep, Step logProcessingStep ) { return new JobBuilder("logProcessingJob", jobRepository) .start(createDirectoryStep) .next(logCollectionStep) .next(logProcessingStep) .build(); } @Bean public Step createDirectoryStep(SystemCommandTasklet mkdirTasklet) { return new StepBuilder("createDirectoryStep", jobRepository) .tasklet(mkdirTasklet, transactionManager) .build(); } @Bean @StepScope public SystemCommandTasklet mkdirTasklet( @Value("#{jobParameters['date']}") String date ) { SystemCommandTasklet tasklet = new SystemCommandTasklet(); tasklet.setWorkingDirectory(BASE_PATH); String collectedLogsPath = "collected_ecommerce_logs\\" + date; String processedLogsPath = "processed_logs\\" + date; try { tasklet.setCommand("cmd.exe", "/c", "mkdir", collectedLogsPath, processedLogsPath); tasklet.setTimeout(3000); } catch (Exception e) { log.error("mkdirTasklet error: ", e); } return tasklet; } @Bean public Step logCollectionStep(SystemCommandTasklet scpTasklet) { return new StepBuilder("logCollectionStep", jobRepository) .tasklet(scpTasklet, transactionManager) .build(); } @Bean @StepScope public SystemCommandTasklet scpTasklet( @Value("#{jobParameters['date']}") String date ) { SystemCommandTasklet tasklet = new SystemCommandTasklet(); tasklet.setWorkingDirectory(BASE_PATH); String processedLogsPath = "collected_ecommerce_logs\\" + date; StringJoiner commandBuilder = new StringJoiner(" & "); for (String host : List.of("localhost")) { // Windows 환경에서 해당 코드를 적용하려면 ssh 관련 설정들을 찾아야 해서 주석 처리 // String command = String.format("scp %s:~/ecommerce_logs/%s.log %s\\%s.log", host, date, processedLogsPath, host); String sourcePath = BASE_PATH + "\\ecommerce_logs\\" + date + ".log"; String command = String.format("copy %s %s\\%s.log", sourcePath, processedLogsPath, host); commandBuilder.add(command); } tasklet.setCommand("cmd.exe", "/c", commandBuilder.toString()); tasklet.setTimeout(10000); return tasklet; } @Bean public Step logProcessingStep( MultiResourceItemReader<LogEntry> multiResourceItemReader, LogEntryProcessor logEntryProcessor, FlatFileItemWriter<ProcessedLogEntry> processedLogEntryJsonWriter ) { return new StepBuilder("logProcessingStep", jobRepository) .<LogEntry, ProcessedLogEntry>chunk(10, transactionManager) .reader(multiResourceItemReader) .processor(logEntryProcessor) .writer(processedLogEntryJsonWriter) .build(); } @Bean @StepScope public MultiResourceItemReader multiResourceItemReader( @Value("#{jobParameters['date']}") String date ) { MultiResourceItemReader<LogEntry> resourceItemReader = new MultiResourceItemReader<>(); resourceItemReader.setName("multiResourceItemReader"); resourceItemReader.setResources(getResources(date)); resourceItemReader.setDelegate(logFileReader()); return resourceItemReader; } private Resource[] getResources(String date) { try { String formattedBasePath = BASE_PATH.replace("\\", "/"); String location = "file:///" + formattedBasePath + "/collected_ecommerce_logs/" + date + "/*.log"; PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); return resolver.getResources(location); } catch (IOException e) { throw new RuntimeException("Failed to resolve log files", e); } } @Bean public FlatFileItemReader<LogEntry> logFileReader() { return new FlatFileItemReaderBuilder<LogEntry>() .name("logFileReader") .delimited() .delimiter(",") .names("dateTime", "level", "message") .targetType(LogEntry.class) .build(); } @Bean public LogEntryProcessor logEntryProcessor() { return new LogEntryProcessor(); } @Bean @StepScope public FlatFileItemWriter<ProcessedLogEntry> processedLogEntryFlatFileItemWriter( @Value("#{jobParameters['date']}") String date ) { String outputPath = Paths.get(BASE_PATH, "processed_logs", date, "processed_logs.jsonl").toString(); ObjectMapper objectMapper = new ObjectMapper(); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))); objectMapper.registerModule(javaTimeModule); return new FlatFileItemWriterBuilder<ProcessedLogEntry>() .name("processedLogEntryJsonWriter") .resource(new FileSystemResource(outputPath)) .lineAggregator(item -> { try { return objectMapper.writeValueAsString(item); } catch (JsonProcessingException e) { throw new RuntimeException("Error Converting item to JSON", e); } }) .build(); } @Data public static class LogEntry { private String dateTime; private String level; private String message; } @Data public static class ProcessedLogEntry { private LocalDateTime dateTime; private LogLevel level; private String message; private String errorCode; } public enum LogLevel { INFO, WARN, ERROR, DEBUG, UNKNOWN; public static LogLevel fromString(String level) { if (level == null || level.trim().isEmpty()) { return UNKNOWN; } try { return valueOf(level.toUpperCase()); } catch (IllegalArgumentException e) { return UNKNOWN; } } } public static class LogEntryProcessor implements ItemProcessor<LogEntry, ProcessedLogEntry> { private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME; private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("ERROR_CODE\\[(\\w+)]"); @Override public ProcessedLogEntry process(LogEntry item) throws Exception { ProcessedLogEntry processedLogEntry = new ProcessedLogEntry(); processedLogEntry.setDateTime(parseDateTime(item.getDateTime())); processedLogEntry.setLevel(parseLevel(item.getLevel())); processedLogEntry.setMessage(item.getMessage()); processedLogEntry.setErrorCode(extractErrorCode(item.getMessage())); return processedLogEntry; } private LocalDateTime parseDateTime(String dateTime) { return LocalDateTime.parse(dateTime, ISO_FORMATTER); } private LogLevel parseLevel(String level) { return LogLevel.fromString(level); } private String extractErrorCode(String message) { if (message == null) { return null; } Matcher matcher = ERROR_CODE_PATTERN.matcher(message); if (matcher.find()) { return matcher.group(1); } // ERROR 문자열이 포함되어 있지만 패턴이 일치하지 않는 경우 if (message.contains("ERROR")) { return "UNKNOWN_ERROR"; } return null; } } } 윈도우즈에서는 scp 명령어 관련해서 windows 서비스에서 open-ssh-server 실행현재 사용하고 있는 사용자(windows 사용자) 가 관리자 권한을 보유 할 경우 programdata/sshd_config 파일 수정 필요기타 파일 권한 정리 필요로 인하여 scp 프로그램을 windows 환경의 intellij idea 에서 id, 비번치게끔 ide 콘솔에서 지원하지 않는거 같아. 그래서 제미니가 추천해준대로 실습 환경에서 scp 접속 단을 copy 로 그냥 퉁치는 것으로 바꿔놨어. 나처럼 windows 환경인 사람들이 있으면 혹시나 참고했으면 좋겠네. ObjectMapper, JavaTimeModule 같은 경우는 org.springframework.boot:spring-boot-starter-json 의존성 추가 필요
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
31강 이미지내용에 틀린 부분이 있는 것 같습니다.
해당사진의 3번째 서브넷부분은10.10.0.16/29가 맞지않나 싶습니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
ProductOption을 통한 FindProductOption에 관한 질문
ProductOption을 fetch해 올때 DB레벨에서 where이랑 orderby를 하지 않고 애플리케이션 레벨에서 코틀린 filter와 sort를 하신 이유가 따로 있을까요? 성능상 DB에서 전체적으로 데이터를 가져오고 인메모리 작업으로 filter와 sort를 하는게 불리하지 않나 싶어서 질문을 남깁니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
상수에 관련해서 질문있습니다.
요구 사항이 자주 변경되는 것을 가정하는 프로젝트인 만큼 isUnique에 관련된 상수나 Recent day에 관한 상수를 properties로 빼서 yml에 관리하는 방식으로 구현해보았는데. 실무에서는 어떤 경우에 yml에서 관리하는 방식을 고려하고 어느 상황에 그냥 상수를 코드에 남기는지 궁금합니다.
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
23강 문제4 질문드립니다.
"과도한 읽기 및 쓰기 트래픽이 몰려"라고 써있는데, 왜 답이 C가 되는지 잘 이해가 되지 않아 질문드립니다. 읽기 전용 복제본을 추가하면 쓰기 트래픽의 부하를 막을 수 있는건 아니라고 생각되는데 왜 답이 C가되나요? 혹시, 다른 답들이 애매해서 그런건가요? 아니면 읽기 트래픽을 줄일 수 있으니 쓰기트래픽이 많아도 읽기 트래픽의 부하를 줄임으로써 전체적인 트래픽의 부하가 줄어들기 때문인가요?
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
histories() 응답에 PointHistory.id를 포함한 이유가 궁금합니다/
안녕하세요.histories() 응답에 PointHistory.id가 포함되어 있던데, 이 값을 내려주신 의도가 궁금합니다.FE에서 이 id를 직접 활용해야 하는 지점이 있는지 궁금해서요.예를 들어 포인트 이력 상세 조회나 특정 이력을 식별해야 하는 기능을 염두에 두신 걸까요?현재로서는 다른 필드들만으로도 충분하지 않나 생각되어, id를 포함하신 이유가 궁금합니다!