WeChat이 libco를 사용하여 8억 명의 사용자를 지원하는 방법

伊谢尔伦
풀어 주다: 2016-11-21 13:35:44
원래의
1971명이 탐색했습니다.

소개

Ibco는 WeChat 백엔드에서 대규모로 사용되는 c/C++ 코루틴 라이브러리로, 2013년부터 WeChat 백엔드의 수만 대의 머신에서 안정적으로 실행되고 있습니다. Libco는 Tencent의 6대 오픈 소스 프로젝트 중 하나로 2013년에 처음으로 오픈 소스화되었습니다. 최근 주요 업데이트가 https://github.com/tencent/libco에 동기화되었습니다. libco는 백엔드 민첩한 동기화 스타일 프로그래밍 모델을 지원하는 동시에 시스템의 높은 동시성 기능을 제공합니다.

libco에서 지원하는 기능

비즈니스 로직을 침범할 필요가 없으며 다중 프로세스 및 다중 스레드 서비스를 코루틴 서비스로 변환할 필요가 없으며 동시성 기능이 100배 향상됩니다.

CGI 프레임워크 지원, 웹 서비스 쉽게 구축(신규)

gethostbyname, mysqlclient, ssl과 같이 일반적으로 사용되는 세 번째 라이브러리 지원(신규)

선택적 공유 스택 모드, 단일 시스템 가능 수천만 개의 연결에 쉽게 액세스(신규);

완벽하고 간결한 코루틴 프로그래밍 인터페이스

– pthread와 유사한 인터페이스 디자인, 간단하고 명확한 인터페이스를 통해 코루틴 생성 및 복구를 완료할 수 있습니다. co_create, co_resume 등 – 클래스 __thread 코루틴 간 통신을 위한 코루틴 세마포 co_signal(신규) – 현장에서 백그라운드 비동기 작업을 작성하고 실행하기 위해 코루틴과 결합된 비언어 수준 람다 구현(신규) epoll/kqueue 기반 작고 가벼운 네트워크 프레임워크, 타임 룰렛 기반의 고성능 타이머

libco의 배경

초기 WeChat 백엔드는 복잡하고 변화하는 비즈니스 요구를 가지고 있었습니다. 제품 요구사항의 신속한 반복, 대부분의 모듈은 반동기 및 반비동기 모델을 채택합니다. 액세스 계층은 비동기식 모델이고 비즈니스 논리 계층은 동기식 다중 프로세스 또는 다중 스레드 모델입니다. 비즈니스 논리의 동시성 기능은 수십에서 수백 개에 불과합니다. WeChat의 비즈니스가 성장함에 따라 시스템 규모는 점점 커지고 각 모듈은 백엔드 서비스/네트워크 지터의 영향을 받기 쉽습니다.

비동기 변환의 선택

WeChat 백엔드의 동시성 기능을 향상시키기 위한 일반적인 접근 방식은 기존 네트워크의 모든 서비스를 비동기 모델로 변경하는 것입니다. 이 접근 방식에는 프레임워크부터 비즈니스 로직 코드까지 엄청난 양의 작업이 필요하며, 이를 위해서는 시간이 많이 걸리고 노동 집약적이며 위험한 완전한 변환이 필요합니다. 그래서 우리는 코루틴 사용에 대해 생각하기 시작했습니다.

그러나 코루틴을 사용하면 다음과 같은 문제에 직면하게 됩니다.

업계에서는 c/C++ 환경에서 코루틴을 대규모로 적용한 경험이 없습니다.

코루틴을 제어하는 ​​방법; 스케줄링;

소켓, mysqlclient 등과 같은 동기식 API 호출을 처리하는 방법

기존 전역 변수 및 스레드 전용 변수 사용을 처리하는 방법

마지막으로 libco를 통해 해결했습니다. 위의 모든 문제는 비즈니스 로직의 비침해적 비동기 변환을 달성합니다. 우리는 libco를 사용하여 수백 개의 WeChat 백엔드 모듈을 코루틴 및 비동기 변환으로 변환했습니다. 변환 프로세스 중에 비즈니스 로직 코드는 기본적으로 변경되지 않았습니다. 지금까지 WeChat 백엔드의 서비스 대부분은 다중 프로세스 또는 다중 스레드 코루틴 모델입니다. 동시성 기능은 이전에 비해 질적으로 향상되었으며 libco는 WeChat 백엔드 프레임워크의 초석이 되었습니다.

