๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Java & Spring ์‹ค์ „ ๊ฐœ๋ฐœ

2ํŽธ. Jackson ์ง๋ ฌํ™” ํŠœ๋‹ — CPU๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ์žก์•„๋จน๋Š” ์ˆจ์€ ๋ณ‘๋ชฉ ํ•ด๊ฒฐ๊ธฐ

๋ฐ˜์‘ํ˜•

 

Jackson ์ง๋ ฌํ™” ํŠœ๋‹

๐ŸŸฆ 2ํŽธ. Jackson ์ง๋ ฌํ™” ํŠœ๋‹ — CPU๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ์žก์•„๋จน๋Š” ์ˆจ์€ ๋ณ‘๋ชฉ ํ•ด๊ฒฐ๊ธฐ

Spring Boot ์„œ๋น„์Šค๋ฅผ ์šด์˜ํ•˜๋‹ค ๋ณด๋ฉด, DB๋‚˜ ์™ธ๋ถ€ API์ฒ˜๋Ÿผ ๋ช…ํ™•ํ•œ ๋ณ‘๋ชฉ๋งŒ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค.
APM์„ ์ž์„ธํžˆ ๋ณด๋ฉด ๊ฝค ๋งŽ์€ ํŠธ๋žœ์žญ์…˜์—์„œ ObjectMapper(JSON ์ง๋ ฌํ™”) ๊ฐ€ ์ „์ฒด ์‘๋‹ต ์‹œ๊ฐ„์˜ 20~40%๋ฅผ ์ฐจ์ง€ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

์ด๋ฒˆ ํŽธ์—์„œ๋Š” ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์‹ค์ œ๋กœ ๊ฒช์—ˆ๋˜ “Jackson ์ง๋ ฌํ™” ๋ณ‘๋ชฉ” ์ด์Šˆ๋ฅผ ๊ธฐ์ค€์œผ๋กœ,
์–ด๋–ป๊ฒŒ CPU๋ฅผ ์ ˆ๋ฐ˜ ์ดํ•˜๋กœ ์ค„์˜€๋Š”์ง€ ์‹ค์ „ ์ค‘์‹ฌ์œผ๋กœ ์ •๋ฆฌํ•ด๋ณธ๋‹ค.


โ–  ๋ฌธ์ œ 2: Jackson ์ง๋ ฌํ™”๊ฐ€ API ์‘๋‹ต์˜ ๋Œ€๋ถ€๋ถ„์„ ์ฐจ์ง€

API ์‘๋‹ต์ด ๋А๋ ค์ง€๋Š” ์›์ธ์„ ์ฐพ์•„๋ณด๋ฉด ์˜์™ธ๋กœ SQL๋„ ๋น ๋ฅด๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋„ ๋น ๋ฅธ๋ฐ
๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์ธ JSON ๋ณ€ํ™˜ ๋ถ€๋ถ„์—์„œ๋งŒ ์ˆ˜์‹ญ ms์”ฉ ์žก์•„๋จน๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

์šด์˜ ์„œ๋ฒ„์—์„œ ๊ด€์ธก๋œ ๋ฌธ์ œ:

  • ObjectMapper.writeValueAsString ๋‹จ๊ณ„์—์„œ๋งŒ 50~120ms ์†Œ๋ชจ
  • ๋Œ€๋Ÿ‰ ๋ฆฌ์ŠคํŠธ(1000๊ฑด ์ด์ƒ) ์‘๋‹ต์—์„œ CPU ์‚ฌ์šฉ๋ฅ  ๊ธ‰์ฆ
  • ๋™์‹œ ์š”์ฒญ ์‹œ Tomcat ์Šค๋ ˆ๋“œ๊ฐ€ ์ง๋ ฌํ™” ๋•Œ๋ฌธ์— ๋ง‰ํ˜€๋ฒ„๋ฆผ
  • GC ๋นˆ๋„ ์ฆ๊ฐ€ → ์ „์ฒด API ์‘๋‹ต์ด ์ง€์—ฐ

ํŠนํžˆ ๊ธˆ์œต๊ถŒ์ฒ˜๋Ÿผ ์‘๋‹ต ๊ฐ์ฒด๊ฐ€ ๋ณต์žกํ•˜๊ณ  ํ•„๋“œ๊ฐ€ ๋งŽ์„์ˆ˜๋ก ์ง๋ ฌํ™” ๋น„์šฉ์€ ๋” ์ปค์ง„๋‹ค.


