Caching bo‘limi quyidagilarni qamrab oladi: @EnableCaching, @Cacheable, @CacheEvict, @CachePut, CacheManager, Caffeine, Redis, cache key strategy, TTL, cache-aside, va write-through.
1. Caching nima?
Caching - tez-tez kerak bo‘ladigan ma’lumotni sekin joydan emas, tez joydan olish.
Masalan:
Client -> API -> DatabaseAgar har safar databasega borsak:
latency oshadi;
databasega yuk tushadi;
bir xil query qayta-qayta ishlaydi.
Cache bilan:
Client -> API -> Cache
↓
DatabaseAgar data cache’da bo‘lsa, databasega bormaymiz.
2. Oddiy misol
Tasavvur qiling, productni ID bo‘yicha olyapmiz:
@Service
public class ProductService {
public Product getById(Long id) {
return productRepository.findById(id)
.orElseThrow();
}
}Agar id = 10 product ko‘p chaqirilsa, har safar DBga query ketadi.
Cache qo‘shsak:
@Cacheable(value = "products", key = "#id")
public Product getById(Long id) {
return productRepository.findById(id)
.orElseThrow();
}Endi birinchi chaqiruvda DBga boradi, keyingi chaqiruvlarda cache’dan oladi.
3. Spring Cache Abstraction
Spring cachingni bitta umumiy abstraction orqali beradi.
Siz kodda shuni yozasiz:
@Cacheable("products")Lekin ichkarida cache provider boshqacha bo‘lishi mumkin:
Provider | Qayerda ishlaydi? |
|---|---|
ConcurrentMap | Oddiy local memory |
Caffeine | Tez local cache |
Redis | Distributed cache |
Ehcache | Local/JVM cache |
Hazelcast | Distributed in-memory cache |
Siz annotationlarni deyarli o‘zgartirmaysiz, faqat cache provider almashadi.
4. Cachingni yoqish
Spring Boot’da caching ishlashi uchun:
@EnableCaching
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}Dependency odatda:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>5. @Cacheable
@Cacheable - method natijasini cachega saqlaydi.
@Cacheable(value = "users", key = "#id")
public UserDto getUser(Long id) {
System.out.println("DBga bordi");
return userRepository.findById(id)
.map(userMapper::toDto)
.orElseThrow();
}Birinchi chaqiruv:
getUser(1)
DBga bordi
cachega saqlandiIkkinchi chaqiruv:
getUser(1)
cache’dan qaytdi
method ichiga kirmadiMuhim joy:
@Cacheablecache hit bo‘lsa, method tanasini umuman ishlatmaydi.
6. value va key
@Cacheable(value = "users", key = "#id")Bu yerda:
Qism | Ma’nosi |
|---|---|
| Cache nomi |
| Cache key |
Masalan:
cache name: users
key: 1
value: UserDto(id=1, name="Ali")7. Cache key qanday tanlanadi?
Agar methodda bitta parametr bo‘lsa:
@Cacheable("users")
public UserDto getUser(Long id) {
}Spring default key sifatida idni ishlatadi.
Lekin aniq yozish yaxshi:
@Cacheable(value = "users", key = "#id")
public UserDto getUser(Long id) {
}Agar bir nechta parametr bo‘lsa:
@Cacheable(value = "users", key = "#status + ':' + #page")
public Page<UserDto> getUsers(UserStatus status, int page) {
}Yaxshiroq:
@Cacheable(
value = "users",
key = "T(String).format('%s:%s:%s', #status, #page, #size)"
)
public Page<UserDto> getUsers(UserStatus status, int page, int size) {
}Lekin murakkab keylar uchun alohida KeyGenerator yozish yaxshiroq.
8. @CachePut
@CachePut methodni har doim ishlatadi va natijani cachega yozadi.
@CachePut(value = "users", key = "#id")
public UserDto updateUser(Long id, UpdateUserRequest request) {
User user = userRepository.findById(id).orElseThrow();
user.setName(request.name());
return userMapper.toDto(userRepository.save(user));
}Farqi:
Annotation | Method ishlaydimi? | Cachega yozadimi? |
|---|---|---|
| Cache miss bo‘lsa | Ha |
| Har doim | Ha |
@CachePut odatda update methodlarda ishlatiladi.
9. @CacheEvict
@CacheEvict - cache’dan ma’lumotni o‘chiradi.
Masalan user delete qilinsa:
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}Endi users::1 cache’dan o‘chadi.
Update qilganda ham ishlatish mumkin:
@CacheEvict(value = "users", key = "#id")
public UserDto updateUser(Long id, UpdateUserRequest request) {
User user = userRepository.findById(id).orElseThrow();
user.setName(request.name());
userRepository.save(user);
return userMapper.toDto(user);
}Bu holatda keyingi getUser(id) DBdan yangisini olib, cachega qayta yozadi.
10. allEntries = true
Ba’zan bitta key emas, butun cache tozalanadi.
@CacheEvict(value = "products", allEntries = true)
public ProductDto createProduct(CreateProductRequest request) {
Product product = productRepository.save(mapper.toEntity(request));
return mapper.toDto(product);
}Bu list cachelar uchun foydali bo‘lishi mumkin.
Masalan:
@Cacheable(value = "productLists", key = "#category")
public List<ProductDto> getByCategory(String category) {
}Agar yangi product qo‘shilsa, category listlar eskirib qolishi mumkin. Shunda allEntries = true ishlatish mumkin.
Lekin ehtiyot bo‘ling:
allEntries = trueko‘p ishlatilsa cache foydasi kamayadi.
11. condition va unless
condition
Method cache ishlatishdan oldin tekshiriladi.
@Cacheable(
value = "users",
key = "#id",
condition = "#id > 0"
)
public UserDto getUser(Long id) {
}Agar id <= 0 bo‘lsa, cache ishlamaydi.
unless
Method ishlagandan keyin natijaga qarab cache qilmaslik.
@Cacheable(
value = "users",
key = "#id",
unless = "#result == null"
)
public UserDto getUser(Long id) {
}Agar result null bo‘lsa, cachega yozilmaydi.
Yana bir misol:
@Cacheable(
value = "users",
key = "#id",
unless = "#result.status == 'BLOCKED'"
)
public UserDto getUser(Long id) {
}12. @Caching
Bir nechta cache operatsiyani birga ishlatish uchun:
@Caching(
put = {
@CachePut(value = "users", key = "#result.id")
},
evict = {
@CacheEvict(value = "userLists", allEntries = true)
}
)
public UserDto updateUser(Long id, UpdateUserRequest request) {
User user = userRepository.findById(id).orElseThrow();
user.setName(request.name());
return userMapper.toDto(userRepository.save(user));
}Bu yerda:
bitta user cache yangilanadi;
user list cache tozalanadi.
13. CacheManager nima?
CacheManager - cachelarni boshqaruvchi Spring abstraction.
Application
↓
CacheManager
↓
Cache provider: Caffeine / Redis / Ehcache / ...Masalan:
@Autowired
private CacheManager cacheManager;Manual ishlatish:
Cache cache = cacheManager.getCache("users");
if (cache != null) {
cache.evict(1L);
}Lekin odatda annotationlar yetarli.
14. Local cache vs distributed cache
Local cache
Har bir application instance o‘z memorysida cache saqlaydi.
App instance 1 -> cache A
App instance 2 -> cache B
App instance 3 -> cache CMisol: Caffeine.
Afzalliklari:
juda tez;
network yo‘q;
setup oson.
Kamchiligi:
har instance cache alohida;
data inconsistent bo‘lishi mumkin;
restart bo‘lsa cache yo‘qoladi.
Distributed cache
Bitta umumiy cache server ishlatiladi.
App instance 1 ┐
App instance 2 ├── Redis
App instance 3 ┘Misol: Redis.
Afzalliklari:
barcha instance bitta cache ko‘radi;
horizontal scalingda yaxshi;
TTL va eviction kuchli;
session/cache/share data uchun qulay.
Kamchiligi:
network latency bor;
Redis down bo‘lsa ta’sir qiladi;
serialization kerak;
infra murakkabroq.
15. Caffeine local cache
Caffeine - JVM ichida ishlaydigan juda tez local cache.
Dependency:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>Config:
spring:
cache:
type: caffeine
cache-names:
- users
- products
caffeine:
spec: maximumSize=10000,expireAfterWrite=10mBu nimani bildiradi?
maximumSize=10000 -> 10 mingtagacha entry
expireAfterWrite=10m -> yozilgandan 10 minut keyin o‘chadi16. Caffeine qachon yaxshi?
Caffeine yaxshi:
Holat | Sabab |
|---|---|
Reference data | Masalan region, category, settings |
Kam o‘zgaradigan data | Cache invalidation oson |
Single instance app | Distributed cache shart emas |
Juda tez response kerak | Memorydan o‘qiydi |
DB yukini kamaytirish | Tez-tez o‘qiladigan datalar |
Misol:
@Cacheable(value = "regions")
public List<RegionDto> getRegions() {
return regionRepository.findAll()
.stream()
.map(mapper::toDto)
.toList();
}17. Redis cache
Redis - distributed cache uchun eng ko‘p ishlatiladigan variantlardan biri.
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>Config:
spring:
cache:
type: redis
data:
redis:
host: localhost
port: 6379TTL config:
@Configuration
public class RedisCacheConfig {
@Bean
public RedisCacheManagerBuilderCustomizer redisCacheCustomizer() {
return builder -> builder
.withCacheConfiguration(
"users",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
)
.withCacheConfiguration(
"products",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
);
}
}Bu yerda:
users cache -> 10 minut TTL
products cache -> 30 minut TTL18. Redisda serialization
Redisga Java obyektini saqlash uchun serialization kerak.
Default serialization ba’zan noqulay bo‘lishi mumkin. JSON ishlatish yaxshiroq:
@Configuration
public class RedisConfig {
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
ObjectMapper objectMapper = new ObjectMapper()
.findAndRegisterModules();
GenericJackson2JsonRedisSerializer serializer =
new GenericJackson2JsonRedisSerializer(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(serializer)
);
}
}Bu productionda ko‘p kerak bo‘ladi.
19. TTL nima?
TTL - Time To Live.
Ya’ni cache entry qancha vaqt yashaydi.
users::1 -> 10 minutdan keyin avtomatik o‘chadiTTL nega kerak?
stale data uzoq qolmasligi uchun;
memory to‘lib ketmasligi uchun;
cache invalidationni yengillashtirish uchun.
20. TTL tanlash
Data turi | Tavsiya TTL |
|---|---|
Region/category/reference data | 1 soat - 24 soat |
Product detail | 5 - 30 minut |
User profile | 1 - 10 minut |
Exchange rate | Manbaga bog‘liq |
Permission/role | Qisqa yoki event-based invalidation |
Search/list result | 30 sekund - 5 minut |
Qoida:
Data qanchalik tez o‘zgarsa, TTL shunchalik qisqa bo‘lishi kerak.
21. Cache key strategy
Yomon key:
@Cacheable(value = "users", key = "#name")
public List<UserDto> search(String name, String city, UserStatus status) {
}Bu noto‘g‘ri, chunki city va status hisobga olinmayapti.
To‘g‘riroq:
@Cacheable(
value = "userSearch",
key = "#name + ':' + #city + ':' + #status"
)
public List<UserDto> search(String name, String city, UserStatus status) {
}Yana yaxshiroq - request object asosida key:
@Cacheable(value = "userSearch", key = "#request.cacheKey()")
public Page<UserDto> search(UserSearchRequest request, Pageable pageable) {
}Request:
public record UserSearchRequest(
String name,
String city,
UserStatus status
) {
public String cacheKey() {
return "%s:%s:%s".formatted(name, city, status);
}
}Lekin pagination bo‘lsa, page, size, sort ham keyga kirishi kerak.
22. Pageable bilan cache key
@Cacheable(
value = "userSearch",
key = "#request.cacheKey() + ':' + #pageable.pageNumber + ':' + #pageable.pageSize + ':' + #pageable.sort"
)
public Page<UserDto> search(UserSearchRequest request, Pageable pageable) {
}Aks holda:
page=0 cachega tushadi
page=1 chaqiriladi
lekin page=0 natijasi qaytib qolishi mumkinBu jiddiy bug.
23. Cache invalidation
Cachingdagi eng qiyin narsa - cachega yozish emas.
Eng qiyini:
Cache’dagi eski datani qachon o‘chirish?
Masalan:
@Cacheable(value = "products", key = "#id")
public ProductDto getProduct(Long id) {
}Product update bo‘lsa:
public ProductDto updateProduct(Long id, UpdateProductRequest request) {
}Agar cache tozalanmasa, user eski productni ko‘raveradi.
To‘g‘ri:
@CacheEvict(value = "products", key = "#id")
public ProductDto updateProduct(Long id, UpdateProductRequest request) {
Product product = productRepository.findById(id).orElseThrow();
product.setName(request.name());
return mapper.toDto(productRepository.save(product));
}24. List cache invalidation
Detail cache oson:
products::10Lekin list cache qiyin:
productList::category=PHONE&page=0
productList::category=PHONE&page=1
productList::category=LAPTOP&page=0Agar product update bo‘lsa, qaysi listlarni tozalash kerak?
Oddiy yechim:
@Caching(evict = {
@CacheEvict(value = "products", key = "#id"),
@CacheEvict(value = "productLists", allEntries = true)
})
public ProductDto updateProduct(Long id, UpdateProductRequest request) {
}Bu xavfsiz, lekin qo‘pol yechim.
Katta sistemalarda:
qisqa TTL;
event-based invalidation;
cache versioning;
Redis key pattern bilan delete;
list cache qilmaslik;
ishlatiladi.
25. Cache-aside pattern
Eng ko‘p ishlatiladigan pattern.
1. App cache’dan o‘qiydi
2. Cache miss bo‘lsa DBdan o‘qiydi
3. Natijani cachega yozadi
4. Keyingi safar cache’dan qaytaradi@Cacheable aynan shunga o‘xshaydi.
@Cacheable(value = "products", key = "#id")
public ProductDto getProduct(Long id) {
return productRepository.findById(id)
.map(mapper::toDto)
.orElseThrow();
}Oqim:
getProduct(10)
cache miss
DB query
cache put
getProduct(10)
cache hit
DBga bormaydi26. Write-through pattern
Write-through - data yozilganda DB bilan birga cache ham yangilanadi.
@CachePut(value = "products", key = "#result.id")
public ProductDto updateProduct(Long id, UpdateProductRequest request) {
Product product = productRepository.findById(id).orElseThrow();
product.setName(request.name());
Product saved = productRepository.save(product);
return mapper.toDto(saved);
}Oqim:
Update request
DB update
Cache updateAfzalligi:
update bo‘lgandan keyin cache yangi bo‘ladi.
Kamchiligi:
yozish operatsiyasi murakkablashadi;
list cachelarni baribir invalidatsiya qilish kerak;
cache update xatosini boshqarish kerak.
27. Cache-aside vs write-through
Pattern | O‘qish | Yozish | Qachon yaxshi |
|---|---|---|---|
Cache-aside | Miss bo‘lsa DB | Update’da evict | Ko‘p app uchun default |
Write-through | Cache doim yangiroq | DB + cache update | Detail cache uchun yaxshi |
Write-behind | Avval cache, keyin DB | Async DB write | Juda ehtiyotkorlik kerak |
Ko‘p Spring Boot loyihalarda eng oddiy va xavfsiz variant:
Read: @Cacheable
Update/Delete: @CacheEvict28. @Transactional va cache
Bu juda muhim.
@Transactional
@CacheEvict(value = "products", key = "#id")
public void updateProduct(Long id) {
Product product = productRepository.findById(id).orElseThrow();
product.setName("New name");
throw new RuntimeException("DB rollback");
}Savol:
Cache qachon o‘chadi? Transaction rollback bo‘lsa nima bo‘ladi?
Spring Cache annotationlari transaction bilan avtomatik ideal integratsiyada deb o‘ylash xavfli. Ba’zi holatlarda cache DB commitdan oldin o‘zgarishi mumkin.
Agar aniq commitdan keyin cache tozalash kerak bo‘lsa, event ishlatish yaxshi:
@Transactional
public void updateProduct(Long id, UpdateProductRequest request) {
Product product = productRepository.findById(id).orElseThrow();
product.setName(request.name());
eventPublisher.publishEvent(new ProductUpdatedEvent(id));
}@Component
public class ProductCacheInvalidator {
@CacheEvict(value = "products", key = "#event.productId")
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void onProductUpdated(ProductUpdatedEvent event) {
// cache evicted after commit
}
}Bu usul DB commit bo‘lgandan keyin cache tozalanishini kafolatlashga yaqinroq.
29. Self-invocation cachingda ham muammo
AOP mavzusidagi muammo cachingda ham bor.
Yomon:
@Service
public class ProductService {
public ProductDto getProductWrapper(Long id) {
return getProduct(id);
}
@Cacheable(value = "products", key = "#id")
public ProductDto getProduct(Long id) {
return productRepository.findById(id)
.map(mapper::toDto)
.orElseThrow();
}
}getProductWrapper() ichidan getProduct() chaqirilsa, cache ishlamasligi mumkin.
Sabab:
this.getProduct(id)proxy orqali o‘tmaydi.
Yechim:
methodni boshqa servicega chiqarish;
tashqaridan proxy orqali chaqirish;
self-injection ishlatish, lekin dizayn jihatdan uncha toza emas.
30. Private methodda caching ishlamaydi
Yomon:
@Cacheable("products")
private ProductDto getProduct(Long id) {
}Spring Cache ham AOP/proxyga tayanadi. Private method intercept qilinmaydi.
To‘g‘ri:
@Cacheable("products")
public ProductDto getProduct(Long id) {
}31. Cache stampede muammosi
Tasavvur qiling cache expire bo‘ldi.
1000 ta request bir vaqtda getProduct(10) chaqirdi
cache miss
hammasi DBga ketdiBu cache stampede yoki thundering herd deyiladi.
Yechimlar:
sync = true;lock;
TTLga jitter qo‘shish;
background refresh;
Redis distributed lock;
hot keylarni alohida boshqarish.
Spring’da:
@Cacheable(value = "products", key = "#id", sync = true)
public ProductDto getProduct(Long id) {
return productRepository.findById(id)
.map(mapper::toDto)
.orElseThrow();
}sync = true bir key bo‘yicha bir vaqtda faqat bitta thread DBga borishiga yordam beradi. Lekin hamma providerlarda bir xil ishlamasligi mumkin.
32. Negative caching
Agar data topilmasa, har safar DBga borish ham yomon.
Masalan:
GET /products/999999Bunday product yo‘q. Lekin bot yoki client qayta-qayta so‘rasa, DBga yuk tushadi.
Negative caching - "yo‘q" natijani ham qisqa muddat cache qilish.
Masalan result Optional.empty() yoki maxsus DTO bilan.
Lekin ehtiyot bo‘ling:
Product hozir yo‘q
5 sekunddan keyin yaratilishi mumkinShuning uchun negative cache TTL qisqa bo‘lishi kerak.
33. Nimalarni cache qilish kerak?
Cache qilish yaxshi:
Data | Sabab |
|---|---|
Reference data | Kam o‘zgaradi |
Product detail | Ko‘p o‘qiladi |
Category list | Kam o‘zgaradi |
Permissions | Tez-tez tekshiriladi |
Settings/config | Ko‘p ishlatiladi |
Expensive calculation | Hisoblash qimmat |
External API response | Sekin va limitli bo‘lishi mumkin |
Cache qilish xavfli:
Data | Sabab |
|---|---|
Tez o‘zgaradigan balance | Stale data xavfli |
Payment status | Xatoga narxi baland |
Personal sensitive data | Security risk |
Juda katta objectlar | Memory bosimi |
Noto‘g‘ri invalidatsiya qilinadigan listlar | Eski data qaytadi |
Transaction ichidagi vaqtinchalik data | Consistency muammo |
34. Cache va security
User-specific data cache qilinsa, keyga user ID kiritilishi shart.
Yomon:
@Cacheable(value = "profile", key = "'current'")
public UserProfileDto getCurrentProfile() {
}Bu hamma userga bitta cache qaytarishi mumkin.
To‘g‘ri:
@Cacheable(value = "profile", key = "#userId")
public UserProfileDto getProfile(Long userId) {
}Role/permission cache qilganda ham:
@Cacheable(value = "permissions", key = "#userId")
public Set<String> getPermissions(Long userId) {
}Agar user role o‘zgarsa:
@CacheEvict(value = "permissions", key = "#userId")
public void changeUserRole(Long userId, Long roleId) {
}35. Cache monitoring
Productionda cache qo‘shib qo‘yish yetarli emas. Monitoring kerak.
Ko‘rish kerak bo‘lgan metriclar:
Metric | Ma’nosi |
|---|---|
Hit rate | Cache’dan qaytgan so‘rovlar foizi |
Miss rate | DBga ketgan so‘rovlar foizi |
Eviction count | Cache’dan chiqarilgan entrylar |
Cache size | Hozirgi entrylar soni |
Latency | Cache access va DB access vaqti |
Redis memory | Redis RAM ishlatilishi |
Redis ops/sec | Redis request soni |
Agar hit rate past bo‘lsa, caching foydasi kam.
36. Spring Boot Actuator bilan cache metric
Agar Actuator va Micrometer ishlatilsa, cache metriclar chiqishi mumkin.
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>Endpoint:
/actuator/metricsCache metriclar:
cache.gets
cache.puts
cache.evictions
cache.sizeProviderga qarab metriclar farq qilishi mumkin.
37. Real project pattern: Product cache
Service
@Service
public class ProductService {
private final ProductRepository productRepository;
private final ProductMapper mapper;
public ProductService(
ProductRepository productRepository,
ProductMapper mapper
) {
this.productRepository = productRepository;
this.mapper = mapper;
}
@Cacheable(value = "products", key = "#id")
@Transactional(readOnly = true)
public ProductDto getById(Long id) {
return productRepository.findById(id)
.map(mapper::toDto)
.orElseThrow(() -> new ProductNotFoundException(id));
}
@Caching(evict = {
@CacheEvict(value = "products", key = "#id"),
@CacheEvict(value = "productLists", allEntries = true)
})
@Transactional
public ProductDto update(Long id, UpdateProductRequest request) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ProductNotFoundException(id));
product.setName(request.name());
product.setPrice(request.price());
return mapper.toDto(product);
}
@CacheEvict(value = "productLists", allEntries = true)
@Transactional
public ProductDto create(CreateProductRequest request) {
Product product = mapper.toEntity(request);
Product saved = productRepository.save(product);
return mapper.toDto(saved);
}
}Bu pattern:
getById -> cache read
update -> detail cache evict + list cache evict
create -> list cache evict38. Real project pattern: Reference data cache
Reference datalar uchun caching juda yaxshi.
@Service
public class RegionService {
private final RegionRepository regionRepository;
@Cacheable(value = "regions", key = "'all'")
@Transactional(readOnly = true)
public List<RegionDto> getAll() {
return regionRepository.findAll()
.stream()
.map(RegionDto::from)
.toList();
}
@CacheEvict(value = "regions", key = "'all'")
@Transactional
public RegionDto create(CreateRegionRequest request) {
Region region = regionRepository.save(new Region(request.name()));
return RegionDto.from(region);
}
}Bu yerda key oddiy:
regions::allChunki butun region list bitta cache entry sifatida saqlanyapti.
39. Cache bilan eng ko‘p qilinadigan xatolar
Xato | Oqibat |
|---|---|
Key noto‘g‘ri tanlangan | Boshqa requestga noto‘g‘ri data qaytadi |
Invalidation yo‘q | Eski data qaytadi |
User-specific key yo‘q | Bir user boshqa user datasini ko‘rishi mumkin |
Juda uzun TTL | Stale data uzoq qoladi |
Juda qisqa TTL | Cache foydasi kamayadi |
Katta object cache | Memory bosimi |
List cache haddan tashqari ko‘p | Invalidation murakkablashadi |
Transaction bilan noaniq ishlash | DB rollback, cache o‘zgarib qolishi mumkin |
Self-invocation | Cache annotation ishlamaydi |
Cache monitoring yo‘q | Foyda yoki zarar noma’lum |
40. Interview savollar
Savol 1: Spring Cache qanday ishlaydi?
Javob:
Spring Cache annotationlar orqali method natijasini cachega saqlaydi yoki cache’dan o‘qiydi. U
CacheManagerabstractioniga tayanadi. Provider sifatida Caffeine, Redis, Ehcache kabi texnologiyalar ishlatilishi mumkin.
Savol 2: @Cacheable, @CachePut, @CacheEvict farqi nima?
Javob:
@Cacheablecache’da data bo‘lsa methodni ishlatmaydi, yo‘q bo‘lsa methodni ishlatib resultni cachega yozadi.@CachePutmethodni har doim ishlatadi va resultni cachega yozadi.@CacheEvictcache’dagi entryni o‘chiradi.
Savol 3: Local cache va distributed cache farqi nima?
Javob:
Local cache har bir app instance ichida alohida saqlanadi, masalan Caffeine. Juda tez, lekin instance’lar orasida umumiy emas. Distributed cache esa Redis kabi alohida serverda bo‘ladi va barcha instance’lar bir xil cache’dan foydalanadi.
Savol 4: Cache invalidation nima?
Javob:
Cache invalidation - data o‘zgarganda cache’dagi eski entryni o‘chirish yoki yangilash jarayoni. Cachingdagi eng qiyin muammolardan biri, chunki noto‘g‘ri invalidation eski yoki noto‘g‘ri data qaytaradi.
Savol 5: Cache-aside pattern nima?
Javob:
Cache-aside’da application avval cache’dan o‘qiydi. Cache miss bo‘lsa DBdan o‘qiydi va natijani cachega yozadi. Spring’dagi
@Cacheableshu patternga juda o‘xshaydi.
Savol 6: Cache key strategy nima uchun muhim?
Javob:
Cache key method natijasini identifikatsiya qiladi. Agar keyga barcha muhim parametrlar kiritilmasa, boshqa requestga noto‘g‘ri data qaytishi mumkin. Masalan paginationda page, size, sort ham keyga kirishi kerak.
Savol 7: Redis qachon kerak?
Javob:
Redis ko‘p instance’li applicationlarda, distributed cache kerak bo‘lganda, cache barcha serverlar orasida umumiy bo‘lishi kerak bo‘lganda ishlatiladi. Masalan microservice, Kubernetes, load balancer ortidagi bir nechta app instance.
41. Qisqa xulosa
Caching performance uchun kuchli qurol, lekin noto‘g‘ri ishlatilsa xavfli.
Mavzu | Asosiy fikr |
|---|---|
| O‘qish natijasini cache qiladi |
| Update natijasini cachega yozadi |
| Eski cache entryni o‘chiradi |
| Cache providerlarni boshqaradi |
Caffeine | Tez local cache |
Redis | Distributed cache |
TTL | Entry qancha yashashini belgilaydi |
Key strategy | To‘g‘ri data qaytishi uchun muhim |
Cache-aside | Eng ko‘p ishlatiladigan pattern |
Write-through | Write paytida cache ham yangilanadi |
Invalidation | Cachingdagi eng qiyin qism |
Eng muhim gap:
Cache - database o‘rnini bosmaydi. Cache faqat tez-tez o‘qiladigan, nisbatan barqaror va noto‘g‘ri eskirib qolsa katta zarar bermaydigan datalar uchun ishlatiladi.