콘텐츠로 이동

OpenAPI 사이트 간 데이터 조회

이 문서에서는 query_data를 통해 현재 워크스페이스에서 조회 권한을 부여받은 다른 사이트의 데이터를 조회하는 방법과 비동기 인터페이스가 반환하는 async_id를 올바르게 처리하는 방법을 설명합니다.

적용 인터페이스

시나리오 인터페이스 설명
동기 조회(권장) POST /api/v1/df/query_data_v1 신규 연동 시 우선 사용
비동기 조회 POST /api/v1/df/asynchronous/query_data 작업이 계속 실행 중일 때만 async_id 반환
구버전 호환 GET/POST /api/v1/df/query_data GET은 body=<URL 인코딩된 JSON> 사용, 신규 연동에는 비권장
조회 권한 대상 조회 GET /api/v1/wksp_share/granted_ws_list 대상 workspaceUUIDtargetRegion 획득
사이트 구성 조회 GET /api/v1/workspace/website/list 사이트 등록 정보 확인 용도이며 데이터 조회 권한을 의미하지 않음

External API의 POST /api/v1/df/{workspace_uuid}/query_data는 동기 진입점이며 async_id를 받지 않습니다. 내부적으로는 동일한 DQL 조회 필드를 사용하지만 인증 방식은 External API의 AK/SK 서명입니다.

요청 모델 및 제한 사항

사이트 간 조회는 여전히 현재 사이트의 OpenAPI Endpoint를 호출하며 현재 워크스페이스의 DF-API-KEY를 사용합니다. 대상 사이트를 직접 요청할 필요가 없으며 대상 사이트의 Endpoint로 현재 Endpoint를 대체해서도 안 됩니다.

queries[i]의 구조는 다음과 같습니다.

{
  "qtype": "dql",
  "query": {
    "q": "L::re(`.*`):(`message`)",
    "workspaceUUIDs": ["wksp_target"],
    "targetRegion": "region_code"
  }
}

다음 규칙을 준수해야 합니다.

  1. 비어 있지 않은 workspaceUUIDsworkspaceUUID보다 우선합니다. workspaceUUIDs가 빈 배열이거나 null이면 workspaceUUID로 폴백합니다. 두 필드를 동시에 전달하지 않는 것이 좋습니다. 둘 다 전달하지 않으면 현재 워크스페이스를 조회합니다.
  2. 사이트 간 조회 시 각 query의 query 객체 내부에 동일한 targetRegion을 명시적으로 전달해야 하며 요청 최상위에만 전달해서는 안 됩니다.
  3. 하나의 요청에 포함된 모든 queries[*]는 하나의 사이트만 가리켜야 합니다. 여러 사이트는 반드시 여러 요청으로 분리한 다음 클라이언트가 결과를 병합해야 합니다.
  4. workspaceUUIDs: ["*"] 또는 workspaceUUID: "*"는 지정된 targetRegion 내에서 현재 워크스페이스가 조회할 수 있는 모든 권한 부여 워크스페이스를 조회함을 의미합니다. 이 경우 targetRegion은 필수입니다.
  5. targetRegion은 권한을 부여한 워크스페이스가 속한 사이트의 regionCode이며 toRegionCode가 아닙니다.
  6. 동일한 요청 내의 여러 대상 워크스페이스는 반드시 동일한 targetRegion에 속해야 합니다. 대상 워크스페이스를 사이트별로 그룹화한 후 요청을 구성하는 것이 좋습니다.

시간 범위 및 페이지네이션 커서

query.timeRange의 시작 및 종료 시간은 동일한 단위(초, 밀리초, 마이크로초 또는 나노초)를 사용해야 합니다. 단위를 혼용하면 HTTP 400, ft.TimeRangeUnitMismatch가 반환되며 서버가 자동으로 수정하지 않습니다. 이 문서의 요청 예시는 밀리초를 사용하므로 실제 조회 시간 범위로 교체하십시오.

cursor_time, cursor_token 등의 페이지네이션 파라미터는 조회 시간 범위와 독립적입니다. 페이지를 넘길 때 인터페이스 규약에 따라 응답 커서를 그대로 다시 전달하고 원래 조회의 timeRange는 유지하십시오. 자릿수를 통일하기 위해 커서를 변환하지 마십시오.

대상 워크스페이스 및 targetRegion 획득

호출:

curl '<Endpoint>/api/v1/wksp_share/granted_ws_list?namespace=logging&pageIndex=1&pageSize=100' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--compressed

