메뉴
HN
Hacker News 23일 전

GitHub Freno: 협력적 고가용성 스로틀러 서비스

IMP
7/10
핵심 요약

Freno는 애플리케이션이 데이터베이스(MySQL 등)에 데이터를 쓰기 전에 요청을 중계하여 과부하를 막아주는 협력적 스로틀러입니다. 대량의 업데이트나 스키마 변경 작업 시 발생할 수 있는 데이터베이스 복제 지연(Replication Lag) 문제를 방지하여 서비스 안정성을 높여줍니다. Raft 합의 알고리즘을 기반으로 고가용성을 보장하며, 클라이언트는 HTTP 요청을 통해 안전하게 쓰기 작업을 진행할 수 있습니다.

번역된 본문

Freno는 협력적이며 고가용성을 갖춘 스로틀러(throttler) 서비스입니다. 클라이언트는 리소스에 대한 쓰기 작업을 제어(throttle)하기 위해 freno를 사용합니다. 현재 구현된 버전은 여러 MySQL 클러스터의 복제(Replication) 상태를 기반으로 쓰기 작업을 제어할 수 있습니다. 복제 지연(lag)이 미리 정의된 임계치를 초과하면 freno는 협력적인 클라이언트의 쓰기 작업을 제한합니다. freno는 서버 인벤토리의 변경 사항에 동적으로 적응하며, 사용자가 직접 특정 앱의 쓰기를 강제로 제한하도록 제어할 수도 있습니다. freno는 고가용성을 제공하며 리더십을 결정하고 구성원 노드 간에 사용자 이벤트를 전달하기 위해 Raft 합의 프로토콜을 사용합니다.

협력적 스로틀러인 freno는 백엔드 저장소(현재는 MySQL만 지원)에서 데이터를 수집하며, "백엔드 저장소에 쓰기를 해도 되는가?"라는 질문에 답할 수 있는 로직을 갖추고 있습니다. 클라이언트(애플리케이션, 스크립트, 작업)는 freno에 이를 문의해야 합니다. freno는 클라이언트와 백엔드 저장소 사이의 프록시(Proxy)가 아닙니다. 단순히 저장소를 관찰하고 "쓰기 가능" 또는 "쓰기 중단" 상태를 알려줄 뿐입니다. 클라이언트는 freno에 문의하고 그 권고 사항을 존중해야 합니다.

저장소 및 앱 freno는 데이터 저장소별로 데이터를 수집합니다. 예를 들어 MySQL 클러스터를 탐색할 때 클러스터별로 복제 지연을 독립적으로 수집합니다. 백엔드 저장소의 메트릭은 자동으로 수집되며 절대적인 사실로 간주됩니다. freno는 '앱(app)'으로 식별되는 클라이언트에 서비스를 제공합니다. freno는 협력적 방식이므로 앱이 스스로를 식별할 것이라고 신뢰합니다. 앱은 관리될 수 있습니다. 즉, freno에게 특정 앱의 작업을 강제로 제한하도록 지시할 수 있습니다. 이는 우선순위가 높은 다른 앱들이 작업을 완료할 수 있도록 하기 위함입니다. freno는 단순히 무엇을 제한할지에 대한 지시만 받을 뿐, 자체적인 스케줄링이나 우선순위 지정 로직은 가지고 있지 않습니다.

MySQL freno는 원래 MySQL 제어에 대한 통합적이고 자체 적응 가능한 솔루션을 제공하도록 설계되었습니다. 즉, 복제 지연을 낮게 유지하면서 쓰기를 제어하는 역할입니다. freno는 미리 정의된 MySQL 클러스터 목록으로 구성됩니다. 여기에는 자격 증명, 지연(또는 기타) 검사 쿼리, 예상 임계치가 포함될 수 있습니다. 각 클러스터에 대해 freno는 데이터를 탐색하고 수집할 서버를 알아야 합니다. 각 클러스터별로 다음 목록을 제공할 수 있습니다:

  • 정적 목록: 호스트 이름[:포트]가 하드코딩된 목록
  • 동적 목록: 호스트는 자유롭게 추가되거나 삭제될 수 있으며, 제어 방식은 이러한 변경에 맞춰 동적으로 적응합니다. 지원되는 동적 옵션은 다음과 같습니다. HAProxy를 통해 제공: freno에 HAProxy URL 및 백엔드/풀 이름을 제공하면, freno는 주기적으로 해당 풀에서 활성화된 서버 목록을 파싱하고 동적으로 탐색을 적용합니다.

사용 사례 freno는 대량 작업, 예를 들어 대규모 데이터 로딩/아카이빙, 스키마 마이그레이션, 대규모 업데이트에 매우 유용합니다. 이러한 작업들은 일반적으로 수천에서 수백만 건의 행(Row)을 거치며 MySQL 복제 지연과 같은 원치 않는 부작용을 초래할 수 있습니다. 이러한 작업을 작은 하위 작업(예: 한 번에 100개 행)으로 나누고, 각 하위 작업을 적용하기 전에 freno에 문의함으로써 데이터베이스와 이를 사용하는 애플리케이션에 악영향을 주지 않고 동일한 결과를 얻을 수 있습니다. freno는 복제본의 유효성을 추론하기 위한 실제 지연 측정에도 사용될 수 있으며, 이는 마스터 노드에서 직접 읽어올 때 발생하는 '쓰기 후 읽기(Write-then-read)' 문제를 완화하는 데 도움을 줍니다.

