🏢 LINE (LY Corporation) 기술 스택 분석

28 min read
linely-corporationjavakotlinopenstackkubernetesverdamessagingfintech

LINE이 아시아 2억+ 사용자에게 서비스를 제공하는 기술 스택 심층 분석 - Java, Kotlin, Verda 프라이빗 클라우드

🏢 LINE (LY Corporation) 기술 스택 분석

일본, 대만, 태국, 인도네시아 등 아시아 전역에서 2억+ 사용자에게 서비스를 제공하는 LINE의 기술 스택을 분석합니다. 2023년 10월 LINE과 Yahoo! JAPAN이 합병하여 LY Corporation으로 재출범


📊 회사 개요

서비스 규모

  • 월간 활성 사용자: 2억+ 명 (일본, 대만, 태국, 인도네시아)
  • 일일 메시지: 수십억 건
  • 주요 서비스: LINE 메신저, LINE Pay, LINE MUSIC, LINE MANGA
  • 합병 후: Yahoo! JAPAN, PayPay, ZOZO 등 통합

엔지니어링 조직

  • 개발자: 10,000명+ (LY Corporation 전체)
  • Verda 인프라 엔지니어: 60명+
  • 내부 개발자 사용자: 2,500명+ (Verda 플랫폼)
  • 오픈소스: 100+ 프로젝트 공개

기술적 도전과제

  1. 대규모 트래픽: 아시아 전역 수억 사용자
  2. 프라이버시: 엄격한 보안 및 개인정보 보호
  3. 글로벌 스케일: 다국가 인프라 운영
  4. 자체 클라우드: Verda 프라이빗 클라우드 운영

🏗️ 아키텍처 Overview

시스템 다이어그램

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│    LINE     │────►│   Proxy     │────►│   Backend   │
│   Clients   │     │   Layer     │     │   Services  │
└─────────────┘     └─────────────┘     └─────────────┘
       │                    │                    │
       │              ┌─────▼─────┐       ┌─────▼─────┐
       │              │  Armeria   │       │  Storage  │
       │              │  Gateway   │       │  (HBase)  │
       │              └───────────┘       └───────────┘
       │                    │                    │
       └────────────────────┤                    │
                      ┌─────▼─────┐       ┌─────▼─────┐
                      │   Verda    │       │   Kafka   │
                      │   Cloud    │       │  Cluster  │
                      └───────────┘       └───────────┘

Verda 프라이빗 클라우드 아키텍처

┌──────────────────────────────────────────────────────────┐
│                      Verda Platform                       │
├─────────────────────────┬────────────────────────────────┤
│       PaaS Layer        │         IaaS Layer             │
├─────────────────────────┼────────────────────────────────┤
│ • Kubernetes (VKS)      │ • Virtual Machines             │
│ • MySQL Managed         │ • Block Storage                │
│ • Redis Managed         │ • Object Storage               │
│ • Elasticsearch         │ • Shared Filesystem            │
│ • Kafka Managed         │ • Load Balancer                │
│ • CI/CD Pipeline        │ • NAT Gateway                  │
│ • Function (Serverless) │ • DNS as a Service             │
└─────────────────────────┴────────────────────────────────┘
                         ↓
           ┌─────────────────────────────┐
           │      OpenStack Core         │
           │  • Nova (Compute)           │
           │  • Neutron (Network)        │
           │  • Cinder (Block Storage)   │
           │  • Designate (DNS)          │
           │  • Custom Nova Driver       │
           │  • SRv6 Overlay Network     │
           └─────────────────────────────┘
                         ↓
           ┌─────────────────────────────┐
           │   Physical Infrastructure   │
           │   6,000+ Hypervisors        │
           │   4M+ CPU Cores             │
           └─────────────────────────────┘