libco 프레임워크

libco 프레임워크는 인터페이스 계층, 시스템 기능 Hook 계층, 이벤트 기반 계층의 세 가지 계층으로 구분됩니다.

WeChat이 libco를 사용하여 8억 명의 사용자를 지원하는 방법
동기식 API 처리

주로 동기식 네트워크 호출인 동기식 API의 경우 libco의 주요 작업은 이러한 대기로 인한 리소스 점유를 제거하고 시스템의 동시성을 향상시키는 것입니다. 성능. 일반적인 네트워크 백그라운드 서비스의 경우 연결, 쓰기, 읽기 등의 단계를 거쳐 완전한 네트워크 상호 작용을 완료할 수 있습니다. 이러한 API를 동기식으로 호출하면 전체 스레드가 네트워크 상호 작용을 기다리면서 중단됩니다.

동기식 프로그래밍 스타일의 동시성 성능은 좋지 않지만 명확한 코드 논리, 쉬운 작성, 빠른 비즈니스 반복 및 민첩한 개발을 지원할 수 있다는 장점이 있습니다. 온라인에서 기존 비즈니스 로직 코드를 수정하지 않고 동기 프로그래밍의 장점을 계속 유지하기 위해 libco는 혁신적으로 네트워크 호출 인터페이스(Hook)를 인수하고 콜백을 통해 비동기 네트워크 IO에 코루틴 항복 및 복구를 이벤트로 등록했습니다. . 비즈니스 처리 중에 동기 네트워크 요청이 발생하면 libco 계층은 네트워크 요청을 비동기 이벤트로 등록하고, 이 코루틴은 CPU 점유를 포기하며, CPU는 실행을 위해 다른 코루틴으로 넘겨집니다. Libco는 네트워크 이벤트가 발생하거나 시간 초과되면 자동으로 코루틴 실행을 재개합니다.

우리는 Hook 메서드를 통해 대부분의 동기화 스타일 API를 인계받았으며 libco는 적절한 시간에 실행을 재개하도록 코루틴을 예약합니다.

수천만 개의 코루틴 지원

기본적으로 libco는 각 코루틴에 대해 독점적인 실행 스택을 갖습니다. 코루틴이 생성되면 힙 메모리에서 고정된 크기의 메모리가 코루틴으로 할당됩니다. .스택을 실행합니다. 코루틴을 사용하여 프런트 엔드에서 액세스 연결을 처리하는 경우 대규모 액세스 서비스의 경우 서비스의 동시성 제한이 메모리에 의해 쉽게 제한됩니다. 이를 위해 libco는 스택 없는 코루틴 공유 스택 모드도 제공합니다. 이를 통해 동일한 실행 스택을 공유하도록 여러 코루틴을 설정할 수 있습니다. 동일한 공유 스택 아래의 코루틴 간에 전환할 때 현재 실행 중인 스택 콘텐츠를 코루틴의 개인 메모리에 복사해야 합니다. 이러한 메모리 복사본 수를 줄이기 위해 공유 스택의 메모리 복사본은 서로 다른 코루틴 간에 전환할 때만 발생합니다. 공유 스택의 점유자가 변경되지 않은 경우 실행 중인 스택을 복사할 필요가 없습니다.


libco 코루틴의 공유 코루틴 스택 모드를 사용하면 충분한 코루틴을 생성하기만 하면 단일 시스템에서 수천만 개의 연결에 쉽게 액세스할 수 있습니다. libco 공유 스택 모드를 통해 1,000만 개의 코루틴(E5-2670 v3 @ 2.30GHz * 2, 128G 메모리)을 생성합니다. 각 100,000개의 코루틴은 128k 메모리를 사용합니다. 전체 stable echo 서비스의 총 메모리 소비량은 약 66G입니다.

코루틴 개인 변수