HTTP freno는 HTTP를 통해 요청을 제공합니다. 가장 중요한 요청은 "이 앱이 이 저장소에 쓰기를 해도 되는가?"를 묻는 확인 요청입니다. freno는 HEAD 요청을 권장하며(GET도 허용되지만 오버헤드가 더 큽니다), 다음과 같은 상태 코드로 응답합니다:

  • 200 (OK): 애플리케이션이 데이터 저장소에 쓸 수 있습니다.
  • 404 (Not Found): 알 수 없는 메트릭 이름입니다.
  • 417 (Expectation Failed): 요청한 애플리케이션은 쓰기가 명시적으로 금지되었습니다.
  • 429 (Too Many Requests): 쓰지 마십시오. 저장소 상태가 예상 임계치를 충족하지 못함을 나타내는 정상적인 상태입니다.
  • 500 (Internal Server Error): 내부 오류입니다. 쓰지 마십시오.

클라이언트 클라이언트는 일반적으로 HEAD를 통해 /check/... 요청을 보냅니다. 클라이언트는 초당 수많은 요청을 보낼 수 있습니다. freno는 리소스 소모가 적습니다. 초당 수백 번 freno를 호출해도 문제가 없습니다. (물론 하드웨어와 리소스에 따라 다릅니다.)

원문 보기
원문 보기 (영어)
freno Cooperative, highly available throttler service: clients use freno to throttle writes to a resource. Current implementation can throttle writes to (multiple) MySQL clusters, based on replication status for those clusters. freno will throttle cooperative clients when replication lag exceeds a pre-defined threshold. freno dynamically adapts to changes in server inventory; it can further be controlled by the user to force throttling of certain apps. freno is highly available and uses raft consensus protocol to decide leadership and to pass user events between member nodes. Cooperative freno collects data from backend stores (at this time MySQL only) and has the logic to answer the question "may I write to the backend store?" Clients (application, scripts, jobs) are expected to consult with freno . freno is not a proxy between the client and the backend store. It merely observes the store and states "you're good to write" or "you should stop writing". Clients are expected to consult with freno and respect its recommendation. Stores and apps freno collects data per data store. E.g. when probing MySQL clusters it will collect replication lag per cluster, independently. Backend store metrics are collected automatically and represent absolute truths. freno serves clients, identified as apps . Since freno is cooperative, it trusts apps to identify themselves. Apps can be managed: freno can be instructed to forcibly throttle a certain app. This is so as to enable other, high priority apps to run to completion. freno merely accepts instructions on who to throttle, and does not have scheduling/prioritization logic of its own. MySQL freno is originally designed to provide a unified, self adapting solution to MySQL throttling: controlling writes while maintaining low replication lag. freno is configured with a pre-defined list of MySQL clusters. This may includes credentials, lag (or other) inspection query, and expected thresholds. For each cluster, freno needs to know what servers to probe and collect data from. For each cluster, you may provide this list: static, hard coded list of hostname[:port] dynamic. Hosts may come and go, and throttling may adapt to these changes. Supported dynamic options: via haproxy : provide freno with a haproxy URL and backend/pool name, and freno will periodically parse the list of enabled servers in that pool and dynamically adapt to probe it. Read more about freno and MySQL throttling Use cases freno is useful for bulk operations: massive loading/archiving tasks, schema migrations, mass updates. Such operations typically walk through thousands to millions of rows and may cause undesired effects such as MySQL replication lags. By breaking these tasks to small subtasks (e.g. 100 rows at a time), and by consulting freno before applying each such subtask, we are able to achieve the same result without ill effect to the database and to the application that uses it. freno can also be used to determine actual lag to infer validity of replicas. This can assist in mitigating write-then-read pains of master reads. See here . HTTP freno serves requests via HTTP . The most important request is the check request: "May this app write to this store?". freno appreciates HEAD requests ( GET are also accepted, with more overhead) and responds with status codes: 200 (OK): Application may write to data store 404 (Not Found): Unknown metric name. 417 (Expectation Failed): Requesting application is explicitly forbidden to write. 429 (Too Many Requests): Do not write. A normal state indicating the store's state does not meet expected threshold. 500 (Internal Server Error): Internal error. Do not write. Read more on HTTP requests & responses Clients Clients will commonly issue /check/... requests via HEAD . Clients can be expected to issue many requests per second. freno is lightweight in resources. It should be just fine to hit freno hundreds of times per second. It depends on your hardware and resources, of course. It makes sense to hit freno in the whereabouts of the granularity one is looking at. If your client is to throttle on a 1000ms replication lag, checking freno 200 times per sec may be overdoing it. However if you wish to keep your clients naive and without caching this should be fine. Read more on clients Raft freno uses raft to provide high availability. freno nodes will compete for leadership and only the leader will collect metrics and should serve clients. Read more on raft and High Availability Configuration See sample config file . Also find: General/raft configuration dissection MySQL-specific configuration dissection Deployment See deployment docs for suggestions on a recommended freno deployment setup. Resources You may find various resources for setting up freno in your environment. freno-client is our Ruby client for freno , open sourced and available as a Ruby Gem. What's in a name? "Freno" is Spanish for "brake", as in car brake . Basically we just wanted to call it "throttler" or "throttled" but both these names are in use by multiple other repositories and we went looking for something else. When we looked up the word "freno" in a dictionary, we found the following sentence: Echa el freno, magdaleno! This reminded us of the 80's and that was it. Project status This project is under active development. Contributing This repository is open to contributions . Please also see code of conduct License This project is released under the MIT LICENSE . Please note it includes 3rd party dependencies release under their own licenses; these are found under vendor . Authors Authored by GitHub Engineering