여러대의 Redis와 Valkey에 연결할 수 있도록 환경설정

This commit is contained in:
Klaus 2024-11-22 17:54:23 +09:00
parent 831bd731ca
commit 157e3a39b6
10 changed files with 122 additions and 113 deletions

View File

@ -2,17 +2,12 @@ package kr.co.vividnext.sodalive.admin.calculate
import kr.co.vividnext.sodalive.creator.admin.calculate.GetCreatorCalculateCommunityPostResponse import kr.co.vividnext.sodalive.creator.admin.calculate.GetCreatorCalculateCommunityPostResponse
import kr.co.vividnext.sodalive.extensions.convertLocalDateTime import kr.co.vividnext.sodalive.extensions.convertLocalDateTime
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
@Service @Service
class AdminCalculateService(private val repository: AdminCalculateQueryRepository) { class AdminCalculateService(private val repository: AdminCalculateQueryRepository) {
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'calculateLive:' + " + "#startDateStr + ':' + #endDateStr"
)
fun getCalculateLive(startDateStr: String, endDateStr: String): List<GetCalculateLiveResponse> { fun getCalculateLive(startDateStr: String, endDateStr: String): List<GetCalculateLiveResponse> {
val startDate = startDateStr.convertLocalDateTime() val startDate = startDateStr.convertLocalDateTime()
val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59) val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59)
@ -23,10 +18,6 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'calculateContent:' + " + "#startDateStr + ':' + #endDateStr"
)
fun getCalculateContentList(startDateStr: String, endDateStr: String): List<GetCalculateContentResponse> { fun getCalculateContentList(startDateStr: String, endDateStr: String): List<GetCalculateContentResponse> {
val startDate = startDateStr.convertLocalDateTime() val startDate = startDateStr.convertLocalDateTime()
val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59) val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59)
@ -37,10 +28,6 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'cumulativeSalesByContent:' + " + "#offset + ':' + #limit"
)
fun getCumulativeSalesByContent(offset: Long, limit: Long): GetCumulativeSalesByContentResponse { fun getCumulativeSalesByContent(offset: Long, limit: Long): GetCumulativeSalesByContentResponse {
val totalCount = repository.getCumulativeSalesByContentTotalCount() val totalCount = repository.getCumulativeSalesByContentTotalCount()
val items = repository val items = repository
@ -51,10 +38,6 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'calculateContentDonationList2:' + " + "#startDateStr + ':' + #endDateStr"
)
fun getCalculateContentDonationList( fun getCalculateContentDonationList(
startDateStr: String, startDateStr: String,
endDateStr: String endDateStr: String
@ -68,10 +51,6 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'calculateCommunityPost:' + " + "#startDateStr + ':' + #endDateStr + ':' + #offset"
)
fun getCalculateCommunityPost( fun getCalculateCommunityPost(
startDateStr: String, startDateStr: String,
endDateStr: String, endDateStr: String,

View File

@ -0,0 +1,18 @@
package kr.co.vividnext.sodalive.configs
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.FilterType
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
@Configuration
@EnableJpaRepositories(
basePackages = ["kr.co.vividnext.sodalive"],
includeFilters = [
ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = [org.springframework.data.jpa.repository.JpaRepository::class]
)
]
)
class JpaConfig

View File

@ -1,32 +1,40 @@
package kr.co.vividnext.sodalive.configs package kr.co.vividnext.sodalive.configs
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration import org.springframework.context.annotation.FilterType
import org.springframework.data.redis.cache.RedisCacheManager
import org.springframework.data.redis.connection.RedisConnectionFactory import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.connection.RedisStandaloneConfiguration import org.springframework.data.redis.connection.RedisStandaloneConfiguration
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory
import org.springframework.data.redis.core.RedisTemplate import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories import org.springframework.data.redis.repository.configuration.EnableRedisRepositories
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer
import java.time.Duration
@Configuration @Configuration
@EnableCaching @EnableRedisRepositories(
@EnableRedisRepositories basePackages = ["kr.co.vividnext.sodalive"],
redisTemplateRef = "redisTemplate",
excludeFilters = [
ComponentScan.Filter(
type = FilterType.REGEX,
pattern = ["kr\\.co\\.vividnext\\.sodalive\\.v2\\..*"]
),
ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = [org.springframework.data.jpa.repository.JpaRepository::class]
)
]
)
class RedisConfig( class RedisConfig(
@Value("\${spring.redis.host}") @Value("\${spring.redis.host}")
private val host: String, private val host: String,
@Value("\${spring.redis.port}") @Value("\${spring.redis.port}")
private val port: Int private val port: Int
) { ) {
@Bean @Bean(name = ["redisConnectionFactory"])
fun redisConnectionFactory(): RedisConnectionFactory { fun redisConnectionFactory(): RedisConnectionFactory {
val clientConfiguration = LettuceClientConfiguration.builder() val clientConfiguration = LettuceClientConfiguration.builder()
.useSsl() .useSsl()
@ -36,53 +44,15 @@ class RedisConfig(
return LettuceConnectionFactory(RedisStandaloneConfiguration(host, port), clientConfiguration) return LettuceConnectionFactory(RedisStandaloneConfiguration(host, port), clientConfiguration)
} }
@Bean @Bean(name = ["redisTemplate"])
fun redisTemplate(): RedisTemplate<*, *> { fun redisTemplate(): RedisTemplate<*, *> {
val redisTemplate: RedisTemplate<*, *> = RedisTemplate<Any, Any>() val redisTemplate: RedisTemplate<*, *> = RedisTemplate<Any, Any>()
redisTemplate.setConnectionFactory(redisConnectionFactory()) redisTemplate.setConnectionFactory(redisConnectionFactory())
return redisTemplate return redisTemplate
} }
@Bean @Bean(name = ["redisStringRedisTemplate"])
fun cacheManager(redisConnectionFactory: RedisConnectionFactory): RedisCacheManager { fun redisStringRedisTemplate(): StringRedisTemplate {
val defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig() return StringRedisTemplate(redisConnectionFactory())
.entryTtl(Duration.ofMinutes(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
GenericJackson2JsonRedisSerializer()
)
)
val cacheConfigMap = mutableMapOf<String, RedisCacheConfiguration>()
cacheConfigMap["default"] = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
GenericJackson2JsonRedisSerializer()
)
)
cacheConfigMap["cache_ttl_3_days"] = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(3))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
GenericJackson2JsonRedisSerializer()
)
)
cacheConfigMap["cache_ttl_3_hours"] = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(3))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
GenericJackson2JsonRedisSerializer()
)
)
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultCacheConfig)
.withInitialCacheConfigurations(cacheConfigMap)
.build()
} }
} }