namespace로 데이터 유형별로 권한을 필터링할 수 있습니다. 예:

  • 로그: logging
  • 분산 추적: tracing
  • 메트릭: metric
  • RUM: rum
  • 신서틱 모니터링: dialtest

응답은 권한을 부여한 사이트별로 그룹화됩니다.

{
  "code": 200,
  "content": [
    {
      "regionCode": "region_a",
      "regionName": "站点 A",
      "data": [
        {
          "workspaceUUID": "wksp_target_a",
          "workspaceName": "目标工作空间 A",
          "regionCode": "region_a",
          "toWorkspaceUUID": "wksp_current",
          "toRegionCode": "region_current",
          "type": ["logging"],
          "indexes": ["*"]
        }
      ],
      "pageInfo": {
        "pageIndex": 1,
        "pageSize": 100,
        "totalCount": 1
      }
    }
  ],
  "success": true
}

파라미터를 구성할 때:

  • data[*].workspaceUUIDquery.workspaceUUID 또는 query.workspaceUUIDs의 값으로 사용합니다.
  • 해당 워크스페이스가 속한 그룹의 content[*].regionCode(또는 동일 데이터 항목의 regionCode)를 query.targetRegion으로 사용합니다.
  • toWorkspaceUUID는 조회 대상으로 사용하지 마십시오. 일반적으로 현재 API Key가 속한 권한 부여 대상 워크스페이스입니다.
  • toRegionCodetargetRegion으로 사용하지 마십시오. 일반적으로 현재 사이트입니다.
  • granted_ws_list는 사이트 그룹별로 독립적으로 페이지네이션되며 pageInfo.count는 현재 페이지의 수량일 뿐이므로 이를 totalCount와 직접 비교하여 페이지 번호를 무한정 증가시키면 안 됩니다.
  • 처음에는 regionCode를 전달하지 않고 pageIndex=1&pageSize=100으로 권한 부여 사이트를 확인한 다음, 조회가 필요한 각 사이트에 해당 regionCode를 명시적으로 전달하고 각각 1페이지부터 페이지를 넘깁니다.
  • 특정 사이트에서 누적 획득한 고유 권한 수가 해당 그룹의 pageInfo.totalCount에 도달하거나 pageIndex * pageSize >= totalCount가 되면 중지합니다. 페이지 데이터를 병합할 때 권한 레코드 uuid로 중복을 제거하고 (regionCode, workspaceUUID)로 대상 매핑을 검증합니다. 동일한 매핑에 충돌하는 권한이 있는 경우 권한 범위를 임의로 확장하지 마십시오.

예를 들어 region_a의 2페이지만 조회하려면:

curl '<Endpoint>/api/v1/wksp_share/granted_ws_list?namespace=logging&regionCode=region_a&pageIndex=2&pageSize=100' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--compressed

GET /api/v1/workspace/website/list가 반환하는 content[*].regionCode는 사이트 코드 후보로만 사용할 수 있습니다. 특정 사이트가 사이트 목록에 존재한다고 해서 현재 워크스페이스가 해당 사이트의 데이터 조회 권한을 획득했다는 의미는 아닙니다. 최종적으로는 granted_ws_list의 결과를 기준으로 해야 합니다.

동기 사이트 간 조회

다음 예시는 region_a 사이트의 wksp_target_a를 조회합니다.

curl '<Endpoint>/api/v1/df/query_data_v1' \
-H 'Content-Type: application/json' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--data-raw '{
  "queries": [
    {
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["wksp_target_a"],
        "targetRegion": "region_a"
      }
    }
  ]
}' \
--compressed

특정 사이트 내 모든 권한이 부여된 워크스페이스를 조회하려면:

{
  "queries": [
    {
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["*"],
        "targetRegion": "region_a"
      }
    }
  ]
}

region_aregion_b를 동시에 조회해야 하는 경우 각각 별도의 요청 두 번을 보내야 합니다.

대상 목록
  ├─ region_a: [wksp_a1, wksp_a2] -> 요청 1
  └─ region_b: [wksp_b1]          -> 요청 2
                                 클라이언트 결과 병합

동일한 queries 배열에 서로 다른 targetRegion을 혼용하지 마십시오. 그렇지 않으면 인터페이스가 ft.UnsupportMultiSiteQuery를 반환합니다.

비동기 조회 및 async_id 수명 주기

async_id는 단일 조회 작업의 핸들이며 세션 ID, 고정 클라이언트 ID 또는 페이지네이션 커서가 아닙니다. 새 조회에는 절대 이전 async_id를 포함해서는 안 됩니다.

