๐ ๋ชฉ์ฐจ
์ง๋๋ฒ ํฌ์คํ ์์ Redis์ ์ด๋ค ํน์ง ๋๋ฌธ์ ์ฑ๋ฅ์ด ๊ฐ์ ๋๋์ง ์์๋ณด์๋ค.
[Redis] Redis Cache๋ฅผ ํ์ฉํด ๋ฐ์ดํฐ ์กฐํ ์๋ ๊ฐ์ ํ๊ธฐ - (1)
[Redis] Redis Cache๋ฅผ ํ์ฉํด ๋ฐ์ดํฐ ์กฐํ ์๋ ๊ฐ์ ํ๊ธฐ - (1)
๐ ๋ชฉ์ฐจ SpringBoot๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ด์ปค๋จธ์ค ์๋น์ค๋ฅผ ๊ตฌํํ๋ ์ค,์ด์ปค๋จธ์ค์ ํน์ฑ์ ์กฐํํ๋ ์ผ์ด ๋ง์๋ฐ ์ฑ๋ฅ์ด ์ ๋์ค์ง ์๋๋ค๋ ๊ฒ์ ํ์ธํ๋ค.๋จผ์ , Redis์ ์ด๋ค ํน์ง ๋๋ฌธ์ ์ฑ๋ฅ์ด
zzudev.tistory.com
์ด๋ฒ ํฌ์คํ ์์๋ Redis ๋ช ๋ น์ด๋ฅผ ์ง์ ์ ์ผ๋ก ์ฌ์ฉํ์ง ์๊ณ ,
Spring Cache ์ด๋ ธํ ์ด์ ์ ์ ์ฉํ์ฌ ์กฐํ ์ฑ๋ฅ์ ๊ฐ์ ํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์.
๐ Spring Cache ์ด๋ ธํ ์ด์ ์ด์ฉํ๊ธฐ
Spring์ ์บ์ฑ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด, ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์์ ์ง์ ์ ์ผ๋ก Redis ๋ช ๋ น์ด๋ฅผ ํธ์ถํ์ง ์์๋ Redis๊ฐ ์๋์ผ๋ก ์ฌ์ฉ๋๋ค. ์บ์ฑ ์ด๋ ธํ ์ด์ ์ ์ข ๋ฅ๋ ๋ค์๊ณผ ๊ฐ๋ค.
1. @Cacheable : ๋ฉ์๋์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅํ๋ค.
@Service
public class UserService {
...
@Cacheable(cacheNames = "cacheName", key = "#key")
public ReturnType methodName(ParamType key) {
// ๋ฉ์๋ ์คํ ๋ก์ง
}
@Cacheable(cacheNames = "userCache", key = "#userId")
public User getUserById(String userId) {
// ๋ฉ์๋ ์คํ ๋ก์ง
}
}
- ๋์ผํ ํค๋ก ๋ฉ์๋๋ฅผ ๋ค์ ํธ์ถํ๋ฉด ์บ์ ๋ ๊ฐ์ ๋ฐํํ๋ค.
- ์บ์์ ๊ฐ์ด ์์ผ๋ฉด ๋ฉ์๋๋ฅผ ์คํํ์ง ์๊ณ ์บ์ ๋ ๊ฐ์ ๋ฐํํ๋ค.
- ์บ์์ ๊ฐ์ด ์์ผ๋ฉด ๋ฉ์๋๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅํ๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ์ ๊ฐ์ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ ๋ ์ฌ์ฉํ๋ค.
2. @CachePut : ๋ฉ์๋์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅํ๋ค.
@Service
public class UserService {
...
@CachePut(cacheNames = "cacheName", key = "#key")
public ReturnType methodName(ParamType key) {
// ๋ฉ์๋ ์คํ ๋ก์ง
}
@CachePut(cacheNames = "userCache", key = "#user.id")
public User updateUser(User user) {
// ๋ฉ์๋ ์คํ ๋ก์ง
}
}
- ๋ฉ์๋๋ฅผ ์คํํ ํ ํญ์ ์บ์๋ฅผ ๊ฐฑ์ ํ๋ค.
- ์บ์๋ฅผ ๊ฐฑ์ ํ์ง๋ง @Cacheable๊ณผ ๋ฌ๋ฆฌ ๋ฉ์๋ ์คํ์ ์๋ตํ์ง ์๋๋ค.
- ๋งค๋ฒ ๋ฉ์๋๋ฅผ ์คํํ์ฌ ์ต์ ๊ฐ์ ์บ์์ ์ ์ฅํ๋ค.
- ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ์บ์๋ฅผ ๊ฐฑ์ ํด์ผ ํ๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ค.
3. @CacheEvict : ์บ์์์ ํ๋ ์ด์์ ํญ๋ชฉ์ ์ ๊ฑฐํ๋ค.
@Service
public class UserService {
...
@CacheEvict(cacheNames = "cacheName", key = "#key", beforeInvocation = false)
public void methodName(ParamType key) {
// ๋ฉ์๋ ์คํ ๋ก์ง
}
@CacheEvict(cacheNames = "userCache", key = "#userId", beforeInvocation = true)
public void deleteUserById(String userId) {
// ๋ฉ์๋ ์คํ ๋ก์ง
}
}
- ๋ฉ์๋ ์คํ ํ ์บ์๋ฅผ ๋น์ด๋ค.
- beforeInvocation ์์ฑ์ true๋ก ์ค์ ํ๋ฉด ๋ฉ์๋ ์คํ ์ ์ ์บ์๋ฅผ ๋น์ด๋ค.
- ๋ฐ์ดํฐ ๋ณ๊ฒฝ ํ ์บ์๋ฅผ ๋ฌดํจํํ์ฌ ์ผ๊ด์ฑ์ ์ ์งํ ๋ ์ฌ์ฉํ๋ค.
์บ์ฑ ์ด๋ ธํ ์ด์ ์ ์ ์ฉํด Redis์ ์บ์ฑ ๊ธฐ๋ฅ์ ์ฌ์ฉํด ๋ณด์. Spring์ ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์บ์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ด ์์กด์ฑ์ ์ถ๊ฐํด์ฃผ์ด์ผํ๋ค.
dependencies {
// Spring Boot Starter for Cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
// JSON ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํ ๊ด๋ จ Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
}
/*
์ง๋ ฌํ: Java ๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์์ด๋ก ๋ณํ
์ญ์ง๋ ฌํ: JSON ๋ฌธ์์ด์ Java ๊ฐ์ฒด๋ก ๋ณํ
*/
์ง๋๋ฒ ๋์์ฑ ์ ์ด ํฌ์คํ ์์ Redis๊ธฐ๋ณธ ์ธํ ์ ๋ง์ณค๋ค๋ ๊ฐ์ ํ์, RedisConfig ํด๋์ค์ ๋ค์ ๋ก์ง์ ์ถ๊ฐํด ์ค๋ค.
[Redis] Redisson์ ์ด์ฉํ ๋ถ์ฐ ๋ฝ ๊ตฌํ์ผ๋ก ๋์์ฑ ์ด์ ํด๊ฒฐ
[Redis] Redisson์ ์ด์ฉํ ๋ถ์ฐ ๋ฝ ๊ตฌํ์ผ๋ก ๋์์ฑ ์ด์ ํด๊ฒฐ
๐ ๋ชฉ์ฐจ SpringBoot๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ด์ปค๋จธ์ค ์๋น์ค๋ฅผ ๊ตฌํํ๋ฉด์ ๋์์ฑ ์ด์๊ฐ ๋ฐ์ํ๋ค.Redis์ Redisson๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด ๋์์ฑ ์ด์๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์.
zzudev.tistory.com
@Configuration
public class RedisConfig {
...
@Bean
public RedisTemplate<String, Object> objectRedisTemplate(
RedisConnectionFactory connectionFactory) {
// ObjectMapper ์ค์ ๋ก์ง
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper));
return template;
}
}
Cache์ค์ ์ ๊ด๋ จ๋ ๋ด์ฉ์ CacheConfig ํด๋์ค์ ๋ฐ๋ก ๋ถ๋ฆฌํด ์ค๋ค. ์บ์ ์ค์ ์ ํ์ฑํํด์ฃผ๊ธฐ ์ํด @EnableCaching ์ด๋ ธํ ์ด์ ๋ ์ถ๊ฐํด ์ฃผ๋๋ก ํ์. ์ด๋, TTL์ ์ค์ ํ ์ ์๋๋ฐ, TTL(Time-To-Live)์ ์บ์์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์ ์ง๋๋ ์๊ฐ์ ๋ํ๋ธ๋ค. ์ค์ ํ ๊ธฐ๊ฐ์ด ์ง๋๋ฉด ์๋์ผ๋ก ์ญ์ ๋๋ค. TTL์ ์บ์ ์ค์ ์์ ์ค์ํ ๋ถ๋ถ์ด๋ฉฐ, ๋ฐ์ดํฐ์ ์ ํจ ๊ธฐ๊ฐ์ ๊ด๋ฆฌํ๊ณ ๋ฉ๋ชจ๋ฆฌ ๋๋ ๋์คํฌ ๊ณต๊ฐ์ ์ต์ ํํ๋ ๋ฐ ๋์์ ์ค๋ค.
@Configuration
@EnableCaching
public class CacheConfig {
public static final String CACHE_180_SECOND = "cache180"; // ์บ์ ๋ง๋ฃ ์๊ฐ 3๋ถ์ผ๋ก ์ค์
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory cf, ResourceLoader rl) {
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(
cf);
// ObjectMapper ์ค์ ๋ก์ง
RedisCacheConfiguration configuration = RedisCacheConfiguration
.defaultCacheConfig(rl.getClassLoader())
.disableCachingNullValues()
.serializeKeysWith(fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(
fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)))
.entryTtl(Duration.ofDays(1));
Map<String, RedisCacheConfiguration> cacheConfigurationMap = new HashMap<>();
cacheConfigurationMap.put(CACHE_180_SECOND,
configuration.entryTtl(Duration.ofSeconds(180L)));
return builder.cacheDefaults(configuration)
.withInitialCacheConfigurations(cacheConfigurationMap).build();
}
}
๋ฐ์ดํฐ์ ์์ ์ด ์์ฃผ ์ผ์ด๋์ง ์๊ณ , ๋จ์ ์กฐํ๋ฅผ ๋น๋ฒํ๊ฒ ํ๋ ์ฅ๋ฐ๊ตฌ๋ ๋๋ฉ์ธ์ @Cacheable, @CacheEvict ์ด๋ ธํ ์ด์ ์ ์ ์ฉํด ๋ณด์.
@Service
@RequiredArgsConstructor
@Transactional
public class CartService {
...
@CacheEvict(cacheNames = CACHE_180_SECOND, key = "'cart:' + #p0", beforeInvocation = false)
public CartInfo addCart(String email, Long productId, Integer quantity) {
// ์ฅ๋ฐ๊ตฌ๋ ์์ฑ ๋ก์ง
}
@CacheEvict(cacheNames = CACHE_180_SECOND, key = "'cart:' + #p0", beforeInvocation = false)
public CartInfo updateCart(String email, Long cartId, Integer quantity) {
// ์ฅ๋ฐ๊ตฌ๋ ์ํ ์์ ๋ก์ง
}
@CacheEvict(cacheNames = CACHE_180_SECOND, key = "'cart:' + #p0", beforeInvocation = false)
public void deleteCart(String email, Long cartId) {
// ์ฅ๋ฐ๊ตฌ๋ ์ํ ์ญ์ ๋ก์ง
}
@Transactional(readOnly = true)
@Cacheable(cacheNames = CACHE_180_SECOND, key = "'cart:' + #p0")
public List<CartInfo> getCarts(String email) {
// ์ฅ๋ฐ๊ตฌ๋ ์กฐํ ๋ก์ง
}
}
โ๏ธ ์ฌ์ฉ๋ ์บ์ ์ ๋ต
์ฝ๊ธฐ ์ ๋ต: ์บ์๋ฅผ ๋จผ์ ํ์ธํ๊ณ , ์บ์์ ๋ฐ์ดํฐ๊ฐ ์์ ๊ฒฝ์ฐ DB์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ Look Aside(Lazy Loading) ์ ๋ต ์ฌ์ฉ.
์ฐ๊ธฐ ์ ๋ต: ๋ณ๊ฒฝ๋ ๋ด์ฉ๋ง DB์ ๋ฐ์ํ๊ณ ํด๋น ์บ์๋ ์ ๊ฑฐ ๋๋ ๋ฌดํจํํ๋ Write-around์ ๋ต ์ฌ์ฉ.
์บ์ ์ด๋ ธํ ์ด์ ์ ์ ์ฉํ๊ณ , ์ฅ๋ฐ๊ตฌ๋ ์กฐํ API๋ฅผ ์คํํด ๋ณด๋ฉด Redis์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฏ๋ก ์กฐํ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ด๋, @Cacheable์ ์ํด Redis์ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ค.
๊ทธ ํ, ๋ค์ ํ๋ฒ ์กฐํํด ๋ณด๋ฉด ์ฟผ๋ฆฌ๋ ์คํ๋์ง ์๊ณ ์บ์์์ ์กฐํ๊ฐ ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. @Cacheable์ ์ํด Redis์์ ์กฐํ๊ฐ ์ด๋ฃจ์ด์ง๋ค. ๋ํ, ์ฅ๋ฐ๊ตฌ๋ ์์ ๋ฐ ์ญ์ ๊ฐ ์ผ์ด๋ฌ์ ๊ฒฝ์ฐ์ @CacheEvict์ ์ํด ๋ฐ์ดํฐ๊ฐ ์ญ์ ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์์์ ์ค๋ช ํ ๋๋ก Look Aside + Write Around ์กฐํฉ์ด ์ฌ์ฉ๋์๊ธฐ ๋๋ฌธ์ DB์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์์ , ์ถ๊ฐ, ์ญ์ ๋ ๋๋ง๋ค ์บ์ ๋ํ ์ญ์ ํด์ฃผ์ด์ผ ํ๋ค. ๋ง์ฝ, ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์บ์๋ฅผ ๋น์์ฃผ์ง ์์ผ๋ฉด ์บ์์ DB์ ๋ฐ์ดํฐ ์ฌ์ด์ ์ ํฉ์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์บ์๋ฅผ ์ ๊ฑฐํด ์ฃผ๋ ์์ ์ด ์ค์ํ๋ค.
๐ Redis Cache๋ฅผ ํ์ฉํด ๋ฐ์ดํฐ ์กฐํ ์ฑ๋ฅ ๊ฐ์ ํ๊ธฐ
์บ์๊ฐ ์ ์ฅ๋๋ ๊ฒ์ ํ์ธํ์ผ๋ ์ฑ๋ฅ ๊ฐ์ ์ด ๋๋์ง ์ง์ ํ์ธ์ ํด๋ณด์.
์ด๋ ๊ฒ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๊ฒฝ์ฐ, ์๋ต ์๋๊ฐ ์ง์ฐ๋๋ ๊ฒ์ ํ์ธํ์๋ค. ์ฌ์ฉ์๊ฐ ๋์ด๋จ์ ๋ฐ๋ผ ์๋ฒ์ ๊ฐ์ ์์ฒญ์ด ๋ฐ๋ณต์ ์ผ๋ก ๋ฐ์ํ์ ๋, DB์ ๋ฌด๋ฆฌ๊ฐ ๊ฐ๊ณ ์ฑ๋ฅ์ด ๋จ์ด์ง ์ ์๋ค. ์บ์ฑ ์ฒ๋ฆฌ ์ , DB์์ ์กฐํ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๊ณ 10,000๊ฑด์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก 4460ms์ ์๋ต ์๋๊ฐ ๊ฑธ๋ฆฌ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์บ์ฑ์ด ์ ์ฉ๋์์ ๋ ์ผ๋งํผ์ ์ฐจ์ด๊ฐ ์๋์ง ํ์ธํด๋ณด์.
์กฐํ ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ง ์์ผ๋ฉฐ, ๋ฐ์ดํฐ๋ฅผ ์บ์์์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์๋ต ์๋ ๋ํ 199ms๋ก 95.5%๊ฐ ๊ฐ์ํ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์บ์ฑ ์ ํ์ ์ฑ๋ฅ ์ฐจ์ด๋ฅผ ํ์ธํ๊ธฐ ์ํด ์กฐ๊ธ ๋ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ์ํฉ์์ ๋น๊ต๋ฅผ ํด๋ณด์.
์กฐํ ์๋ต ์๋ ์ฑ๋ฅ์ธก์ ๊ฒฐ๊ณผ, ์กฐํํ๋ ๋ฐ์ดํฐ์ ์๊ฐ ๋ง์์ง์๋ก ์๋ต์๊ฐ์ด 5๋ฐฐ๊ฐ๋ ์ฐจ์ด๋๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
* ์์ ์ฑ๋ฅ ๋น๊ต๋ ์ ๋ถ ๊ฐ์ ํ๊ฒฝ์์ ํ ์คํธ๋ฅผ ์งํํ ๊ฒ์ด์ง๋ง, ๋ณด๋ค ์ ํํ ์ฑ๋ฅ ๋น๊ต๋ฅผ ์ํด์๋ ์์ธํ ํ ์คํธ๊ฐ ํ์ํ ๊ฒ์ด๋ค.
์ฌ๊ธฐ๊น์ง Spring Cache ์ด๋ ธํ ์ด์ ๋ฐ Redis Cache๋ฅผ ํ์ฉํด ๋ฐ์ดํฐ ์กฐํ ์๋๋ฅผ ๊ฐ์ ํ๋ ๋ฒ์ ๋ํด ์์๋ณด์๋ค.
๐ ์ฐธ๊ณ
Spring Cache, ์ ๋๋ก ์ฌ์ฉํ๊ธฐ
Spring Cache ์ฌ์ฉ๋ฒ, Annotation ๋ฑ์ ์์๋ณด๊ณ ์ค์ ๋ฐฉ์์ ์์๋ณด๋ ๊ฒ์ด ํด๋น ํฌ์คํ ์ ๋ชฉํ์ ๋๋ค. ๐ Spring Cache Series โ Spring Cache, ์ ๋๋ก ์ฌ์ฉํ๊ธฐ โ Caffeine Cache, ์ ๋๋ก ์ฌ์ฉํ๊ธฐ 1 โ Caffeine Cac
gngsn.tistory.com
Redis ์ @Cacheable, @CachePut, @CacheEvict ์ ์ฉํด๋ณด๊ธฐ
Redis ์๋ ์ฌ๋ฌ๊ฐ์ง ์บ์ฑ ๋ฐฉ๋ฒ๋ค์ด ์์ง๋ง ์ ๋ฐฉ์์ผ๋ก ์ ์ฉํด๋ณผ ๊ฒ์ด๋ค ์ด๋ ธํ ์ด์ (์ด ์ด๋ ธํ ์ด์ ๋ค์ ...
blog.naver.com
[Spring + Redis] Redis cache๋ฅผ ์ ์ฉํด ์กฐํ ์ฑ๋ฅ ๊ฐ์ ๋ฐฉ๋ฒ
๋ด ํ๋ก์ ํธ์์๋ ์ฌ์ฉ์๋ณ๋ก ์ฌ์ด๋๋ฐ์ ์ฐ ์, ์ฅ๋ฐ๊ตฌ๋ ์๋ค์ ์นด์ดํธ ์ฟผ๋ฆฌ๋ก ๋ฐํ๋ ๋ฐ์ดํฐ ์๋ฅผ view์ ๋ฟ๋ ค์ฃผ๋๋ฐ, ์ด ์ฌ์ด๋๋ฐ๋ ์ฌ๋ฌ ํ์ด์ง์์ ๋ ธ์ถ๋์ด ํ์ด์ง ์ด๋๋ง๋ค ์นด์ดํธ ์ฟผ
hstory0208.tistory.com
Spring Boot์ Redis๋ก ์บ์ฑ ๊ตฌํํ๊ธฐ | ์์ฆIT
์บ์ฑ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋น์ฉ์ ์ค์ด๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๊ธฐ๋ฒ์ผ๋ก ๋น์ฉ์ด ๋ง์ด ๋๋ ๋ฐ์ดํฐ ์กฐํ ์์ ์์ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ฒ ๊ธ์์๋ ์บ์๋ฅผ ๊ตฌํํ๊ธฐ์ ์์ ์ฌ์ ์ ์์๋๋ฉด ์ข์ ๋งํ ์บ์
yozm.wishket.com