View File

@ -0,0 +1,66 @@
package kr.co.vividnext.sodalive.configs
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.FilterType
import org.springframework.data.redis.connection.RedisClusterConfiguration
import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories
import java.time.Duration
@Configuration
@EnableRedisRepositories(
basePackages = ["kr.co.vividnext.sodalive.v2"],
redisTemplateRef = "valkeyTemplate",
includeFilters = [
ComponentScan.Filter(
type = FilterType.REGEX,
pattern = ["kr\\.co\\.vividnext\\.sodalive\\.v2\\..*"]
)
],
excludeFilters = [
ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = [org.springframework.data.jpa.repository.JpaRepository::class]
)
]
)
class ValkeyConfig(
@Value("\${spring.valkey.host}")
private val host: String,
@Value("\${spring.valkey.port}")
private val port: Int
) {
@Bean(name = ["valkeyConnectionFactory"])
fun valkeyConnectionFactory(): RedisConnectionFactory {
val clusterConfig = RedisClusterConfiguration()
clusterConfig.clusterNode(host, port)
val clientConfig = LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(5))
.shutdownTimeout(Duration.ofSeconds(5))
.useSsl()
.disablePeerVerification()
.build()
return LettuceConnectionFactory(clusterConfig, clientConfig)
}
@Bean(name = ["valkeyTemplate"])
fun valkeyTemplate(): RedisTemplate<*, *> {
val redisTemplate: RedisTemplate<*, *> = RedisTemplate<Any, Any>()
redisTemplate.setConnectionFactory(valkeyConnectionFactory())
return redisTemplate
}
@Bean(name = ["valkeyStringRedisTemplate"])
fun valkeyStringRedisTemplate(): StringRedisTemplate {
return StringRedisTemplate(valkeyConnectionFactory())
}
}