1. 최초 제출: async_id 생략

curl '<Endpoint>/api/v1/df/asynchronous/query_data' \
-H 'Content-Type: application/json' \
-H 'DF-API-KEY: <DF-API-KEY>' \
--data-raw '{
  "queries": [
    {
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["wksp_target_a"],
        "targetRegion": "region_a"
      }
    }
  ]
}' \
--compressed

작업이 계속 실행 중인 경우 응답 예시:

{
  "code": 200,
  "content": {
    "data": [
      {
        "async_id": "async_task_001",
        "is_running": true
      }
    ]
  },
  "success": true,
  "traceId": "TRACE-XXXX"
}

2. 폴링: 실행 중인 작업 ID만 다시 전달

동일한 결과 항목이 다음 조건을 모두 충족할 때만 폴링합니다.

content.data[i].is_running === true
그리고
content.data[i].async_id 비어 있지 않음

ID를 동일한 배열 인덱스의 queries[i].async_id에 다시 넣고 qtype, query.q, 시간 범위, 대상 워크스페이스 및 targetRegion은 변경하지 않은 채 유지합니다.

{
  "queries": [
    {
      "async_id": "async_task_001",
      "qtype": "dql",
      "query": {
        "q": "L::re(`.*`):(`message`)",
        "timeRange": [1772516130000, 1772519730000],
        "limit": 100,
        "workspaceUUIDs": ["wksp_target_a"],
        "targetRegion": "region_a"
      }
    }
  ]
}

증분 백오프를 사용하고 전체 타임아웃을 설정하는 것이 좋습니다. 예를 들어 먼저 1초를 기다린 후 2초, 4초로 점차 늘리는 방식입니다. 간격 없이 연속으로 요청하지 마십시오.

3. 종료: async_id 포함 중단

content.data[i].is_runningfalse이면 해당 작업은 이미 종료된 것입니다. 호출자는 최종 데이터를 읽고 즉시 폴링을 중지해야 합니다. 응답 객체에 async_id 필드가 여전히 포함되어 있는지 여부와 관계없이 다음 새 조회에서는 반드시 이전 ID를 생략해야 합니다.

다음과 같은 동작은 잘못되었습니다.

  • 이전 작업의 async_id를 모든 후속 요청에 고정으로 포함하는 경우.
  • DQL, 시간 범위, 워크스페이스 또는 targetRegion을 수정한 후에도 이전 ID를 계속 재사용하는 경우.
  • content.data[0].async_idqueries[1]에 넣는 경우.
  • async_idsearch_after, cursor_time 또는 cursor_token을 대신하여 페이지를 넘기는 경우.

is_running=true인데 async_id가 비어 있는 경우 로컬에 저장된 이전 ID를 다시 채우지 마십시오. 응답의 traceId를 기록하고 제한된 재시도 정책에 따라 해당 논리 조회를 다시 요청하십시오. 이 현상이 지속되면 기술 지원에 문의하십시오.

배치 비동기 조회에서 content.data[i]queries[i]는 배열 인덱스로 서로 대응됩니다. ID와 조회 항목이 잘못 매칭될 위험을 줄이기 위해 비동기 호출 시 매번 하나의 query만 제출하는 것을 권장합니다.

페이지네이션과 비동기 작업의 차이

비동기 작업이 완료된 후에도 페이지네이션은 최종 조회 결과가 반환한 페이지네이션 필드를 사용합니다.

시나리오 다음 요청 파라미터
로그 심층 페이지네이션 응답의 search_after를 다음 조회의 query.search_after에 전달
시간 분할 조회 최초에 query.cursor_time을 종료 시간으로 설정하고 이후에는 응답의 next_cursor_time 전달
동일 타임스탬프 안전 페이지 전환 응답의 next_cursor_token을 다음 조회의 query.cursor_token에 전달

페이지 전환은 새로운 조회 요청이므로 완료된 작업의 async_id를 계속 포함해서는 안 됩니다. 페이지 전환 요청이 다시 비동기 작업으로 전환되더라도 'async_id 생략'부터 새로운 수명 주기를 시작합니다.

클라이언트 병합 권장 사항