핵심 설계 원칙

  1. Private Cloud First: 보안/프라이버시를 위한 자체 클라우드
  2. Microservices: 서비스별 독립 배포
  3. Polyglot: Java, Kotlin, Perl, Node.js 혼용
  4. Infrastructure as Code: Terraform 기반 관리
  5. Cloud Native: Kubernetes 기반 컨테이너화

기술 진화

  • 2011: LINE 메신저 출시 (동일본 대지진 이후)
  • 2014-2016: 글로벌 확장, 핀테크 진출
  • 2016: Verda 프라이빗 클라우드 시작
  • 2018-2020: LINE Pay, LINE Bank 확대
  • 2023: Yahoo! JAPAN과 합병, LY Corporation 출범
  • 2024-현재: 통합 플랫폼 구축

🧩 기술 스택 상세

Backend 기술

언어 및 프레임워크

| Technology | Usage | Notes | | ----------- | ------------- | --------------------------- | | Java | 핵심 백엔드 | 레거시 및 고성능 서비스 | | Kotlin | 신규 개발 | Perl 마이그레이션 대상 언어 | | Perl | 레거시 시스템 | 점진적 Kotlin 전환 중 | | Node.js | 웹 서비스 | Express, SSR | | Go | 인프라 도구 | Kubernetes 컨트롤러 |

Armeria - LINE의 오픈소스 RPC 프레임워크

// Armeria 서버 예시
import com.linecorp.armeria.server.Server;
import com.linecorp.armeria.server.grpc.GrpcService;
import com.linecorp.armeria.server.docs.DocService;

public class LineServiceServer {

    public static void main(String[] args) {
        Server server = Server.builder()
            .http(8080)
            .https(8443)
            .tlsSelfSigned()
            // gRPC 서비스
            .service(
                GrpcService.builder()
                    .addService(new MessagingServiceImpl())
                    .addService(new UserServiceImpl())
                    .enableUnframedRequests(true)
                    .build()
            )
            // REST API
            .annotatedService("/api", new RestApiService())
            // Thrift 서비스 (레거시 호환)
            .service("/thrift", THttpService.of(new ThriftServiceImpl()))
            // 문서화
            .serviceUnder("/docs", DocService.builder().build())
            // 헬스체크
            .service("/health", HealthCheckService.of())
            // 메트릭
            .decorator(MetricCollectingService.newDecorator())
            .build();

        server.start().join();
    }
}

// gRPC 서비스 구현
@GrpcService
public class MessagingServiceImpl extends MessagingServiceGrpc.MessagingServiceImplBase {

    private final MessageRepository messageRepository;
    private final UserPresenceService presenceService;
    private final NotificationService notificationService;

    @Override
    public void sendMessage(SendMessageRequest request,
                           StreamObserver<SendMessageResponse> responseObserver) {
        try {
            // 메시지 검증
            validateMessage(request);

            // 메시지 저장
            Message message = Message.builder()
                .id(generateMessageId())
                .senderId(request.getSenderId())
                .chatId(request.getChatId())
                .content(request.getContent())
                .type(request.getType())
                .timestamp(Instant.now())
                .build();

            messageRepository.save(message);

            // 수신자에게 전달
            List<String> recipients = getChatMembers(request.getChatId());
            recipients.stream()
                .filter(userId -> !userId.equals(request.getSenderId()))
                .forEach(userId -> {
                    if (presenceService.isOnline(userId)) {
                        // 실시간 전송
                        pushToClient(userId, message);
                    } else {
                        // 푸시 알림
                        notificationService.sendPush(userId, message);
                    }
                });

            responseObserver.onNext(SendMessageResponse.newBuilder()
                .setMessageId(message.getId())
                .setTimestamp(message.getTimestamp().toEpochMilli())
                .setStatus(Status.SUCCESS)
                .build());
            responseObserver.onCompleted();

        } catch (Exception e) {
            responseObserver.onError(
                Status.INTERNAL
                    .withDescription(e.getMessage())
                    .asRuntimeException()
            );
        }
    }
}

Kotlin 백엔드 (LINE Creators Market)

