검색
이 검색 상자를 닫습니다.

Qumulo의 엔지니어링: REST API

작성자 :

파일 시스템 구축을 처음 시작했을 때 우리는 명령줄 도구, UI 및 자동화된 테스트를 통해 파일 시스템을 제어하고 검사할 수 있기를 원했습니다. 사용 REST API 이 기능을 노출하는 것은 자연스러운 일이었고 우리가 Qumulo 내에서 이 기능을 원하면 고객도 원할 것이라는 것을 깨달았습니다. 그래서 처음부터 REST API를 공개하기로 결정했습니다.

이 게시물에서는 API의 신조, REST의 과제, 파일 시스템과 함께 API를 지속적으로 발전시키는 방법을 살펴보겠습니다.

REST API 신조

REST(Representational State Transfer)는 널리 사용되는 아키텍처 스타일로 이미 익숙하다고 가정합니다. REST를 사용하여 새 API를 정의할 때 많은 선택을 해야 합니다. 먼저 API에 어떤 종류의 기능이 들어갈지 결정해야 합니다. 컨트롤 플레인(시스템 구성 및 통계)? 데이터 평면(파일 시스템에 저장된 파일 및 메타데이터)? 기능 개발을 지원하기 위해 두 가지와 내부 전용 엔드포인트를 모두 선택했습니다. Qumulo 클러스터에서 수행할 수 있는 모든 작업은 REST API를 통해 수행할 수 있습니다.

다음으로 응답 내용을 살펴보았다. SMB 또는 NFS와 같은 파일 시스템 프로토콜을 사용하여 메타데이터를 읽을 때 파일 시스템 상태에 대한 해당 프로토콜의 해석을 얻게 되며 표현할 수 있는 범위가 제한될 수 있습니다. 반면 REST API는 정답을 반환합니다. 클라이언트는 반환된 데이터를 해석할 필요가 없으며 사용 가능한 모든 정보를 반환합니다. 파일 시스템의 기능을 확장함에 따라(집계된 메타데이터 저장과 같은) 엔드포인트를 확장하여 이러한 기능을 노출합니다.

REST API Design Rulebook에서 영감을 받아 각 엔드포인트를 다음 리소스 원형 중 하나로 분류합니다.

  • 문서: 필드와 관련 리소스에 대한 링크가 모두 있는 데이터베이스 레코드
  • 수집: 리소스 디렉토리(일반적으로 문서 리소스)
  • 제어 장치: 실행 가능한 기능(예: "메일 보내기")
  • 스토어: 클라이언트 관리 리소스 저장소(일반적으로 API에서 사용되지 않음)

URI를 구성할 때 우리는 개발자나 관리자가 끝점에 대해 스크립트를 작성하거나 cURL과 같은 도구를 사용하기 쉽게 만들고 싶었습니다. 또한 끝점의 계약이 변경되는 경우 클라이언트가 실수로 중단되지 않도록 하고 싶었습니다. 이로 인해 버전 번호와 같은 더 많은 콘텐츠를 URI에 추가하여 암시적 계약보다 명시적 계약을 선호하게 되었습니다. 예를 들어 디렉토리를 읽는 방법은 다음과 같습니다.

/ v1 /파일/ % 2F /항목/ ?한계=1000

/ v1: 끝점의 버전이 항상 먼저 옵니다.
/파일/: 액세스할 문서, 컬렉션 또는 컨트롤러입니다. 이 경우 /files/는 모음입니다.
% 2F: 파일 컬렉션에 있는 문서의 ID입니다. 이 경우 파일 시스템의 루트 디렉터리입니다.
/항목/: 지정된 파일/폴더에 대해 수행할 작업입니다.
?한계=1000: 마지막으로 작업에 대한 선택적 쿼리 매개변수입니다.

이 디자인에서 필요한 유일한 HTTP 헤더는 OAuth2 스타일 전달자 토큰에 대한 권한 부여입니다.

curl -k -X GET -H "Authorization: Bearer <token>" https://server:8000/v1/file-system</var/www/wordpress>

기존 파일 시스템 REST API를 모방하려고 시도하지 않았다는 점은 주목할 가치가 있습니다. 우리는 API가 파일 시스템의 기능에 따라 달라지고 사용자가 시스템을 최대한 제어할 수 있기를 원했습니다. 미래의 어느 시점에 S3, WebDAV 등과 통신하는 클라이언트를 지원하려는 경우 해당 프로토콜에 대한 새 포트를 추가하여 핵심 REST API와 별도로 유지합니다.

REST의 과제

대부분의 구성 엔드포인트에는 간단한 동작이 있습니다. GET</var/www/wordpress> to retrieve a document (e.g. GET /v1/users/123</var/www/wordpress>), and you use SET</var/www/wordpress> or PATCH</var/www/wordpress> to update the document. The requests take effect immediately, so that when you receive a 200 OK</var/www/wordpress> response, you know the change has been made.