다중 프로세스 프로그램이 다중 스레드 프로그램으로 변환될 때 __thread를 사용하여 전역 변수를 빠르게 수정할 수 있습니다. 코루틴 환경에서 우리는 코루틴을 만들었습니다. 프로세스 변수 ROUTINE_VAR은 코루틴 변환 작업 부하를 크게 단순화합니다.

코루틴은 본질적으로 스레드 내에서 직렬로 실행되므로 스레드 전용 변수를 정의할 때 재진입 문제가 발생할 수 있습니다. 예를 들어, __thread라는 스레드 전용 변수를 정의하는 경우 원래는 각 실행 로직이 이 변수에 독점적으로 액세스할 수 있기를 원했습니다. 하지만 우리의 실행 환경을 코루틴으로 마이그레이션하면 동일한 스레드 전용 변수가 여러 코루틴에서 작동될 수 있어 변수 침입 문제가 발생할 수 있습니다. 이러한 이유로 우리는 libco의 비동기 변환을 수행할 때 대부분의 스레드 전용 변수를 코루틴 수준의 전용 변수로 변경했습니다. 코루틴 전용 변수에는 다음과 같은 특징이 있습니다. 코드가 다중 스레드 비코루틴 환경에서 실행되는 경우 변수는 스레드 전용입니다. 코드가 코루틴 환경에서 실행되는 경우 이 변수는 코루틴 전용입니다. 기본 코루틴 개인 변수는 실행 환경을 자동으로 결정하고 필요한 값을 올바르게 반환합니다.

코루틴 프라이빗 변수는 기존 환경을 동기화에서 비동기화로 전환하는 데 결정적인 역할을 하는 동시에 코루틴 프라이빗 변수를 정의하는 매우 간단하고 편리한 방법을 정의했습니다. 선언 코드 줄.

 gethostbyname의 후크 방법

기존 네트워크 서비스의 경우 시스템의 gethostbyname API 인터페이스를 통해 실제 주소를 얻기 위해 DNS에 쿼리해야 할 수도 있습니다. 코루틴 변환 중에 우리 후크의 소켓 패밀리 기능이 gethostbyname에 적용되지 않는다는 것을 발견했습니다. 코루틴이 gethostbyname을 호출하면 결과를 동기적으로 기다리므로 동일한 스레드의 다른 코루틴이 실행이 지연됩니다. 우리는 glibc의 gethostbyname 소스 코드를 연구한 결과 glibc가 이벤트를 기다리기 위해 내부적으로 __poll 메서드를 정의하는 동시에 일반 폴 메서드 대신 스레드 전용 변수도 정의하기 때문에 후크가 적용되지 않는다는 것을 발견했습니다. 이는 다른 코루틴에서 사용될 수 있습니다. 전환하면 재진입이 발생하여 데이터가 부정확해질 수 있습니다. 마지막으로 gethostbyname 코루틴의 비동기화는 Hook __poll 메서드와 코루틴 개인 변수 정의를 통해 해결됩니다.
코루틴 세마포

멀티 스레드 환경에서는 스레드 간 동기화 요구 사항이 있습니다. 예를 들어 한 스레드의 실행은 다른 스레드의 신호를 기다려야 합니다. , 우리는 일반적으로 pthread_signal을 사용하여 해결됩니다. libco에서는 코루틴 간의 동시성 요구 사항을 처리하기 위해 코루틴 세마포 co_signal을 정의합니다. 코루틴은 co_cond_signal 및 co_cond_broadcast를 통해 대기 중인 코루틴에 알리거나 대기 중인 모든 코루틴을 깨울지 결정할 수 있습니다.

요약

Libco는 완전한 코루틴 프로그래밍 인터페이스, 일반적으로 사용되는 소켓 계열 함수 Hook 등을 제공하는 효율적인 c/C++ 코루틴 라이브러리로, 동기 프로그래밍의 빠른 반복에 비즈니스를 사용할 수 있게 해줍니다. 모델 개발. 지난 몇 년간 안정적인 운영을 통해 libco는 WeChat 백엔드 프레임워크의 초석으로서 중추적인 역할을 해왔습니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