View File

@ -28,7 +28,6 @@ import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import kr.co.vividnext.sodalive.utils.generateFileName import kr.co.vividnext.sodalive.utils.generateFileName
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.Cacheable
import org.springframework.context.ApplicationEventPublisher import org.springframework.context.ApplicationEventPublisher
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -717,11 +716,6 @@ class AudioContentService(
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_days"],
key = "'contentRanking:' + ':' +" +
"#isAdult + ':' + #startDate + ':' + #endDate + ':' + #sortType + ':' + #offset + ':' + #limit"
)
fun getAudioContentRanking( fun getAudioContentRanking(
isAdult: Boolean, isAdult: Boolean,
startDate: LocalDateTime, startDate: LocalDateTime,

View File

@ -10,7 +10,6 @@ import kr.co.vividnext.sodalive.event.EventItem
import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import org.springframework.beans.factory.annotation.Value import org.springframework.beans.factory.annotation.Value
import org.springframework.cache.annotation.Cacheable
import org.springframework.data.domain.Pageable import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
@ -27,7 +26,6 @@ class AudioContentMainService(
private val imageHost: String private val imageHost: String
) { ) {
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(cacheNames = ["default"], key = "'themeList:' + ':' + #isAdult")
fun getThemeList(isAdult: Boolean): List<String> { fun getThemeList(isAdult: Boolean): List<String> {
return audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult) return audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult)
} }
@ -81,7 +79,6 @@ class AudioContentMainService(
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(cacheNames = ["default"], key = "'newContentUploadCreatorList:' + #memberId + ':' + #isAdult")
fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<GetNewContentUploadCreator> { fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<GetNewContentUploadCreator> {
return repository.getNewContentUploadCreatorList( return repository.getNewContentUploadCreatorList(
cloudfrontHost = imageHost, cloudfrontHost = imageHost,
@ -93,7 +90,6 @@ class AudioContentMainService(
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(cacheNames = ["default"], key = "'contentMainBannerList:' + #memberId + ':' + #isAdult")
fun getAudioContentMainBannerList(memberId: Long, isAdult: Boolean) = fun getAudioContentMainBannerList(memberId: Long, isAdult: Boolean) =
repository.getAudioContentMainBannerList(isAdult = isAdult) repository.getAudioContentMainBannerList(isAdult = isAdult)
.asSequence() .asSequence()
@ -156,11 +152,6 @@ class AudioContentMainService(
.toList() .toList()
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["default"],
key = "'getAudioContentCurationListWithPaging:' + #memberId + ':' + #isAdult + ':' + #contentType" +
"+ ':' + #offset + ':' + #limit"
)
fun getAudioContentCurationListWithPaging( fun getAudioContentCurationListWithPaging(
memberId: Long, memberId: Long,
isAdult: Boolean, isAdult: Boolean,

View File

@ -4,17 +4,12 @@ import kr.co.vividnext.sodalive.admin.calculate.GetCalculateLiveResponse
import kr.co.vividnext.sodalive.admin.calculate.GetCumulativeSalesByContentResponse import kr.co.vividnext.sodalive.admin.calculate.GetCumulativeSalesByContentResponse
import kr.co.vividnext.sodalive.extensions.convertLocalDateTime import kr.co.vividnext.sodalive.extensions.convertLocalDateTime
import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.Member
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
@Service @Service
class CreatorAdminCalculateService(private val repository: CreatorAdminCalculateQueryRepository) { class CreatorAdminCalculateService(private val repository: CreatorAdminCalculateQueryRepository) {
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["default"],
key = "'creatorCalculateLive:v20240403_01:' + " + "#member + ':' + #startDateStr + ':' + #endDateStr"
)
fun getCalculateLive(startDateStr: String, endDateStr: String, member: Member): List<GetCalculateLiveResponse> { fun getCalculateLive(startDateStr: String, endDateStr: String, member: Member): List<GetCalculateLiveResponse> {
val startDate = startDateStr.convertLocalDateTime() val startDate = startDateStr.convertLocalDateTime()
val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59) val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59)
@ -25,11 +20,6 @@ class CreatorAdminCalculateService(private val repository: CreatorAdminCalculate
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'creatorCalculateContentList:v20240403_01:' + " +
"#startDateStr + ':' + #endDateStr + ':' + #memberId + ':' + #offset + ':' + #limit"
)
fun getCalculateContentList( fun getCalculateContentList(
startDateStr: String, startDateStr: String,
endDateStr: String, endDateStr: String,
@ -48,10 +38,6 @@ class CreatorAdminCalculateService(private val repository: CreatorAdminCalculate
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'creatorCumulativeSalesByContent:' + " + "#memberId + ':' + #offset + ':' + #limit"
)
fun getCumulativeSalesByContent(memberId: Long, offset: Long, limit: Long): GetCumulativeSalesByContentResponse { fun getCumulativeSalesByContent(memberId: Long, offset: Long, limit: Long): GetCumulativeSalesByContentResponse {
val totalCount = repository.getCumulativeSalesByContentTotalCount(memberId) val totalCount = repository.getCumulativeSalesByContentTotalCount(memberId)
val items = repository val items = repository
@ -62,11 +48,6 @@ class CreatorAdminCalculateService(private val repository: CreatorAdminCalculate
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'creatorCalculateContentDonationList2:' + " +
"#startDateStr + ':' + #endDateStr + ':' + #memberId + ':' + #offset + ':' + #limit"
)
fun getCalculateContentDonationList( fun getCalculateContentDonationList(
startDateStr: String, startDateStr: String,
endDateStr: String, endDateStr: String,
@ -86,11 +67,6 @@ class CreatorAdminCalculateService(private val repository: CreatorAdminCalculate
} }
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Cacheable(
cacheNames = ["cache_ttl_3_hours"],
key = "'creatorCalculateCommunityPost:' + " +
"#startDateStr + ':' + #endDateStr + ':' + #memberId + ':' + #offset + ':' + #limit"
)
fun getCalculateCommunityPost( fun getCalculateCommunityPost(
startDateStr: String, startDateStr: String,
endDateStr: String, endDateStr: String,

View File

@ -1,10 +1,13 @@
package kr.co.vividnext.sodalive.live.roulette package kr.co.vividnext.sodalive.live.roulette
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.data.redis.core.StringRedisTemplate import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class RedisIdGenerator(private val stringRedisTemplate: StringRedisTemplate) { class RedisIdGenerator(
@Qualifier("redisStringRedisTemplate") private val stringRedisTemplate: StringRedisTemplate
) {
fun generateId(key: String): Long { fun generateId(key: String): Long {
return stringRedisTemplate.opsForValue().increment(key, 1) ?: 1L return stringRedisTemplate.opsForValue().increment(key, 1) ?: 1L
} }

View File

@ -0,0 +1,8 @@
package kr.co.vividnext.sodalive.v2
import kr.co.vividnext.sodalive.member.token.MemberToken
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
@Repository
interface NewMemberTokenRepository : CrudRepository<MemberToken, Long>

View File

@ -52,6 +52,10 @@ jwt:
secret: ${JWT_SECRET} secret: ${JWT_SECRET}
spring: spring:
valkey:
host: ${VALKEY_HOST}
port: ${VALKEY_PORT}
redis: redis:
host: ${REDIS_HOST} host: ${REDIS_HOST}
port: ${REDIS_PORT} port: ${REDIS_PORT}