그러나 REST는 상태 저장도 아니고 트랜잭션도 아니기 때문에 적절하게 고려하지 않으면 사용자 경험에 영향을 미칠 수 있습니다. 관리자가 기본 제공 UI를 사용하여 클러스터에서 파일 공유를 편집한다고 가정해 보겠습니다. UI가 파일 공유 세부 정보를 검색하는 시간과 관리자가 변경 사항을 저장하는 시간 사이에 다른 사용자 또는 프로세스가 해당 파일 공유를 변경할 수 있습니다. API에서는 기본적으로 마지막 작성자가 이기므로 관리자는 무의식적으로 이러한 변경 사항을 방해합니다. 그것은 우리가 원하는 사용자 경험이 아니므로 ETag</var/www/wordpress> and If-Match</var/www/wordpress> HTTP headers for all of our documents to prevent accidental overwrites. When the UI retrieves a document, it reads the ETag</var/www/wordpress> response header (entity tag, or essentially a hashcode) and stores that. Later, when updating that same document, the UI sends an If-Match</var/www/wordpress> request header, which tells the cluster to only perform the action if the document is the same as we expect. If the document changed, we’ll get back a 12 Precondition Failed</var/www/wordpress> response, which allows us to build a better experience for the user.

장기 실행 작업에도 특별한 고려가 필요합니다. REST API 응답 시간을 예측 가능하게 유지하기 위해 단기 실행 요청은 동기식으로, 장기 실행 요청은 비동기식으로 처리합니다. API의 모든 엔드포인트를 단기 또는 장기 실행으로 분류하여 클라이언트가 복잡성을 줄이기 위해 처리해야 하는 응답 유형을 알 수 있습니다. 모두 GET, PUT</var/www/wordpress>, and PATCH</var/www/wordpress> operations on documents and collections are short-running requests, returning 200 OK</var/www/wordpress> when successfully processed. In contrast, we always POST to a controller endpoint for long-running requests, which return 202 Accepted</var/www/wordpress> with a URI to poll for completion status. For example, when joining a cluster to Active Directory, the client invokes the controller like this:

의뢰 POST /v1/ad/join
요청 본문 {
"도메인": "ad.server.com",
"사용자": "도메인-사용자",
"비밀번호": "도메인-비밀번호",
...
}

요청이 유효하면 컨트롤러는 다음과 같이 응답합니다.

 

의뢰 POST /v1/ad/join
202 수락 {
"monitor_uri": "/v1/ad/모니터"
}

그런 다음 클라이언트는 반복적으로 발행할 수 있습니다. GET /v1/ad/monitor</var/www/wordpress> calls while waiting for the join action to succeed or fail.

REST API의 진화

REST API가 파일 시스템의 기능과 보조를 맞추기 위해 엔드포인트는 코드에서 자동으로 생성됩니다. 이는 파일 시스템, API 및 API 설명서가 항상 동기화됨을 의미합니다. 우리의 빌드 시스템은 API 클라이언트를 손상시키는 REST API 변경을 초래하는 내부 데이터 구조를 실수로 변경하는 것을 방지합니다. 그리고 API 설명서를 코드에 넣으면 코드와 함께 최신 상태를 유지할 수 있습니다.

REST API를 개발한 지 XNUMX년 만에 우리는 문제가 있음을 깨달았습니다. 다른 개발 팀이 기능을 추가함에 따라 API가 유기적으로 성장했고, 이로 인해 엔드포인트와 의심스러운 계층 간에 불일치가 발생하여 기능을 발견하기 어려웠습니다. 이 문제를 해결하기 위해 우리는 두 가지 작업을 수행했습니다. 일관성 및 검색 가능성 문제를 해결하기 위해 일련의 릴리스를 통해 새로운 API 네임스페이스로 마이그레이션했으며 API가 발전하고 일관성을 유지할 수 있도록 Qumulo 엔지니어가 따라야 할 API 로드맵을 만들었습니다. API 네임스페이스 개선의 예는 모든 실시간 분석-/v1/analytics의 관련 기능. 이전에는 이 기능이 전체 네임스페이스에 분산되어 있었고 고객이 이러한 기능을 찾을 수 없다는 소식을 들었을 때 이 부분이 개선해야 할 영역임을 알았습니다.

이제 /v1 API를 강화했으므로 브레이킹 체인지가 필요한 경우 개별 엔드포인트가 버전을 변경할 수 있습니다. (주요 변경 사항에는 요청에 새 필수 필드를 추가하거나 반환하는 데이터의 의미 체계를 변경하는 것과 같은 것들이 포함됩니다.) 이 조항이 있더라도 주요 변경 사항은 최후의 수단입니다. 기존 API 클라이언트에 영향을 주지 않으면서 응답 데이터를 보강하거나 선택적 필드를 도입하는 방법을 찾기 위해 노력하고 있습니다.

이 게시물에서는 Qumulo의 REST API의 원칙, REST로 몇 가지 문제를 해결한 방법, 제품과 함께 API를 발전시키는 접근 방식을 살펴보았습니다.

관련 게시물

위쪽으로 스크롤