// Kotlin + Spring WebFlux 서비스
@RestController
@RequestMapping("/api/v1/stickers")
class StickerController(
    private val stickerService: StickerService,
    private val authService: AuthService
) {

    @GetMapping("/{stickerId}")
    suspend fun getSticker(
        @PathVariable stickerId: Long,
        @RequestHeader("Authorization") token: String
    ): ResponseEntity<StickerDto> {
        val user = authService.validateToken(token)
        val sticker = stickerService.findById(stickerId)

        return if (sticker != null) {
            ResponseEntity.ok(sticker.toDto())
        } else {
            ResponseEntity.notFound().build()
        }
    }

    @PostMapping
    suspend fun createSticker(
        @RequestBody request: CreateStickerRequest,
        @RequestHeader("Authorization") token: String
    ): ResponseEntity<StickerDto> {
        val creator = authService.validateCreator(token)

        val sticker = stickerService.create(
            Sticker(
                creatorId = creator.id,
                title = request.title,
                description = request.description,
                images = request.images,
                price = request.price,
                status = StickerStatus.PENDING_REVIEW
            )
        )

        return ResponseEntity
            .status(HttpStatus.CREATED)
            .body(sticker.toDto())
    }

    @GetMapping("/trending")
    fun getTrendingStickers(
        @RequestParam(defaultValue = "0") page: Int,
        @RequestParam(defaultValue = "20") size: Int
    ): Flow<StickerDto> = flow {
        stickerService.getTrending(page, size)
            .collect { sticker ->
                emit(sticker.toDto())
            }
    }
}

// 코루틴 기반 서비스
@Service
class StickerService(
    private val stickerRepository: StickerRepository,
    private val searchService: ElasticsearchService,
    private val cacheService: RedisCacheService
) {

    suspend fun findById(id: Long): Sticker? {
        // 캐시 확인
        cacheService.get<Sticker>("sticker:$id")?.let { return it }

        // DB 조회
        val sticker = stickerRepository.findById(id)

        // 캐시 저장
        sticker?.let {
            cacheService.set("sticker:$id", it, Duration.ofHours(1))
        }

        return sticker
    }

    fun getTrending(page: Int, size: Int): Flow<Sticker> = flow {
        val ids = cacheService.zrevrange<Long>(
            "trending:stickers",
            (page * size).toLong(),
            ((page + 1) * size - 1).toLong()
        )

        coroutineScope {
            ids.map { id ->
                async { findById(id) }
            }.awaitAll()
                .filterNotNull()
                .forEach { emit(it) }
        }
    }

    suspend fun search(query: String, filters: SearchFilters): List<Sticker> {
        return searchService.search(
            index = "stickers",
            query = SearchQuery(
                text = query,
                filters = mapOf(
                    "status" to "APPROVED",
                    "category" to filters.category,
                    "priceRange" to filters.priceRange
                ),
                sort = filters.sortBy,
                size = filters.limit
            )
        )
    }
}

Frontend 기술

State of LY Frontend 2024

LY Corporation의 프론트엔드 기술 현황 (2024년 내부 조사 기반):

| Category | Technologies | | ------------- | ------------------------------ | | Framework | React, Vue.js, Next.js | | Language | TypeScript (주력) | | Styling | CSS Modules, Tailwind CSS | | State | Redux, Zustand, TanStack Query | | Testing | Jest, Vitest, Playwright | | Build | Vite, Webpack, Turbopack |

LINE 웹 클라이언트

// LINE 웹 클라이언트 (React + TypeScript)
import React, { useEffect, useCallback } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";

interface Message {
  id: string;
  chatId: string;
  senderId: string;
  content: string;
  type: "text" | "image" | "sticker" | "file";
  timestamp: number;
  readBy: string[];
}

interface ChatRoomProps {
  chatId: string;
}