서버는 한 번의 query_data 요청에서 여러 사이트를 걸친 조회를 지원하지 않습니다. 클라이언트에서 병합할 때 다음 사항을 권장합니다.

  1. 먼저 targetRegion별로 대상 워크스페이스를 그룹화합니다.
  2. 각 사이트별로 요청, 페이지네이션, 비동기 작업 처리를 각각 독립적으로 수행합니다.
  3. 각 배치 결과에 sourceRegion, queriedWorkspaceUUIDs 등의 클라이언트 메타데이터를 추가합니다. 다중 워크스페이스 조회는 모든 레코드에 신뢰할 수 있는 출처 워크스페이스가 포함된다는 것을 보장하지 않으므로 전체 배치 결과를 특정 sourceWorkspaceUUID로 표시할 수 없습니다. 한 번에 하나의 워크스페이스만 조회하는 경우에만 이렇게 표시할 수 있습니다. 레코드 수준의 출처가 필요한 경우 워크스페이스별로 조회하거나 DQL이 업무상 확인된 신뢰할 수 있는 출처 차원을 반환하도록 해야 합니다.
  4. 로그 유형 결과는 time, date_ns 및 안정적인 고유 식별자를 기준으로 정렬하고 중복을 제거합니다. 메트릭 결과는 시간 입도, 집계 함수, 태그 집합이 일치하는지 먼저 확인한 후 병합해야 합니다.
  5. 특정 사이트가 실패하면 다른 사이트의 성공 결과를 보존하고 사이트별 오류 상세를 반환해야 합니다. 부분 성공을 전체 성공으로 포장하지 마십시오.

일반적인 오류

오류 코드 / 현상 원인 처리 방법
ft.TimeRangeUnitMismatch timeRange 시작/종료 시간에 서로 다른 단위를 혼용함 동일한 단위로 시간 범위를 다시 구성하고 페이지네이션 커서는 응답 그대로 다시 전달
ft.UnsupportMultiSiteQuery 하나의 요청에 여러 대상 사이트를 혼합함 targetRegion별로 요청 분리
ft.workspaceUnauthorized 대상 워크스페이스가 현재 워크스페이스에 권한이 부여되지 않음 granted_ws_list를 다시 조회하여 권한 상태와 UUID 확인
ft.NotFoundWorkspaceAuthorizationCfg 대상 사이트에 사용 가능한 권한 구성이 없음. *를 사용했지만 사이트에 권한이 없는 경우에 흔함 targetRegion 확인 및 대상 사이트에 유효한 권한 존재 여부 확인
ft.NoInitOtherNodeCfg 외부 조직 사이트 간 권한은 존재하지만 대상 사이트의 Front Endpoint/노드 구성이 없음 무작정 재시도하지 말고 사이트 관리자에게 문의하여 대상 노드 구성을 확인하고 보완
ft.InvalidWorkspace 현재 사이트의 대상 워크스페이스가 유효하지 않거나 비활성화됨 워크스페이스 목록을 새로 고치고 상태 확인
계속 이전 결과를 폴링함 클라이언트가 완료된 작업의 async_id를 장기간 재사용함 is_running=false 이후 로컬 ID를 삭제하고 새 조회에는 async_id를 전달하지 않음
사이트는 존재하지만 데이터를 조회할 수 없음 workspace/website/list만 확인하고 권한을 확인하지 않음 wksp_share/granted_ws_list를 기준으로 판단
DQLDataAccessScopeRestricted warning 데이터 액세스 규칙이 일부 인덱스만 허용하거나 관련 인덱스를 허용하지 않음 warnings[].details[].metadata.restriction 및 데이터 액세스 규칙 확인

출시 전 점검 목록

  • 현재 워크스페이스의 DF-API-KEY로 현재 사이트의 OpenAPI Endpoint를 요청합니다.
  • granted_ws_list에서 대상 workspaceUUID와 동일 그룹의 regionCode를 획득합니다.
  • 모든 사이트 간 query에 동일한 targetRegion을 명시적으로 전달합니다.
  • 다중 사이트 대상을 targetRegion별로 여러 요청으로 분리했습니다.
  • 새 비동기 조회에는 async_id를 전달하지 않습니다.
  • is_running=true이고 ID가 비어 있지 않은 경우에만 폴링하고 배열 인덱스로 작업을 바인딩합니다.
  • is_running=false 이후 작업 ID를 삭제합니다. 페이지네이션은 새로운 비동기 수명 주기에서 시작합니다.
  • 폴링 백오프, 전체 타임아웃, 페이지네이션 상한 및 사이트별 오류 처리를 설정합니다.
  • 결과 병합 시 출처 사이트/워크스페이스를 유지하고 업무 기본 키로 중복을 제거합니다.

문서 평가

이 페이지가 도움이 되었나요?