묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
k6의 결과 해석
안녕하세요. 강의에서 k6를 실행하기 위해 30명의 가상유저가 10초동안 요청을 무한히 보내도록 설정하셨습니다. 그 결과 http_reqs 값이 1.66/s 가 나왔습니다. 이 값은 시스템의 대역폭 max값으로 이해해도 되나요?30명, 10초 설정값이 아니더라도 100명, 10초 설정값으로 진행해도 1.66/s 에 근사한 값이 나와야하는지 궁금합니다. (시스템이 처리할 수 있는 능력 의 Maximum은 항상 일정해야하지 않을까 라는 생각에 질문드립니다.)
-
미해결대규모 트래픽 처리를 위한 부하테스트 입문/실전
cpu, memory 모두 100%를 치지 않았을 때 병목을 확인하는 방법
안녕하세요! 수업 잘 듣고 저희 서비스에서 테스트를 해보고 있습니다. duration 3m, target 500 으로 테스트를 해보았는데, 46TPS 정도 에서 병목이 생긴걸로 파악 했습니다. 다만 메트릭들을 확인해보니, ec2 메모리 사용률은 46% 정도고, CPU 사용율도 58% 정도며, DB 의 메모리도 충분히 남아있고, CPU 사용율도 59%정도로 여유가 있어보이는데요, 이 메트릭 외에도 병목을 확인할 수 있는 메트릭이 있을까요? 예시로 보여주셨던 걸로는 100% 에 가깝게 수치가 튀어야할거 같은데, 그정도가 아닌 상태에서 병목이 발생해서요!
-
미해결대규모 트래픽 처리를 위한 부하테스트 입문/실전
ec2에 세팅을 하는이유
안녕하세요혹시 로컬 말고 ec2에서 세팅을 하는 이유가 있는지 궁금합니다
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
Jackson2JsonRedisSerializer에 대한 궁금증
GenericJackson2JsonRedisSerializer를 사용할 때 저장되는 캐싱 데이터는 다음과 같았습니다."[{\"@class\":\"org.example.package..\",\"id\":\"123984\",\"title\":\"title0123984\",...,강의상에 나온 데이터 순서?? 와는 조금 다르게 package 다음에 @class 이후 데이터가 저장되는 구조가 나오는 것을 확인했습니다.이때 캐싱된 데이터를 조회하려고 하는데 com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected VALUE_STRING: need String, Number of Boolean value that contains type id (for subtype of java.lang.Object) 에러가 발생했습니다.너무 궁금해서 GenericJackson2JsonRedisSerializer에 대해서 알아보고 있는데, 여전히 에러가 발생하는 이유를 잘 모르겠습니다ㅜㅜ데이터가 캐싱되어서 저장될 때 구조가 다르게 들어가는 이유가 궁금합니다 아 물론 강의 후반부처럼 Jackson2JsonRedisSerializer를 사용했을 때는 정상적으로 동작했습니다.
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
사용된 어노테이션에 관한 질문
5:12분경 createdAt에서 @CreatedDate를 제외한 나머지 어노테이션들을 특별히 사용하신 이유가 있으실까요?
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
Redis 사용 방식에 대해서 질문 있습니다
안녕하세요 레디스를 공부하면서 궁금한게 있습니다.제가 토이프로젝트를 하면서 상품 검색 입력시 버튼 하나씩 누를때마다(이벤트 keyup 사용) 백엔드와 통신하여 입력창 하단에 자동완성 기능창을 만들려고 하고 있습니다.아무래도 버튼 하나씩 누를때마다 통신해야되니 빠르게 통신해야될 것 같아서 redis를 사용했습니다.상품 등록할 때 DB와 redis에 저장하고 (redis에는 상품 이름만 저장했습니다.)입력창 하단의 자동완성은 redis를 통해 상품 이름을 출력하고 출력된 상품이름을 선택시 DB를 통해서 상품 상세정보를 가져오는 식으로 했는데배운대로라면 Cache Aside 전략과 다른데 이럴때는 어떻게 구성해야되나요?아니면 SQL 튜닝만 잘해도 굳이 redis는 필요없는건지 궁금합니다.아무래도 버튼 누를때마다 통신하다보니 SQL은 느릴까봐 싶어 조바심이 나네요ㅠㅠ 알아보니 최근검색어나 인기검색어 같은 경우도 redis로 한다고하는데 이런것들도 굳이 출력하자면 DB로만 사용하여 출력이 될텐데 이게 Cache Aside 전략과 어떤 관계가 있는지 감이 안잡힙니다실무뛰면서 redis를 써본적이 없고 거의 db로만 해결하다보니 redis 사용예시를 잘 모르겠습니다
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
aws elasticcache redis 툴 접속.
안녕하세요. 강의 잘 들었습니다.강의를 듣다보니 의문이 드는 점이 있어 질문드립니다.redis를 사용하다 보면 redisinsight같은 gui 툴을 통해 데이터를 확인하는데 운영관점에서 더 편한데요.aws elasticcache redis가 외부 로컬에서 접속이 안되면aws elasticcache는 데이터 확인을 툴로 못하는건가요? 실무에서 운영을 하다보면 분명 직접 데이터를 체크를 해야하는 케이스가 발생하는데 이걸 일일이 cli 명령어 찾는다는 것은 돈을 주고 aws 사용하는 고객입장에서는 너무 불편하다고 생각들어 문의드립니다.
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
Redis를 사용하는 이유
캐싱을 위해 Redis를 많이 사용한다고 생각하고 있었는데 SQL튜닝으로 해결되는 부분이 있는거군요! 그러면 일반적으로 현업에서 Redis를 사용하는 이유 중 어떤 이유로 가장 많이 사용하는지 여쭤볼 수 있을까요??
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
로컬에서 docker compose 명령어 실행 시
로컬에서 docker compose up --build -d 명령어 실행 시 아래와 같은 에러가 발생합니다.Cannot connect to the Docker daemon at unix:///Users/milaju/.docker/run/docker.sock. Is the docker daemon running?따로 설정을 해줘야 하는 부분이 있을까요?
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
EC2 서버 실행시키기 관련하여
# 스프링 프로젝트 경로로 들어가서 아래 명령어 실행$ ./gradlew clean build -x test $ cd build/libs$ java -jar -Dspring.profiles.active=prod {빌드된 jar 파일명}서버 실행시키기 명령어 단계에서 $ java -jar -Dspring.profiles.active=prod {빌드된 jar 파일명} 실행 시 ec2 터미널 창에서 아래와 같은 에러가 발생하게 됩니다. 현재 jar 파일은 그림과 같이 생성되었고 명령어는 java -jar -Dspring.profiles.activate=prod demo-0.0.1-SNAPSHOT.jar 이렇게 진행하였습니다.Failed to initialize JPA EntityManagerFactory: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided)2024-10-03T16:57:37.160Z WARN 5523 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided)2024-10-03T16:57:37.166Z INFO 5523 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]2024-10-03T16:57:37.213Z INFO 5523 --- [ main] .s.b.a.l.ConditionEvaluationReportLogger : Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.2024-10-03T16:57:37.243Z ERROR 5523 --- [ main] o.s.boot.SpringApplication : Application run failedorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:954) ~[spring-context-6.1.13.jar!/:6.1.13] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.13.jar!/:6.1.13] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.4.jar!/:3.3.4] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.4.jar!/:3.3.4] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.4.jar!/:3.3.4] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.4.jar!/:3.3.4] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.4.jar!/:3.3.4] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.4.jar!/:3.3.4] at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[!/:0.0.1-SNAPSHOT] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na] at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided) at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:276) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.boot.model.relational.Database.<init>(Database.java:45) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:221) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:189) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:171) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1431) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1502) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) ~[spring-orm-6.1.13.jar!/:6.1.13] at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:390) ~[spring-orm-6.1.13.jar!/:6.1.13] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-6.1.13.jar!/:6.1.13] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-6.1.13.jar!/:6.1.13] at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:366) ~[spring-orm-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-6.1.13.jar!/:6.1.13] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1802) ~[spring-beans-6.1.13.jar!/:6.1.13] ... 22 common frames omittedCaused by: org.hibernate.HibernateException: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided) at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:191) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:87) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentWithDefaults(JdbcEnvironmentInitiator.java:153) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:364) ~[hibernate-core-6.5.3.Final.jar!/:6.5.3.Final]
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
캐싱 객체 직렬화/역직렬화
안녕하세요! 강의를 수강하고 제 프로젝트에서 캐싱을 적용하고 싶어서 따라 적용해보고 있습니다. package com.ecommerceproduct.api.controller.product.dto.response; import com.ecommerceproduct.domain.product.repository.dao.ProductDetailDao; import com.ecommerceproduct.domain.product.type.OptionType; import com.ecommerceproduct.domain.product.type.ProductCategory; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import lombok.Builder; @Builder public record ProductDetailResponse( Long id, String name, StoreInfo store, int quantity, ProductCategory category, String thumbnailImgUrl, int basePrice, @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonSerialize(using = LocalDateTimeSerializer.class) @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdDateTime, List<ProductOptionInfo> options ) { public static ProductDetailResponse from(List<ProductDetailDao> daos){ List<ProductOptionInfo> options = new ArrayList<>(); daos.forEach(dao -> options.add(ProductOptionInfo.from(dao.option()))); ProductDetailDao dao = daos.get(0); return ProductDetailResponse.builder() .id(dao.id()) .name(dao.name()) .store(StoreInfo.from(dao.store())) .quantity(dao.quantity()) .category(dao.category()) .thumbnailImgUrl(dao.thumbnailImgUrl()) .basePrice(dao.basePrice()) .createdDateTime(dao.createdDateTime()) .options(options) .build(); } public record StoreInfo( Long storeId, String name ) { public static StoreInfo from(ProductDetailDao.StoreInfo daoStore){ return new StoreInfo(daoStore.storeId(), daoStore.name()); } } public record ProductOptionInfo( Long optionId, String name, int count, int price, OptionType optionType ){ public static ProductOptionInfo from(ProductDetailDao.ProductOptionInfo option){ return new ProductOptionInfo( option.optionId(), option.name(), option.count(), option.price(), option.optionType() ); } } } 해당 클래스를 반환하는 메서드에 @Cacheable을 적용하려고 합니다.@Cacheable(cacheNames = "getProduct", key = "'product:productId:' + #productId", cacheManager = "매니저이름") public ProductDetailResponse get(Long productId) { return ProductDetailResponse.from(productRepository.findWithOptions(productId)); }강의에서 알려주신 매니저와 동일하게 매니저를 bean으로 등록해서 사용해본결과직렬화/역질렬화가 안되는것으로 보입니다. 매니저에 설정을 serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer( new Jackson2JsonRedisSerializer<>(objectMapper, ProductDetailResponse.class)))처럼 명시적으로 타입을 지정해주면 문제가 없는 것 같은데 record여서 안되는 걸까 싶어서 class로 바꾸어도 되지는 않더라고요! 강의에서의 Board 클래스는 문제없이 직렬화/역직렬화가 되는데 제가만든 dto가 안되는 이유는 강의의 Board가 @Entity클래스여서 인걸까요??그렇다면 dto로 쓰려면 매니저를 각각의 dto마다 매니저를 하나씩 만들어주어야할까요?
-
미해결백엔드 애플리케이션 성능 개선하기 - 기초편
AWS 실습
안녕하세요. 강의 잘 듣고 있습니다 🙂. Vultr Payment로 등록할 카드가 알 수 없는 이유로 거절되고 있습니다. AWS EC2, RDS로 실습을 대체해도 문제가 없을까요?
-
미해결백엔드 애플리케이션 성능 개선하기 - 기초편
레디스에 대해서 질문드립니다.
안녕하세요? 끝까지 강의를 들었는데, 알차고 재미있는 강의였습니다. 강의를 보다보니 레디스를 사용해도 성능적인 차이가 많이 안나는 것을 보고 궁금한 점이 있어서 질문드립니다. 사실 주변에서 캐시로 레디스를 무조건적으로 사용을 하시는 경우를 많이 봤는데요, 제가 생각할때는 결국 I/O대기시간이 일반적인 api에서 큰 부분을 차지하고, 결국 레디스라는 것도 IO를 기다려야 하는 것은 동일하지 않나요? 그렇게 따지고 보면 강의에서 보여주신 것처럼 레디스를 사용하더라도 성능적 차이가 많이 안나는 경우가 꽤나 빈번할 것 같은데, 강사님의 의견이 궁금합니다. 레디스 내에서 해시값을 기반으로 데이터를 조회하는 속도야 빠르겠지만, 애초에 요청받았을 때 수행해야하는 [작업] 그 자체의 비중보다 [IO]를 대기하는 시간이 큰 경우가많은, 예를 들면 DB에서 단순히 레코드한줄을 조회한다든지 하는 기능이라고 하면 레디스를 쓰는 건 비용까지 고려했을 때 굳이 할 필요가 없는 선택처럼 느껴집니다.결국 레디스는 IO보다 요청에 따라 수행해야 하는 작업 그자체의 크기가 조금 클때 그제서야 유의미해 보이는데 어떻게 생각하시는지 의견이 궁금합니다! 추가로 강의 잘들었습니다. 혹시 다음 강의는 언제쯤 출시할 예정이신지 알 수 잇을까요?
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
@Cacheable key 속성에서 page, size 파라미터값 null
BoardService.class@Cacheable( cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size", cacheManager = "boardCacheManager" ) public List<Board> getBoards(int page, int size) { log.info("page={},size={}", page, size); Pageable pageable = PageRequest.of(page - 1, size); Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable); return pageOfBoards.getContent(); }BoardController.class@GetMapping public List<Board> getBoards( @RequestParam(name = "page", defaultValue = "1") int page, @RequestParam(name = "size", defaultValue = "10") int size ) { log.info("page={}, size={}", page, size); return boardService.getBoards(page, size); }#page, #size 값에 모두 null이 저장되는 것 같습니다.위 코드에서처럼 BoardService.getBoards(), BoardController.getBoards() 두 메서드 전부 page, size 값을 로그로 출력해보니 각각 1, 10으로 여기서는 정상적으로 나오는데, 어디서 문제가 있는지 모르겠습니다.구글링을 해도 마땅한 답을 구할 수 없어서 질문 남깁니다!
-
미해결백엔드 애플리케이션 성능 개선하기 - 기초편
비동기 분리에 대해서 질문드립니다.
안녕하세요? 강의쭉 잘 듣고 있습니다.강의에서 말씀해주시고자 하는 부분은 [IO대기시간이 있는 작업을 비동기로 돌려서 클라이언트쪽에 우선응답을 빠르게 주고, 나머지는 따로 알아서 처리하는 것]으로 이해했습니다. 말씀해주신 방법은 충분히 사용할 수 있는 방법이라고 생각합니다. 그런데 조금 논외로, 이렇게 분리하는 방식이 좋은 방향성인가?에 대해서 궁금증이 생기고 사실 이 부분에 대해 최근 현업에서도 꽤 고민하고 있어서 질문을 드립니다. 아무래도 쪼렙 주니어개발자다보니.. 이런 부분에서 부족함과 의문이 많이 있네요 ㅠㅠ 제 생각에, 단축 url을 만드는 api가 200을 내려준다고하면 저장까지 올바르게 완료됨을 전제해야한다고 생각합니다. 이렇게 생각하는 이유는, 단축 url을 저장하는 것까지가 일종의 핵심적인 로직에 포함되지 않나? 하는 생각입니다. 예를 들어 로그를 찍거나, 혹은 비즈니스로직이여도 그렇게 중요하지 않은 부분이라면 마음편하게 완료를 보장하지 않는 async로 돌려도 될것 같습니다.하지만 url저장처럼 핵심적인 로직에 관한 부분에 대해서는 200을 내려줄 거면 저장도 올바르게 보장되어야 하지 않나? 하는 생각이 듭니다. 다르게 말하면, 내려준 단축 url이 정상적으로 동작하지 않는데 200을 내려줘도 되나? 에 대한 궁금증입니다.(물론 핵심적인 로직에 대한 판단은 개개인마다 또 상황마다 다를 수 있지만요) 결론적으로 여쭤보고 싶은 부분은 아래와 같습니다1) 비동기로 나누는 부분의 기준이 강사님에게 있으실 것 같은데, 보통 어떤 기준으로 나누시나요?2) 추가로, 핸들링을 어떤식으로 하시는지도 궁금합니다. 예를 들면 위와 같이 저장하는 로직을 비동기로 뺏을 때, 실패한다면 보통 어떤식으로 핸들링을 하시나요?
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
도커 컴포즈
현재 개인 프로젝트에 EC2에 도커 컴포즈로 프론트, 백엔드, db까지 실행되도록 아키텍처를 구성 했습니다.그런데 말씀하신 것처럼 RDS, elastiCache 를 분리시켜서 아키텍처를 구성 해야 할 필요성이 있을까요?
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
vCPU 할당량 증가
안녕하세요 강의 잘 듣고 있습니다!You have requested more vCPU capacity than your current vCPU limit of 1 allows for the instance bucket that the specified instance type belongs to. Please visit http://aws.amazon.com/contact-us/ec2-request to request an adjustment to this limit. <EC2, RDS, Spring Boot, Redis 셋팅>강의 중t3s.small 로 인스턴스를 설정하려 하는데 위와 같이 문구가 나오면서 '인스턴스 시작 실패'가 떴습니다.할당량 증가 요청을 보내기 위해 ' 새 할당량 값'을 넣어야 되는데 얼마를 넣어야 되는지 알 수 있을까요?
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
Cacheable key값 설정에서 null
@Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size", cacheManager = "boardCacheManager") public List<Board> getBoards(int page, int size) { Pageable pageable = PageRequest.of(page - 1, size); Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable); return pageOfBoards.getContent(); } }여기서 key = "'boards:page:' + #page + ':size:' + #size"레디스에 저장되는 키값은 "getBoards::boards:page:null:size:null" 이렇게 저장이 됩니다. 혹시 null이 들어가는 이유가 있을까요? page와 size의 데이터도 잘 넘어오고 레디스에서 저 키값으로 조회를 하면 안에 데이터는 잘 들어가 있습니다. #page와 #size가 null인 이유가 있을까요?
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
파라미터에 있는 값이 아닌 외부에 있는 값을 캐시 key에 넣을 수 있나요?
파라미터에 있는 값이 아닌 외부에 있는 값을 캐시 key에 넣을 수 있나요?
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
CacheManager 는 한 번만 등록하나요? 아니면 각 도메인마다 등록하나요?
안녕하세요, 좋은 강의 감사합니다. Spring Boot 에서 Redis 세팅 추가하는 편에서, CacheManager 를 하나만 등록해서 사용하고 있습니다. 그리고 이를 활용하는 API 가 1개 뿐인데, 이름이 boardCacheManager 로 정확히 Board 도메인에 대한 전용 CacheManager 인 것처럼 보입니다. 도메인 별로 CachaManager 를 각각 만들면서 사용을 하는 게 좀 더 바람직한 방법인가요?만약 그렇다면, 각 도메인 별로 설정을 관리하고 유지보수성을 높이기 위함인가요?만약 CachaManager 를 도메인 별로 값이나 타입을 다르게 적용하지 않고 프로젝트 전체에 대해서 동일하게 적용을 하기로 결정했다면, 그때에도 CacheManager 를 각각 적용해야 할 이유가 혹시 있을까요? 인터넷 기사나 블로그 등에서는 이렇게도 하고 저렇게도 하는 것 같습니다. 선생님의 의견이나 또 실무 상의 고려사항이 있는지 궁금합니다.