export const ChatRoom: React.FC<ChatRoomProps> = ({ chatId }) => {
  const queryClient = useQueryClient();
  const { user } = useAuth();

  // 메시지 조회
  const { data: messages, isLoading } = useQuery({
    queryKey: ["messages", chatId],
    queryFn: () => fetchMessages(chatId),
    staleTime: 0,
    refetchOnWindowFocus: true,
  });

  // 실시간 메시지 구독
  useEffect(() => {
    const ws = new WebSocket(`wss://chat.line.me/ws/${chatId}`);

    ws.onmessage = (event) => {
      const message: Message = JSON.parse(event.data);

      queryClient.setQueryData(["messages", chatId], (old: Message[] = []) => [
        ...old,
        message,
      ]);

      // 읽음 처리
      if (message.senderId !== user.id) {
        markAsRead(message.id);
      }
    };

    return () => ws.close();
  }, [chatId, queryClient, user.id]);

  // 메시지 전송
  const sendMutation = useMutation({
    mutationFn: (content: string) => sendMessage(chatId, content),
    onMutate: async (content) => {
      // 낙관적 업데이트
      const optimisticMessage: Message = {
        id: `temp-${Date.now()}`,
        chatId,
        senderId: user.id,
        content,
        type: "text",
        timestamp: Date.now(),
        readBy: [user.id],
      };

      queryClient.setQueryData(["messages", chatId], (old: Message[] = []) => [
        ...old,
        optimisticMessage,
      ]);

      return { optimisticMessage };
    },
    onError: (_, __, context) => {
      // 롤백
      if (context?.optimisticMessage) {
        queryClient.setQueryData(["messages", chatId], (old: Message[] = []) =>
          old.filter((m) => m.id !== context.optimisticMessage.id)
        );
      }
    },
  });

  const handleSend = useCallback(
    (content: string) => {
      if (content.trim()) {
        sendMutation.mutate(content);
      }
    },
    [sendMutation]
  );

  if (isLoading) return <LoadingSpinner />;

  return (
    <div className="chat-room">
      <MessageList messages={messages || []} currentUserId={user.id} />
      <MessageInput onSend={handleSend} disabled={sendMutation.isPending} />
    </div>
  );
};

인프라: Verda 프라이빗 클라우드

Verda 핵심 특징

  • OpenStack 기반: Nova, Neutron, Cinder, Designate
  • Kubernetes 지원: Rancher 기반 VKS (Verda Kubernetes Service)
  • SRv6 네트워크: 테넌트 격리를 위한 커스텀 오버레이
  • IaC: Terraform으로 인프라 관리

규모

  • 하이퍼바이저: 1,400 → 6,000+ (2년간 4배 성장)
  • CPU 코어: 400만+ 코어
  • 내부 사용자: 2,500+ 개발자
  • 인프라 엔지니어: 60명+

Terraform for Verda

# Verda 리소스 프로비저닝 예시
terraform {
  required_providers {
    verda = {
      source  = "linecorp/verda"
      version = "~> 1.0"
    }
  }
}

provider "verda" {
  region     = "jp-east-1"
  project_id = var.project_id
}

# Kubernetes 클러스터
resource "verda_kubernetes_cluster" "main" {
  name               = "line-service-cluster"
  kubernetes_version = "1.28"

  master_config {
    instance_type = "m4.large"
    count         = 3
  }

  node_pool {
    name          = "default-pool"
    instance_type = "m4.xlarge"
    min_size      = 3
    max_size      = 100

    autoscaling {
      enabled = true
    }
  }

  network {
    vpc_id    = verda_vpc.main.id
    subnet_id = verda_subnet.private.id
  }
}

# 관리형 MySQL
resource "verda_mysql" "main" {
  name           = "line-db"
  engine_version = "8.0"
  instance_type  = "db.r5.2xlarge"

  storage {
    type = "ssd"
    size = 500
  }

  replication {
    mode     = "async"
    replicas = 2
  }

  backup {
    enabled         = true
    retention_days  = 30
    window          = "03:00-04:00"
  }
}