โ— ์›์ธ ๋ถ„์„

1) Lombok ์˜ @Data + Getter ์กฐํ•ฉ ๋ฌธ์ œ

@Data ๋Š” equals, hashcode, toString ๊นŒ์ง€ ์ƒ์„ฑํ•ด๋ฒ„๋ฆฌ๋Š”๋ฐ,
Jackson ์ง๋ ฌํ™” ์‹œ ๋ฆฌํ”Œ๋ ‰์…˜ ๋น„์šฉ์ด ์ปค์ง€๊ณ  ํ•„๋“œ๋ฅผ ์Šค์บ”ํ•˜๋Š” ๋น„์šฉ๋„ ์ฆ๊ฐ€ํ•œ๋‹ค.

2) ๋ถˆํ•„์š”ํ•œ null ํ•„๋“œ๋„ ๋ชจ๋‘ JSON ์œผ๋กœ ์ถœ๋ ฅ

ํ•„๋“œ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ง๋ ฌํ™” ์‹œ๊ฐ„์ด ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ฆ๊ฐ€ํ•œ๋‹ค.

3) LocalDateTime ๋“ฑ ๋‚ ์งœ ํƒ€์ž… ๋ณ€ํ™˜ ๋น„์šฉ์ด ๋†’์Œ

Java 8 ๋‚ ์งœ ํƒ€์ž…์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง๋ ฌํ™” ๋น„์šฉ์ด ๊ฝค ํฌ๋‹ค.

4) ObjectMapper ์ธ์Šคํ„ด์Šค๋ฅผ ๋งค ์š”์ฒญ๋งˆ๋‹ค ์ƒ์„ฑ

Controller·Service ๋‚ด๋ถ€์—์„œ ObjectMapper๋ฅผ NEW ํ•ด์„œ ์“ฐ๋ฉด ์ง๋ ฌํ™” ๋น„์šฉ ํญ์ฆ.


โ— ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

์šด์˜ ํ™˜๊ฒฝ์—์„œ ๊ฐ€์žฅ ํšจ๊ณผ๊ฐ€ ์ปธ๋˜ ํŒจํ„ด์„ ์ •๋ฆฌํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.


โœ” 1) ObjectMapper Bean์„ ์ „์—ญ ์‹ฑ๊ธ€ํ„ด์œผ๋กœ ๋“ฑ๋ก

@Configuration
public class JacksonConfig {

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        return JsonMapper.builder()
                .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .serializationInclusion(JsonInclude.Include.NON_NULL)  // null ํ•„๋“œ ์ œ๊ฑฐ
                .build();
    }
}

ํšจ๊ณผ: ์ง๋ ฌํ™” ์‹œ๊ฐ„ 20~30% ๊ฐ์†Œ


โœ” 2) DTO์—์„œ @JsonInclude / @JsonIgnore ์ ๊ทน ์‚ฌ์šฉ

ํ•„์š” ์—†๋Š” ํ•„๋“œ๋ฅผ ๊ณผ๊ฐํžˆ ์ œ์™ธํ•˜๋ฉด ์ง๋ ฌํ™” ๋น„์šฉ์€ ๊ทธ๋Œ€๋กœ ์ค„์–ด๋“ ๋‹ค.

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseDto {

    private String name;

    @JsonIgnore
    private String internalCode;
}

ํšจ๊ณผ: ํ•„๋“œ๊ฐ€ ๋งŽ์€ ์‘๋‹ต ๊ฐ์ฒด์—์„œ CPU ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ


โœ” 3) ๋‚ ์งœ ์ง๋ ฌํ™”๋ฅผ ์œ„ํ•œ ๋ชจ๋“ˆ ์ ์šฉ

objectMapper.registerModule(new JavaTimeModule());

๋˜๋Š” ์ง์ ‘ ํฌ๋งท ์ง€์ •:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdAt;

ํšจ๊ณผ: LocalDateTime ์ง๋ ฌํ™” ๋น„์šฉ ์•ˆ์ •ํ™”


โœ” 4) @Data ๋Œ€์‹  @Getter + @Setter ์‚ฌ์šฉ

@Getter
@Setter
public class UserResponse {
    private Long id;
    private String name;
}

