18. cache-aside 쓰기 순서: 커밋 전 캐시 반영과 무효화 누락 (C#)
난이도 하 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 플레이어 프로필 캐시(cache-aside) — 읽기 캐시 + DB 원본
//
// 프로필(닉네임, 소개글 등)은 읽기가 매우 잦아 Redis 같은 캐시를 앞에 둔다.
// 읽기: 캐시 히트면 캐시 값, 미스면 DB에서 읽어 캐시에 채운다.
// 쓰기: 프로필을 수정하면 DB와 캐시를 갱신한다.
//
// 요구사항:
// - 커밋에 성공한 값만 이후 읽기에 보여야 한다(커밋 안 된/롤백된 값이 캐시로
// 새어나가면 안 된다).
// - DB 갱신이 실패하면 캐시가 그 실패한 값을 계속 서빙하면 안 된다.
// - 읽기·쓰기는 여러 스레드/요청에서 동시에 일어난다.
//
// 아래 리포지토리의 (A)(B) 지점을 검토하라.
using System;
public interface ICache
{
bool TryGet(string key, out string value);
void Set(string key, string value);
void Remove(string key);
}
public interface IDb
{
string Read(string key);
void Update(string key, string value); // 실패 시 예외
}
public sealed class ProfileRepository
{
private readonly ICache _cache;
private readonly IDb _db;
public ProfileRepository(ICache cache, IDb db) { _cache = cache; _db = db; }
public string GetProfile(string playerId)
{
if (_cache.TryGet(playerId, out var cached))
return cached;
var value = _db.Read(playerId);
_cache.Set(playerId, value);
return value;
}
public void UpdateProfile(string playerId, string newValue)
{
_cache.Set(playerId, newValue); // (A)
_db.Update(playerId, newValue); // (B)
}
} 결함 코드 · C++
// 시나리오: 플레이어 프로필 캐시(cache-aside) — 읽기 캐시 + DB 원본 (C++)
//
// 프로필은 읽기가 잦아 인메모리/원격 캐시를 앞에 둔다.
// 읽기: 캐시 히트면 캐시 값, 미스면 DB에서 읽어 캐시에 채운다.
// 쓰기: 프로필 수정 시 DB와 캐시를 갱신한다.
//
// 요구사항:
// - 커밋에 성공한 값만 이후 읽기에 보여야 한다.
// - DB 갱신이 실패(예외)하면 캐시가 그 값을 계속 서빙하면 안 된다.
// - 읽기·쓰기는 동시에 일어난다.
//
// 아래 리포지토리의 (A)(B) 지점을 검토하라.
#include <optional>
#include <string>
struct ICache {
virtual std::optional<std::string> tryGet(const std::string& key) = 0;
virtual void set(const std::string& key, const std::string& value) = 0;
virtual void remove(const std::string& key) = 0;
virtual ~ICache() = default;
};
struct IDb {
virtual std::string read(const std::string& key) = 0;
virtual void update(const std::string& key, const std::string& value) = 0; // 실패 시 throw
virtual ~IDb() = default;
};
class ProfileRepository {
public:
ProfileRepository(ICache& cache, IDb& db) : cache_(cache), db_(db) {}
std::string getProfile(const std::string& playerId) {
if (auto cached = cache_.tryGet(playerId))
return *cached;
std::string value = db_.read(playerId);
cache_.set(playerId, value);
return value;
}
void updateProfile(const std::string& playerId, const std::string& newValue) {
cache_.set(playerId, newValue); // (A)
db_.update(playerId, newValue); // (B)
}
private:
ICache& cache_;
IDb& db_;
};
int main() { return 0; } 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.