# 관리형 Redis
resource "verda_redis" "cache" {
  name          = "line-cache"
  version       = "7.0"
  instance_type = "cache.r5.large"

  cluster_mode {
    enabled = true
    shards  = 3
    replicas_per_shard = 2
  }
}

# 관리형 Kafka
resource "verda_kafka" "events" {
  name    = "line-events"
  version = "3.5"

  broker_config {
    instance_type = "kafka.m5.2xlarge"
    count         = 6
  }

  storage {
    size_per_broker = 1000
    retention_hours = 168
  }
}

데이터 인프라

메시지 저장 및 처리

| Layer | Technology | Purpose | | ----------------- | ------------- | ------------------------- | | Primary DB | MySQL | 사용자, 채팅방 메타데이터 | | Message Store | HBase | 대량 메시지 저장 | | Cache | Redis | 세션, 최근 메시지 | | Search | Elasticsearch | 메시지 검색 | | Queue | Kafka | 이벤트 스트리밍 |


🔧 주요 오픈소스 프로젝트

LINE이 공개한 주요 오픈소스:

| Project | Description | Stars | | --------------------------------------------------------- | -------------------------- | -------- | | Armeria | 비동기 RPC/REST 프레임워크 | ⭐ 4.8k+ | | Central Dogma | 분산 설정 관리 서비스 | ⭐ 600+ | | LINE Bot SDK | LINE 봇 개발 SDK | ⭐ 700+ | | LINESimpleBLE | Bluetooth LE 라이브러리 | - | | Promgen | Prometheus 관리 도구 | ⭐ 800+ |

Armeria 상세

// Armeria의 주요 기능

// 1. 다중 프로토콜 지원 (HTTP/1, HTTP/2, gRPC, Thrift)
Server server = Server.builder()
    .service("/grpc", GrpcService.builder()
        .addService(new MyGrpcService())
        .build())
    .service("/thrift", THttpService.of(new MyThriftService()))
    .annotatedService("/rest", new MyRestService())
    .build();

// 2. 클라이언트 사이드 로드밸런싱
WebClient client = WebClient.builder("group:my-service")
    .endpointRemapper(endpoint ->
        Endpoint.of("service-discovery.local", 8080)
            .withWeight(100))
    .decorator(RetryingClient.builder(
        RetryRule.failsafe())
        .maxTotalAttempts(3)
        .newDecorator())
    .decorator(CircuitBreakerClient.builder(
        CircuitBreaker.builder("my-service")
            .failureRateThreshold(0.5)
            .build())
        .newDecorator())
    .build();

// 3. 서킷 브레이커 + 리트라이
@Decorator(CircuitBreakerClientBuilder.class)
@Decorator(RetryingClientBuilder.class)
public interface MyServiceClient {
    @Get("/api/data")
    CompletableFuture<Data> getData();
}

💡 핵심 기술 인사이트

1. 프라이빗 클라우드 선택의 이유

  • 보안: 엄격한 개인정보 보호 정책
  • 비용: 대규모 운영 시 퍼블릭 클라우드 대비 효율적
  • 커스터마이징: 특수 요구사항 대응 (SRv6 네트워크 등)
  • 데이터 주권: 각국 규제 대응

2. Polyglot 전략

  • Java: 안정성이 필요한 핵심 시스템
  • Kotlin: 신규 개발 및 레거시 마이그레이션
  • Perl → Kotlin: 점진적 현대화
  • Node.js: 웹 SSR 서비스

3. OpenStack 커스터마이징

  • 표준 Ironic 대신 자체 Nova 드라이버 개발
  • SRv6 기반 L3 오버레이 네트워크
  • Rancher 기반 Kubernetes (Magnum 대체)

📈 성과 & 지표

기술적 성과

  • 인프라 성장: 2년간 4배 (1,400 → 6,000 하이퍼바이저)
  • CPU 코어: 400만+ 코어 운영
  • 개발자 지원: 2,500+ 내부 개발자
  • 서비스 가용성: 99.9%+

