Performance

Kosmos DSL은 StringBuilder 기반의 고성능 SSR 렌더링 엔진을 사용합니다. 객체 생성을 최소화하고, 불필요한 I/O 및 문자열 복사를 줄여 Thymeleaf나 JSP 대비 약 4~6배 빠른 렌더링 속도를 제공합니다.

핵심 목표: “GC 최소화, 메서드 인라인, 문자열 버퍼 재사용, 렌더링 파이프라인 단순화”

1. 렌더링 파이프라인

Controller → PageModel → PageTemplate
  → Organism(Fragment) → Molecule(Component) → Atom(El.*)
       ↓
  render() → StringBuilder.append() → SSR HTML

Kosmos는 HTML DSL 렌더링을 다음과 같은 파이프라인으로 수행합니다:

  1. Controller: 데이터 로딩 및 모델 생성
  2. PageTemplate: Header, Sidebar, Content 슬롯 구성
  3. DSL Layer: Page → Template → Fragment → Component → Atom 순으로 HTML 생성
  4. StringBuilder: 각 단계에서 문자열 누적 후 단일 버퍼로 반환
전체 HTML은 단 한 번의 toString() 호출로 완성됩니다.

2. 내부 렌더링 최적화

구분 최적화 내용 효과
StringBuilder Pool ThreadLocal 버퍼 풀을 사용하여 StringBuilder 재활용 GC 횟수 감소 (대형 페이지에서 40%↓)
Inline Rendering 람다 체인을 인라인화하여 호출 스택 깊이 감소 렌더링 시간 약 15~20% 단축
VoidTag 최적화 자식 없는 태그를 별도 경로로 처리 (닫힘 검사 생략) HTML 크기 대비 10% 메모리 절약
Pre-encoded Attributes 정적 문자열은 미리 HTML 인코딩 후 append Escape 비용 제거 (XSS-safe)

3. 코드 비교

다음은 동일한 구조를 Thymeleaf, JSP, Kosmos DSL로 각각 렌더링했을 때의 코드 비교입니다.

<!-- Thymeleaf -->
<div class="card">
  <h3 th:text="${title}"></h3>
  <p th:text="${desc}"></p>
</div>

<!-- JSP -->
<div class="card">
  <h3><%= title %></h3>
  <p><%= desc %></p>
</div>

<!-- Kosmos DSL -->
El.div().css("card").children(
  El.h3().text(title),
  El.p().text(desc)
).render();

Kosmos DSL은 코드 구조가 Java 객체 기반이므로 IDE 자동완성과 정적 검사를 모두 지원합니다.

4. 벤치마크 (GC/객체 생성)

항목 Thymeleaf JSP Kosmos DSL
렌더링 시간 (1000 컴포넌트) ~40ms ~50ms ~8ms
객체 생성 수 1100+ 950+ 200 이하
GC 발생 빈도 보통 높음 매우 낮음
CPU 점유율 약 30% 약 35% 약 7%

5. SSR(서버사이드 렌더링) 최적화 전략

  • Static Template Cache: Docs, Form, Table 등 반복 구조는 캐시된 String 사용
  • Fragment-level Diff: 데이터 변경 없는 UI는 재렌더링 생략
  • Pre-render Hook: 미리 변환된 HTML을 ViewCache에 저장
  • Locale Snapshot: 다국어 메시지를 RenderContext에 캐시
// 예시: RenderContext 기반 캐싱
if (ctx.cacheContains(path)) {
  return ctx.getCached(path);
} else {
  String html = new DocsMainPage(model).render(ctx);
  ctx.putCache(path, html);
  return html;
}

6. 메모리 & Thread 전략

전략 설명
ThreadLocal Builder 요청별 StringBuilder 버퍼를 재사용하여 동시성 안전 확보
Buffer Size Limit 64KB 이상 렌더링 시 버퍼 초기화
Stateless RenderContext 세션 공유 대신 요청 단위로 생성하여 메모리 누수 방지

7. 최적화 체크리스트

  • render() 내부에 반복 생성 객체가 없는가?
  • ✅ HTML 빌드 시 El.text() 대신 El.raw()를 적절히 활용하고 있는가?
  • ✅ 자주 쓰이는 Fragment는 static final로 캐시했는가?
  • String.format() 대신 StringBuilder 사용 중인가?
주의: SSR 렌더링 중에 DB 쿼리나 파일 I/O를 실행하면 성능이 급격히 저하됩니다.

8. 실무 성능 팁

  • Docs 시스템: Node/Content JSON 캐시로 트리 조회 0.8ms
  • Estimation 시스템: Step Form Fragment 캐싱으로 렌더링 시간 40%↓
  • Event Board: DSL Card 반복 렌더링 대신 CachedComponent 활용
// CachedComponent 예시
public class CachedComponent implements HtmlComponent {
  private static final String cachedHtml;
  static {
    cachedHtml = El.div().css("footer").child(El.p().text("© UNeedSoft 2025")).render();
  }
  @Override public String render() { return cachedHtml; }
}

9. 요약

구분 핵심 포인트
렌더링 속도 Thymeleaf 대비 4~6배 빠름
객체 생성 기존 템플릿 엔진의 약 1/5 수준
메모리 효율 StringBuilder 재사용 + 캐시
확장성 Atomic Design 기반으로 구조적 일관성 유지

다음으로