묻고 답해요
140만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결AWS 배포 완벽가이드 (feat. Lightsail, Docker, ECS)
WSL에 설치한 Redis에 연결이 안 됩니다.
import express from "express"; import * as redis from "redis"; const PORT = 4000; const createApp = async () => { const app = express(); const client = redis.createClient({ url: "redis://localhost:6379" }); await client.connect(); app.use(express.json()); app.get("/", (req, res) => { res.status(200).send("hello from express"); }); return app; }; createApp().then((app) => { app.listen(PORT, () => { console.log(`App listening at port ${PORT}`); }); });Error: connect ECONNREFUSED 127.0.0.1:6379 [1] at createConnectionError (node:net:1647:14) [1] at afterConnectMultiple (node:net:1677:16) { [1] errno: -4078, [1] code: 'ECONNREFUSED', [1] syscall: 'connect', [1] address: '127.0.0.1', [1] port: 6379 [1] }WSL의 bind를 0.0.0.0으로 바꿔봄방화벽에서 6379 포트 허용함WSL의 ip를 localhost 대신에 넣어서 접속 시도이렇게 했는데 실행하면 계속 연결할 수 없다는 에러가 발생합니다. 혹시 해결 방법을 알 수 있을까요?
-
미해결실습으로 배우는 선착순 이벤트 시스템
안녕하세요 질문 있습니다!
현재 카프카로 데이터를 보내기전에 redis를 사용하여 발급된 쿠폰 개수에 대한 동시성 처리를 해서 개수에 대한 검증 로직이 있다고 앞서 강의에서 얘기를 하셨습니다. 그러면 발급된 쿠폰 개수가 100개 되고 난 이후의 요청은 그냥 무시하면 되나요?쿠폰이 천개, 만개 이렇게 매우 많다면 쿠폰 발급에 대한 요청을 바로 DB에 저장을 하면 DB에 부하가 심해져서 카프카를 도입해 이러한 부하를 낮춘다고 이해를 했습니다. 궁금한 점은 DB에 대한 부하를 낮춰도 이벤트 시기에 수많은 사용자들의 요청으로 인해 서버 자체에 대한 부하는 굉장히 심할꺼 같은데 서버에 대한 부하를 낮추는 방법은 없나요?현재 흐름이 쿠폰 요청 -> 서버 -> reids에서 쿠폰 개수 확인 -> 카프카 -> 컨슈머 -> DB 인데 이러한 흐름을 요청 -> 서버 -> 카프카 -> 컨슈머 -> redis에서 쿠폰 개수 확인 -> DB 이렇게 바꾸는 방식은 어떤지 궁금합니다. 이런식으로 하면 서버쪽에서 카프카로 데이터를 비동기로 전송한다면 서버 자체에도 부하가 낮아지지 않을까 라는 생각이 들어서 여쭤 봅니다.redis streams나 래빗엠큐 같은 다른 기능들도 있는데 Kafka를 사용하신 이유가 궁금합니다.만약 쿠폰 발급이 100개처럼 적게 발급하는 시스템이라면 굳이 카프카를 도입을 할 필요가 없는건가요?publisher가 카프카로 데이터를 보내면 consumer가 바로 받아와서 DB에 처리를 하면 안되겠죠? 이렇게 처리를 하면 바로 DB에 저장을 하는 상황이니 DB에 부하가 심해진다고 생각합니다.현재 강사님이 알려주신 코드를 바탕으로 시스템을 구축하고 여기에 부하 테스트를 한다고 했을때 어떤 식으로 단계를 잡아서 부하 테스트를 하면 좋을지 조언을 해주실 수 있을까요 한번에 너무 많은 질문해서 죄송합니다.
-
미해결15일간의 빅데이터 파일럿 프로젝트
클라우데라 ERR_SSL_PROTOCOL_ERROR 문제
안녕하세요VM환경구성 중 클라우데라가 접속이 안되어 질문드립니다.기존에 잘 접속이 되었었는데,CPU와 메모리 문제로 가상서버 2개를 구동하면컴퓨터가 다운이 되어 작업이 불가능한 상태였습니다그래서 램16GB, SSD 1TB를 추가하였는데요이후에 가상서버를 실행 후 클라우데라 접속이 되지 않습니다ㅜㅜserver01.hadoop.com:7180입력 후 화면기존에 C드라이브에 프로젝트 서버 파일과 버츄얼박스를 깔아두었는데 D드라이브로 옮겨 실행하니 되지 않았습니다.다시 모두 지우고, C드라이브에 프로젝트파일, 버츄얼박스 설치후 실행하여도 동일하게 프로토콜 에러가 나네요ㅜ 구글링을 해보았지만 .. 초반에 디스크 공간이 부족한 상태에서도 클라우데라 매니저 접속이 되었던걸 생각하면 어떤게 무엇인지 잘 파악이 되지 않습니다.버츄얼박스 서버2개 실행후 컴퓨터 성능 현황은 아래와 같습니다 메모장으로 hosts 파일 수정도 완료한 상태입니다. 버츄얼박스는 커뮤니티에 이전분들이 올려주신 질의내용 참고하여 제일 최근 버전(VirtualBox-7.0.20)으로 사용하고 있습니다.
-
해결됨대기업 근무하며 경험한 Redis를 야무지게 사용하는 방법 [이론편]
Redis란 무엇인가? 질문사항
강의의 내용중 3:35 즈음에인메모리 같은 ssd 같은 메모리를 사용을 한다고 하셨는데궁금증이 생겼습니다.ssd는 제가 알기로는 디스크로 알고 있는데메모리라고 하셔서 궁금하고,ssd를 언급하신 이유는 지속성 옵션 관련해서 말씀 하신건지이 두 부분이 궁금하여 질문 올려봅니다:)
-
미해결비전공자도 이해할 수 있는 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마다 매니저를 하나씩 만들어주어야할까요?
-
해결됨비전공자도 이해할 수 있는 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으로 여기서는 정상적으로 나오는데, 어디서 문제가 있는지 모르겠습니다.구글링을 해도 마땅한 답을 구할 수 없어서 질문 남깁니다!
-
해결됨비전공자도 이해할 수 있는 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 를 각각 적용해야 할 이유가 혹시 있을까요? 인터넷 기사나 블로그 등에서는 이렇게도 하고 저렇게도 하는 것 같습니다. 선생님의 의견이나 또 실무 상의 고려사항이 있는지 궁금합니다.
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
windows 에서 설치하는 분들, Permission denied 에러가 나는 경우 참고해주세요
windows 실습 환경에서 admin 계정이 아닌 경우에는 기본적으로 .rdb 파일에 대한 권한이 읽기만 설정되어 있는 것 같습니다.그런데, redis 자체가 .rdb 에 대한 snapshot 생성을 시도하려고 하는데 이때 쓰기 권한이 없어서 예외를 발생시킵니다. 처음 실습할 때는 (어차피 본격적으로 쓰는 건 Linux 에서 쓸 거라고 생각하고)무시하다가, 이후에 Spring Boot Project 실습할 때 같은 이유로 캐싱 자체가 안 되는 현상이 있었습니다.따라서 무시할 게 아니라 쓰기 권한을 부여해야 합니다. 관련된 내용을 사진 첨부드리니 참고 부탁드립니다.또한 해당 내용은 windows 에서 설치하고 PING 으로 확인할 때부터 나타나는 현상이므로, 혹시라도 제안드리자면 노션의 redis 설치 가이드 페이지에서 권한 문제 트러블슈팅으로 추가로 적어주시면 공유하기에 좋을 듯 합니다. Mac 은 잘 모르겠습니다...ㅎㅎdump.rdb 등 .rdb 확장자 파일에서 우클릭 후 속성 클릭 [보안] 탭으로 이동한 후 편집 클릭(현재 사용 중인 계정을 클릭하면 현재 부여된 사용 권한도 확인 가능)현재 사용 중인 계정을 찾아서 사용 권한에 수정과 쓰기 등등 필요한 권한 부여(잘 모르겠으면 모든 권한 클릭) 후 저장
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
LettuceConnectionFactory 를 RedisConnectionFactory 의 빈으로 등록하지 않는 특별한 이유가 있나요?
안녕하세요, 좋은 강의 감사합니다. 강의시간 3:10LettuceConnectionFactory 라는 게 있어서 한 번 들여다봤는데, RedisConnectionFactory 를 구현하는 객체로 보입니다. 이왕이면 RedisConnectionFactory 빈의 구현체로 등록하고, 또 RedisConnectionFactory 를 의존하도록 설계하고 싶은 욕구가 생겨서 그렇게 해봤는데, 일단 별 문제는 안 생긴 것 같습니다.LettuceConnectionFactory 를 실제로 RedisConnectionFactory 의 구현체로 등록해도 상관없나요? 아니면 혹시나 혹시나, RedisConnectionFactory 의 빈으로 등록하면 안 되는 이유가 있는 건가요?@Bean public RedisConnectionFactory lettuceConnectionFactory() { return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port)); }
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
페이지 데이터 캐싱할때 질문
페이지 데이터 캐싱할 때, 아래처럼 컨텐트만 보내는 게아니라@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(); }아래처럼 Page 객체 자체를 보내야,실제로 페이징 처리가 가능할텐데요@Cacheable(cacheNames = "getBoards",key = "'boards:page:'+ #page + ':size:' + #size", cacheManager = "boardCacheManager") public Page<Board> getBoards(int page, int size) { Pageable pageable = PageRequest.of(page - 1, size); Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable); return pageOfBoards; }이렇게 하면, Page 역직렬화시 오류가 발생하는데, 이렇게 Page<Board>를 보내줘야 할 때는 어떻게 보내야할지 모르겠습니다. 정확히 캐싱의 역직렬화가 어디까지 가능한지 파악이 잘 안되서..gpt한테 물어보니, Page 같은 특수한 객체는 역직렬화 방법이 없고, db에서 찾은 page를 분해해서 이걸 다시 dto로 감싸서 보내라는데, 이런 방식밖에 없는건지.. Page 데이터 보내실때 어떻게 보내시는지 궁금합니다.
-
미해결비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
RDS관련
java.lang.NullPointerException: Cannot invoke "org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(java.sql.SQLException, String)" because the return value of "org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.sqlExceptionHelper()" is null at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:116) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:290) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:123) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:77) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.boot.model.relational.Database.<init>(Database.java:45) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:221) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.<init>(InFlightMetadataCollectorImpl.java:189) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:171) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1431) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1502) ~[hibernate-core-6.5.2.Final.jar!/:6.5.2.Final] at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) ~[spring-orm-6.1.12.jar!/:6.1.12] at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:390) ~[spring-orm-6.1.12.jar!/:6.1.12] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-6.1.12.jar!/:6.1.12] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-6.1.12.jar!/:6.1.12] at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:366) ~[spring-orm-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1802) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) ~[spring-beans-6.1.12.jar!/:6.1.12] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:954) ~[spring-context-6.1.12.jar!/:6.1.12] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.12.jar!/:6.1.12] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.3.jar!/:3.3.3] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.3.jar!/:3.3.3] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.3.jar!/:3.3.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.3.jar!/:3.3.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.3.jar!/:3.3.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.3.jar!/:3.3.3] at redis_in_spring.practice.PracticeApplication.main(PracticeApplication.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) ~[practice-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) ~[practice-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT] at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) ~[practice-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]2024-08-27T12:34:29.323Z ERROR 4899 --- [ main] j.LocalContainerEntityManagerFactoryBean : 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-08-27T12:34:29.325Z WARN 4899 --- [ 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-08-27T12:34:29.333Z INFO 4899 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]2024-08-27T12:34:29.377Z INFO 4899 --- [ main] .s.b.a.l.ConditionEvaluationReportLogger : Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.2024-08-27T12:34:29.432Z ERROR 4899 --- [ 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)// ...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)// ...Caused 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)application.yml을 깃허브에 올라가지 않도록 처리한 후 EC2에서 직접 작성하는 식으로 해봤는데요. 위와 같은 에러가 계속 발생하는데 무슨 문제때문에 저 에러가 발생하는 것인지 도무지 원인을 모르겠습니다.[서비스]에서 MySQL80이 실행되는 것은 확인했습니다.인텔리제이에서 DataSource 지정시에도 Test Connection이 성공했지만 데이터 역시 안 뜨는 상황입니다.
-
미해결실습으로 배우는 선착순 이벤트 시스템
쿠폰 발급 유저 흐름에 대한 질문
쿠폰이 발급되고 바로 사용하려는 유저가 있다면 어떻게해야하나요? 실무에서 보통의 경우 어떻게 처리하는지 궁금한데요.예를 들어서, 쿠폰이 생성되려면 시간이 다소 소요될 수 있다는 안내 문구와 같은 정책으로 안고가는지.. 아니면 다른 좋은 방법이 있는지 궁금합니다.강의 내용 흐름레디스를 통해서 싱글 스레드로 쿠폰 개수 확인제한 범위 안이라면 클라이언트에게 쿠폰 발급 성공 응답비동기로 처리량을 조절하면서 쿠폰 데이터를 저장실제 유저가 아직 쿠폰 발급이 안되었는데, 쿠폰 사용 시도이 경우 어떻게 대응하는지 궁금합니다.
-
해결됨비전공자도 이해할 수 있는 Redis 입문/실전 (조회 성능 최적화편)
redis 클라우드 선택기준
현재 진행중인 프로젝트에서, NCP server로 spring과 db가 구동되고 있는데요.로컬에서 Redis를 적용시키고 있는 와중에, redis 클라우드를 어느곳을 선택해야할지 고민입니다.aws, ncp, redislabs 등등 ncp 자체에도 있을뿐만 아니라, 다른 클라우드 서비스도 많은데, 어떤 기준으로 골라야될지 잘 모르겠습니다. 성능상 aws를 ncp로 연결하는게 안좋을 거 같지만서도, ncp와 aws도 사용해봤다는 걸로 어필할 수 있는 요소가 될수 있을거 같다는 생각이 들어서요 . 그러나 성능/비용 둘다 안좋은데 왜 굳이 따로 썻냐고 이런부분을 지적받을 수도 있을거 같고요.. 조언부탁드립니다.
-
미해결실습으로 배우는 선착순 이벤트 시스템
수량 조절에 대한 질문이 있습니다.
안녕하세요! 먼저 강의 잘 들었습니다. 좋은 강의 만들어주셔서 감사합니다. 해당 강의에서 쿠폰 수량 조절을 Redis로 진행을 하는데 이에 대해 근본적으로 궁금한 점과 전체적으로 제가 이해한 것이 맞는지 여쭙고 싶습니다. 쿠폰 재고의 동시성을 싱글스레드 기반인 Redis를 통해 100개까지 생성해준다. -> 여기서 X-lock을 사용하는 비관적락을 사용해도 문제가 없지 않나요? Redis를 사용했을 때 장점은 직접적인 DB락을 걸지 않아 데드락이나 다른 위험을 방지할 수 있다는 것인가요?(강의에는 해당되지 않지만) 동시성 제어를 위해 비관적락, 낙관적락(x), Redis를 통한 수량제어 이렇게 해볼 수 있을 거 같은데 언제 Redis를 선택할지 감이 잘 오지 않습니다.강의에서 DB에 10,000개가 들어와서 서버 사용률이 높아졌는데, 결국 카프카로 보내 컨슈머들이 처리를 하게 된다면 똑같이 DB에는 10,000개의 부하가 오지 않나요? 단지 흐름 제어용이라고 보면 될까요? (카프카가 익숙하지 않습니다.)쿠폰의 재고가 아닌 만약 사용자가 상품을 구매할 때에도 해당 강의에 내용을 적용해볼 수 있을 것 같습니다.상품 구매할 때 중복 구매를 방지한다고 하면 Redis에 Set 키 값으로 [product:1(pid):member:1] 이런식으로 하면 마찬가지로 실수로 같은 사용자의 중복 결제도 막아볼 수 있을 것 같습니다! (의도라면 시간을 같이 넣어 조절해도 될 거 같아요) 잘 이해한게 맞을까요?