비즈니스 영향

  • MAU: 2억+ (일본, 대만, 태국, 인도네시아)
  • LINE Pay 거래: 연간 수조 원
  • LY Corporation 매출: 연간 1.7조 엔+ (합병 후)

🎓 LINE에서 배울 점

✅ 적용 가능한 패턴

  1. 프라이빗 클라우드: 보안/비용 최적화
  2. Armeria: 고성능 마이크로서비스
  3. Polyglot 마이그레이션: 점진적 현대화
  4. IaC: Terraform 기반 인프라 관리
  5. 오픈소스 문화: 핵심 기술 공개

❌ 주의사항

  1. 운영 복잡성: 대규모 프라이빗 클라우드 운영 부담
  2. 기술 부채: Perl 레거시 시스템
  3. 통합 과제: Yahoo! JAPAN 합병 후 시스템 통합
  4. 인재 확보: 전문 인력 필요

📚 추천 리소스


🔮 미래 전망

통합 후 집중 분야

  1. 통합 플랫폼: LINE + Yahoo! JAPAN 시너지
  2. AI 강화: 검색, 추천, 챗봇 고도화
  3. 핀테크: PayPay, LINE Pay 통합
  4. 이커머스: ZOZO, Yahoo! 쇼핑 연계
  5. 미디어: 뉴스, 엔터테인먼트 통합

기술 투자 영역

  • LLM/AI: 생성형 AI 서비스
  • 클라우드 확장: Verda 글로벌 확대
  • Web3: 블록체인, NFT 플랫폼
  • 보안: 제로 트러스트 아키텍처
  • 개발자 경험: 내부 플랫폼 고도화

"기술로 CLOSING THE DISTANCE - 사람과 사람, 사람과 정보를 연결합니다."

  • LY Corporation

마지막 업데이트: 2025-12-05

Found this helpful? Share it with others!
Tweet

🔗 Related Content

You might also be interested in these articles

🏢 company

🏢 카카오 기술 스택 분석

카카오가 5천만 한국인의 일상을 연결하는 기술 스택 심층 분석 - Java, Kotlin, MySQL로 구축한 국민 메신저부터 슈퍼앱까지

32 min read
kakao, java +9
Read more
🏢 company

🏢 배달의민족 기술 스택 분석

배달의민족이 한국 배달 문화를 혁신하며 동남아로 확장한 기술 스택 심층 분석 - Java, Spring, Kotlin으로 구축한 O2O 플랫폼

51 min read
baemin, woowa +10
Read more
🏢 company

🏢 토스 기술 스택 분석

토스가 한국 금융을 혁신하며 유니콘으로 성장한 기술 스택 심층 분석 - Node.js, React Native, Kotlin으로 만든 모바일 금융 플랫폼

39 min read
toss, nodejs +8
Read more
🏢 company

🏢 Airbnb 기술 스택 분석

에어비앤비가 전 세계 400만 개의 숙소를 연결하는 글로벌 마켓플레이스 기술 스택 심층 분석 - Ruby on Rails에서 Service-Oriented Architecture로의 진화

24 min read
airbnb, ruby +12
Read more
🏢 company

🏢 Canva 기술 스택 분석

캔바가 1억 명 이상의 사용자에게 쉽고 강력한 디자인 도구를 제공하는 기술 스택 심층 분석 - Java, TypeScript, AWS로 구축한 대규모 디자인 플랫폼

32 min read
canva, java +10
Read more
🏢 company

🏢 당근마켓 기술 스택 분석

당근마켓이 동네 커뮤니티를 혁신하며 유니콘으로 성장한 기술 스택 심층 분석 - Ruby on Rails, Kotlin, Swift로 만든 하이퍼로컬 플랫폼

48 min read
karrot, daangn +9
Read more

Found this helpful?

Help us improve this content by contributing on GitHub or sharing your feedback with the community.