아래는 최신 트렌드(.NET 8 기준)의 ASP.NET Core 애플리케이션 성능 최적화 방법을 단계별로 정리한 블로그 글 예시입니다. 각 단계별로 설명과 코드 샘플을 풍부히 담았으니, 필요에 따라 추가·변경하여 활용하세요.
1단계: 불필요한 서비스 등록 줄이기
ASP.NET Core의 미들웨어·서비스는 필요할 때만 등록해야 애플리케이션이 가벼워집니다. Program.cs에서 기본 템플릿이 등록해 주는 모든 것을 다 쓰는 것이 아니라, 실제 사용하는 것만 골라서 추가하세요.
var builder = WebApplication.CreateBuilder(args);
// 예: Identity나 Razor Pages를 안 쓰면 제거
// builder.Services.AddRazorPages();
// builder.Services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>();
// 필요한 서비스만 등록
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
// 캐싱, 압축, 인증·권한 등은 필요 시에만
builder.Services.AddMemoryCache(); // Tip 2에서 사용
builder.Services.AddResponseCompression(); // Tip 5에서 사용
var app = builder.Build();
// 미들웨어도 필요한 것만
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.Run();
이렇게 구성 요소를 슬림화하면 애플리케이션 시작 속도가 빨라지고 메모리 사용량도 줄어듭니다.
2단계: 메모리 캐싱으로 DB 호출 횟수 줄이기
DB 호출은 디스크 I/O로 느립니다. 자주 읽지만 자주 변경되지 않는 데이터는 IMemoryCache(혹은 서버 팜 환경에는 Redis 등 분산 캐시)로 보관하세요.
// 1) Repository 클래스
public class CustomerRepository
{
private readonly IMemoryCache _cache;
public CustomerRepository(IMemoryCache cache) => _cache = cache;
public async Task<Customer> GetByIdAsync(string id, bool forceReload = false)
{
if (forceReload)
_cache.Remove(id);
return await _cache.GetOrCreateAsync(id, async e =>
{
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
return await LoadCustomerFromDbAsync(id);
});
}
private Task<Customer> LoadCustomerFromDbAsync(string id)
=> _dbContext.Customers.FirstOrDefaultAsync(c => c.Id == id);
}
// 2) Controller에서 사용
public class HomeController : Controller
{
private readonly CustomerRepository _repo;
public HomeController(IMemoryCache cache)
=> _repo = new CustomerRepository(cache);
public async Task<IActionResult> Index(string id, bool force = false)
{
var customer = await _repo.GetByIdAsync(id, force);
return View(customer);
}
}
분산 캐시: 서버 팜을 쓰면 Redis, NCache, SQL Server 분산 캐시를 활용하세요
3단계: 클라이언트로 전송하는 데이터 최소화
초기 페이지 로드 시 불필요한 데이터를 모두 내려주면 렌더링 지연이 발생합니다.
페이징(paging): 첫 페이지 데이터만 내려주고, 사용자가 요청할 때 추가 로드
Infinite Scroll: 화면에 보이는 영역 + α 만큼만 로드
<!-- View: 최소 데이터만 렌더링 -->
<div id="grid"></div>
<script>
let page = 1, pageSize = 20;
async function loadPage() {
const res = await fetch(`/api/items?page=${page}&size=${pageSize}`);
const data = await res.json();
renderGrid(data);
}
loadPage();
// 스크롤 이벤트로 추가 로드...
</script>
// API: 페이징 지원
[HttpGet("api/items")]
public async Task<IActionResult> GetItems(int page = 1, int size = 20)
{
var items = await _dbContext.Items
.AsNoTracking()
.Skip((page - 1) * size)
.Take(size)
.ToListAsync();
return Ok(items);
}
public async Task<IActionResult> GetDataAsync()
{
var data = await _httpClient.GetFromJsonAsync<List<MyDto>>("https://api.example.com/data");
return View(data);
}
비동기를 통해 높은 동시성(concurrency)을 확보할 수 있습니다.
마무리
필요한 것만 등록
DB 호출 줄이기 → 캐싱
클라이언트 전송 최소화
CDN·번들링·압축
캐싱 및 비동기
이 여섯 가지+보너스 비동기를 적용하면 사용자 체감 속도가 크게 개선됩니다. 여기에 프로파일링(BenchmarkDotNet, MiniProfiler)이나 GC 튜닝(Workstation vs Server mode), Kestrel 옵션 조정 등 추가 최적화 기법을 더하면 더 좋은 성능을 얻을 수 있습니다.