@ToString, @EqualsAndHashCode ์ž๋™์ƒ์„ฑ ๋น„์šฉ์„ ์ œ๊ฑฐํ•จ์œผ๋กœ์จ
๊ฐ์ฒด ์Šค์บ” ๋ฐ ์ง๋ ฌํ™” ๋น„์šฉ์ด ์‹ค์ œ๋กœ 10~20% ๊ฐ์†Œํ–ˆ๋‹ค.


โœ” 5) ๋Œ€๋Ÿ‰ ๋ฆฌ์ŠคํŠธ๋Š” “Stream → DTO ๋ณ€ํ™˜ → JSON” ๋Œ€์‹  ๋ฐ”๋กœ Writer ์‚ฌ์šฉ

objectMapper.writeValue(outputStream, resultList);

ํšจ๊ณผ: ์ค‘๊ฐ„ ๊ฐ์ฒด ์ƒ์„ฑ(GC) ๊ฐ์†Œ → TPS ํ–ฅ์ƒ


โ— ์ ์šฉ ํ›„ ์„ฑ๋Šฅ ๊ฐœ์„  ํšจ๊ณผ

์šด์˜ ์„œ๋ฒ„ ๊ธฐ์ค€:

ํ•ญ๋ชฉ ๊ฐœ์„  ์ „ ๊ฐœ์„  ํ›„

JSON ์ง๋ ฌํ™” ํ‰๊ท  60~120ms 18~35ms
CPU ์‚ฌ์šฉ๋ฅ  65% ์ด์ƒ 40% ์ดํ•˜
GC ๋นˆ๋„ 2~3๋ฐฐ ๊ฐ์†Œ ์ ˆ๋ฐ˜ ์ดํ•˜
TPS(์ดˆ๋‹น ์š”์ฒญ ์ฒ˜๋ฆฌ๋Ÿ‰) +15~20% ์ฆ๊ฐ€  

์ด์ฒ˜๋Ÿผ Jackson ํŠœ๋‹์€ ๋‹จ์ˆœํ•œ ์ตœ์ ํ™”๊ฐ€ ์•„๋‹ˆ๋ผ
์ „์ฒด API ์‘๋‹ต ์ง€์—ฐ์„ ์ค„์ด๋Š” ํ•ต์‹ฌ ์š”์†Œ๊ฐ€ ๋œ๋‹ค.


โ— ์‹ค์ „ ํŒ 3๊ฐœ (์šด์˜ ํ™˜๊ฒฝ ๊ธฐ์ค€)

1. @Data ๋ฅผ ์ƒ์‹œ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ๋ผ — ์ง๋ ฌํ™” ๋น„์šฉ ์ฆ๊ฐ€์˜ ์ฃผ๋ฒ”

ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ํšจ์œจ์ ์ด๋‹ค.

2. null ํ•„๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ์ง๋ ฌํ™” ์†๋„๋Š” ๋ˆˆ์— ๋„๊ฒŒ ๋นจ๋ผ์ง„๋‹ค

ํŠนํžˆ ๊ธˆ์œต ๋ฐ์ดํ„ฐ์ฒ˜๋Ÿผ ํ•„๋“œ๊ฐ€ 30๊ฐœ ์ด์ƒ์ด๋ผ๋ฉด ํšจ๊ณผ๊ฐ€ ํฌ๋‹ค.

3. ObjectMapper ๋Š” ๋ฐ˜๋“œ์‹œ ์‹ฑ๊ธ€ํ„ด Bean ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ผ

๋งค๋ฒˆ ์ƒ์„ฑํ•˜๋ฉด CPU·GC ๋ชจ๋‘ ํญ๋ฐœํ•œ๋‹ค.


๐Ÿงฉ ๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ํŽธ์—์„œ๋Š” Spring Boot ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์‹ค์ œ๋กœ ํšจ๊ณผ๊ฐ€ ์ปธ๋˜ Jackson ์ง๋ ฌํ™” ์„ฑ๋Šฅ ํŠœ๋‹์„ ๋‹ค๋ค˜๋‹ค.
๋‹ค์Œ ๊ธ€์—์„œ๋Š” ThreadPool ํŠœ๋‹, Tomcat NIO ์„ค์ •, slow request trace ๋ถ„์„ ๊ฐ™์€ ๋” ๊นŠ์€ ์šด์˜ ๊ฒฝํ—˜์„ ์ด์–ด์„œ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ค.


๐Ÿ”– TAGS

Java, SpringBoot, Jackson, JSON, PerformanceTuning, BackendOptimization, CPUOptimization, ProductionIssue, RealWorldTips

๋ฐ˜์‘ํ˜•