1. 소개

이 기사에서는 Fauna 분산 데이터베이스를 살펴보겠습니다 . 애플리케이션에 어떤 기능을 제공하는지, 무엇을 할 수 있는지, 어떻게 상호작용하는지 살펴보겠습니다.

2. 동물군이란?

Fauna는 다중 프로토콜, 다중 모델, 다중 테넌트, 분산형 트랜잭션 DBaaS(Database as a Service) 오퍼링입니다. 이것은 복잡하게 들리므로 조금 분해해 보겠습니다.

2.1. 서비스로서의 데이터베이스

"Database as a Service"는 데이터베이스가 클라우드 Provider에 의해 호스팅됨을 의미합니다. 클라우드 Provider는 모든 인프라와 유지 관리를 담당하므로 도메인별 세부 정보(컬렉션, 인덱스, 쿼리 , 등. 이렇게 하면 시스템의 기능을 계속 활용하면서 이러한 시스템을 관리하는 복잡성을 많이 제거할 수 있습니다.

2.2. 분산 트랜잭션 데이터베이스

분산된다는 것은 데이터베이스가 여러 서버에서 실행되고 있음을 의미합니다. 이를 통해 보다 효율적이고 동시에 내결함성을 높일 수 있습니다. 하나의 서버에 장애가 발생해도 전체 데이터베이스는 계속해서 올바르게 작동할 수 있습니다.

트랜잭션이라는 것은 데이터베이스가 데이터의 유효성에 대해 강력한 보증을 제공한다는 것을 의미합니다. 단일 트랜잭션 내에서 수행되는 데이터 업데이트는 데이터를 부분적인 상태로 남겨둘 위험 없이 전체적으로 성공하거나 실패합니다.

추가 조치로 Fauna는 여러 분산 노드에서 여러 트랜잭션을 재생한 결과가 항상 올바른지 확인하는 격리 수준을 제공합니다. 이것은 분산 데이터베이스에 대한 중요한 고려 사항입니다. 그렇지 않으면 다른 트랜잭션이 다른 노드에서 다르게 재생되어 다른 결과로 끝날 수 있습니다.

예를 들어 동일한 레코드에 적용되는 다음 트랜잭션을 고려해 보겠습니다.

  1. 값을 "15"로 설정
  2. 값을 "3"씩 증가

표시된 순서대로 재생되면 최종 결과는 "18"이 됩니다. 그러나 반대 순서로 재생되면 최종 결과는 "15"가 됩니다. 이는 동일한 시스템의 다른 노드에서 결과가 다른 경우 훨씬 더 혼란스럽습니다. 이는 데이터가 노드 간에 일관성이 없음을 의미하기 때문입니다.

2.3. 다중 모델 데이터베이스

다중 모델 데이터베이스는 동일한 데이터베이스 엔진 내에서 동일한 연결에서 액세스할 수 있는 다양한 방식으로 다양한 유형의 데이터를 모델링할 수 있음을 의미합니다.

내부적으로 Fauna는 문서 데이터베이스입니다. 즉, 각 레코드를 구조화된 문서로 저장하고 랜덤의 모양을 JSON으로 표시합니다. 이를 통해 Fauna는 키-값 저장소 역할을 할 수 있습니다. 문서에는 단순히 하나의 필드, 값만 있습니다. 그러나 중첩 필드, 배열 등을 사용하여 보다 복잡한 문서를 저장할 수도 있습니다.

// Key-Value document
{
  "value": "Baeldung"
}

// Tabular document
{
  "name": "Baeldung",
  "url": "https://www.baeldung.com/"
}

// Structured document
{
  "name": "Baeldung",
  "sites": [
    {
      "id": "cs",
      "name": "Computer Science",
      "url": "https://www.baeldung.com/cs"
    },
    {
      "id": "linux",
      "name": "Linux",
      "url": "https://www.baeldung.com/linux"
    },
    {
      "id": "scala",
      "name": "Scala",
      "url": "https://www.baeldung.com/scala"
    },
    {
      "id": "kotlin",
      "name": "Kotlin",
      "url": "https://www.baeldung.com/kotlin"
    },
  ]
}

또한 관계형 데이터베이스에서 흔히 볼 수 있는 몇 가지 기능에 액세스할 수 있습니다. 특히 문서에 인덱스를 생성하여 쿼리를 보다 효율적으로 만들고, 여러 컬렉션에 제약 조건을 적용하여 데이터의 일관성을 유지하고, 한 번에 여러 컬렉션에 걸쳐 쿼리를 수행할 수 있습니다.

Fauna의 쿼리 엔진은 또한 그래프 쿼리를 지원하므로 여러 컬렉션에 걸친 복잡한 데이터 구조를 구축하고 단일 데이터 그래프인 것처럼 모두 액세스할 수 있습니다.

마지막으로 Fauna에는 수명의 어느 시점에서든 데이터베이스와 상호 작용할 수 있는 시간 모델링 기능이 있습니다. 즉, 시간이 지남에 따라 레코드에 발생한 모든 변경 사항을 볼 수 있을 뿐만 아니라 지정된 시점의 데이터에 직접 액세스할 수 있습니다.

2.4. 다중 테넌트 데이터베이스

다중 테넌트 데이터베이스 서버는 서로 다른 사용자가 사용하는 서로 다른 여러 데이터베이스를 지원함을 의미합니다. 이것은 하나의 서버가 많은 다른 고객을 지원할 수 있음을 의미하기 때문에 클라우드 호스팅에 사용되는 데이터베이스 엔진에서 매우 일반적입니다.

Fauna는 이것을 약간 다른 방향으로 받아들입니다. 설치된 단일 데이터베이스 엔진 내에서 서로 다른 고객을 나타내는 서로 다른 테넌트 대신 Fauna는 테넌트를 사용하여 단일 고객에 대한 서로 다른 데이터 하위 집합을 나타냅니다.

자체적으로 다른 데이터베이스의 자식인 데이터베이스를 생성할 수 있습니다. 그런 다음 이러한 하위 데이터베이스에 액세스하기 위한 자격 증명을 만들 수 있습니다. 그러나 Fauna가 다른 점은 우리가 연결된 하위 데이터베이스의 데이터에 대해 읽기 전용 쿼리를 수행할 수 있다는 것입니다. 그러나 상위 또는 형제 데이터베이스의 데이터에 액세스할 수 없습니다.

이를 통해 동일한 상위 데이터베이스 내에서 다른 서비스에 대한 하위 데이터베이스를 생성한 다음 관리자 사용자가 한 번에 모든 데이터를 쿼리하도록 할 수 있습니다. 이는 분석 목적에 편리할 수 있습니다.

2.5. 다중 프로토콜 데이터베이스

이는 동일한 데이터에 액세스할 수 있는 여러 가지 방법이 있음을 의미합니다.

데이터에 액세스하는 표준 방법은 제공된 드라이버 중 하나를 통해 FQL(Fauna Query Language)을 사용하는 것입니다. 이를 통해 데이터베이스 엔진의 모든 기능에 액세스할 수 있으므로 필요한 방식으로 모든 데이터에 액세스할 수 있습니다.

또는 Fauna는 우리가 사용할 수 있는 GraphQL 엔드포인트도 노출합니다. 이것의 장점은 언어 전용 드라이버에 의존하지 않고 프로그래밍 언어에 관계없이 모든 응용 프로그램에서 사용할 수 있다는 것입니다. 그러나 이 인터페이스를 통해 모든 기능을 사용할 수 있는 것은 아닙니다. 특히 데이터의 형태를 미리 설명하는 GraphQL 스키마를 생성해야 합니다. 즉, 동일한 컬렉션에서 형태가 다른 여러 레코드를 가질 수 없습니다.

3. 동물 데이터베이스 만들기

이제 Fauna가 우리를 위해 무엇을 할 수 있는지 알았으므로 사용할 데이터베이스를 실제로 만들어 봅시다.

아직 계정이 없다면 계정을 만들어야 합니다 .

로그인한 후 대시보드에서 "데이터베이스 만들기" 링크를 클릭하기만 하면 됩니다.

동물군 생성 DB

그러면 데이터베이스의 이름과 지역에 대한 창이 열립니다. 또한 시스템에 익숙해지는 데 도움이 되도록 몇 가지 예제 데이터로 데이터베이스를 미리 채우는 옵션도 있습니다.

동물 군 db 지역

이 화면에서 "Region Group" 선택은 무료 한도를 초과하는 항목에 대해 지불해야 하는 금액과 외부에서 데이터베이스에 연결하는 데 사용해야 하는 Endpoints 모두에 대해 중요합니다.

이 작업을 완료하면 필요에 따라 사용할 수 있는 전체 데이터베이스가 확보됩니다. 데모 데이터를 선택한 경우 일부 채워진 컬렉션, 인덱스, 사용자 지정 함수 및 GraphQL 스키마가 함께 제공됩니다. 그렇지 않은 경우 데이터베이스가 완전히 비어 있고 원하는 구조를 만들 준비가 된 것입니다.

동물군 DB 구조

마지막으로 외부에서 데이터베이스에 접속하기 위해서는 인증키가 필요합니다. 사이드바의 Security 탭에서 만들 수 있습니다.

동물군 인증 키

새 키를 만들 때 Security상의 이유로 화면을 나간 후에 다시 가져올 수 있는 방법이 없으므로 복사해야 합니다.

4. 동물과의 상호 작용

이제 데이터베이스가 있으므로 작업을 시작할 수 있습니다.

Fauna는 외부에서 데이터베이스의 데이터를 읽고 쓰는 두 가지 방법인 FQL 드라이버와 GraphQL API를 제공합니다. 또한 웹 UI 내에서 랜덤의 명령을 실행할 수 있는 Fauna Shell에 액세스할 수 있습니다.

4.1. 동물 껍질

Fauna Shell을 사용하면 웹 UI 내에서 모든 명령을 실행할 수 있습니다. 구성된 키를 사용하여 이 작업을 수행할 수 있습니다. 이 작업은 해당 키를 사용하여 외부에서 연결하는 것과 정확히 동일하게 작동하거나 특정 특수 관리자 연결로 수행할 수 있습니다.

동물군 껍질

이를 통해 데이터를 탐색하고 매우 마찰이 적은 방식으로 애플리케이션에서 사용하려는 쿼리를 테스트할 수 있습니다.

4.2. FQL과 연결

대신 애플리케이션을 Fauna에 연결하고 FQL을 사용하려면 Java 및 Scala용 드라이버를 포함하여 제공된 드라이버 중 하나를 사용해야 합니다 .

Java 드라이버를 사용하려면 Java 11 이상에서 실행해야 합니다.

가장 먼저 해야 할 일은 의존성을 추가하는 것입니다. Maven을 사용하는 경우 pom.xml 파일에 추가하기만 하면 됩니다.

<dependency>
    <groupId>com.faunadb</groupId>
    <artifactId>faunadb-java</artifactId>
    <version>4.2.0</version>
    <scope>compile</scope>
</dependency>

그런 다음 데이터베이스와 통신하는 데 사용할 수 있는 클라이언트 연결을 만들어야 합니다.

FaunaClient client = FaunaClient.builder()
    .withEndpoint("https://db.us.fauna.com/")
    .withSecret("put-your-authorization-key-here")
    .build();

데이터베이스를 생성할 때 선택한 리전 그룹에 따라 달라지는 데이터베이스 엔드포인트와 이전에 생성한 비밀 키에 올바른 값을 제공해야 합니다.

이 클라이언트는 연결 풀 역할을 하여 다른 쿼리에 필요한 경우 데이터베이스에 대한 새 연결을 엽니다. 즉, 응용 프로그램을 시작할 때 한 번 생성하고 필요한 만큼 재사용할 수 있습니다.

다른 비밀과 연결해야 하는 경우 다른 클라이언트가 필요합니다. 예를 들어 동일한 부모 데이터베이스 내에서 여러 다른 자식 데이터베이스와 상호 작용하려는 경우입니다.

이제 클라이언트가 있으므로 이를 사용하여 데이터베이스에 쿼리를 보낼 수 있습니다.

client.query(
    language.Get(language.Ref(language.Collection("customers"), 101))
).get();

4.3. GraphQL과 연결

Fauna는 데이터베이스와 상호 작용하기 위한 완전한 GraphQL API를 제공합니다. 이를 통해 특별한 드라이버 없이 HTTP 클라이언트만 있으면 데이터베이스를 사용할 수 있습니다.

GraphQL 지원을 사용하려면 먼저 GraphQL 스키마를 생성해야 합니다. 이것은 스키마 자체와 컬렉션, 인덱스 및 함수와 같은 기존 Fauna 데이터베이스 구조에 매핑하는 방법을 정의합니다. 완료되면 모든 GraphQL 인식 클라이언트 또는 RestTemplate 과 같은 HTTP 클라이언트를 사용하여 데이터베이스를 호출할 수 있습니다.

이렇게 하면 데이터베이스의 데이터와만 상호 작용할 수 있습니다. 새 컬렉션 또는 인덱스 만들기와 같은 관리 명령을 사용하려면 FQL 명령이나 웹 관리 UI가 필요합니다.

GraphQL을 통해 Fauna에 연결하려면 올바른 URL(미국 지역의 경우 https://graphql.us.fauna.com/graphql)을 사용하고 Authorization 헤더 내에서 전달자 토큰으로 인증 키를 제공해야 합니다. 이 시점에서 URL에 대한 POST 요청을 만들고 본문에 쿼리 또는 변형을 제공하고 선택적으로 함께 사용할 변수를 제공하여 일반적인 GraphQL 엔드포인트로 사용할 수 있습니다.

5. Spring의 동식물 활용

이제 Fauna가 무엇이고 어떻게 사용하는지 이해했으므로 이를 Spring 애플리케이션에 통합하는 방법을 볼 수 있습니다.

Fauna에는 기본 Spring 드라이버가 없습니다. 대신, 일반 Java 드라이버를 애플리케이션 내에서 사용할 Spring 빈으로 구성할 것입니다.

5.1. 동물 구성

Fauna를 사용하려면 몇 가지 구성이 필요합니다. 특히 우리는 Fauna 데이터베이스가 있는 지역을 알아야 합니다. 이 지역에서 적절한 URL을 파생할 수 있고 데이터베이스에 연결하는 데 사용할 수 있는 비밀을 알아야 합니다.

이를 위해, 우리는 우리의 application.properties 파일 또는 지원되는 다른 Spring 구성 방법 에 동물상.지역동물상.비밀 에 대한 속성을 추가할 것입니다 .

fauna.region=us
fauna.secret=FaunaSecretHere

여기서는 URL 대신 동물군을 정의하고 있습니다. 이를 통해 동일한 설정에서 FQL과 GraphQL 모두에 대한 URL을 올바르게 파생할 수 있습니다. 이렇게 하면 두 URL을 다르게 구성할 수 있는 위험을 피할 수 있습니다.

5.2. FQL 클라이언트

애플리케이션에서 FQL을 사용하려는 경우 Spring 컨텍스트에 FaunaClient 빈을 추가할 수 있습니다. 여기에는 적절한 속성을 사용하고 FaunaClient 개체를 구성하는 Spring 구성 개체를 만드는 작업이 포함됩니다.

@Configuration
class FaunaClientConfiguration {
    @Value("https://db.${fauna.region}.fauna.com/")
    private String faunaUrl;

    @Value("${fauna.secret}")
    private String faunaSecret;

    @Bean
    FaunaClient getFaunaClient() throws MalformedURLException {
        return FaunaClient.builder()
            .withEndpoint(faunaUrl)
            .withSecret(faunaSecret)
            .build();
    }
}

이렇게 하면 JDBC 데이터베이스에 액세스하기 위해 JdbcTemplate을 사용하는 것과 같은 방식으로 애플리케이션의 어디에서나 직접 FaunaClient를 사용할 수 있습니다 . 또한 원하는 경우 도메인별 용어로 작업하기 위해 이것을 상위 수준 개체로 래핑할 수 있는 기회가 있습니다.

5.3. GraphQL 클라이언트

GraphQL을 사용하여 Fauna에 액세스할 계획이라면 조금 더 많은 작업이 필요합니다. GraphQL API를 호출하기 위한 표준 클라이언트는 없습니다. 대신 Spring RestTemplate을 사용하여 GraphQL Endpoints에 대한 표준 HTTP 요청을 만듭니다. 최신 WebClient는 WebFlux 기반 애플리케이션을 구축하는 경우에도 동일하게 잘 작동합니다.

이를 달성하기 위해 RestTemplate을 래핑 하고 Fauna에 적절한 HTTP 호출을 할 수 있는 클래스를 작성합니다 .

@Component
public class GraphqlClient {
    @Value("https://graphql.${fauna.region}.fauna.com/graphql")
    private String faunaUrl;

    @Value("${fauna.secret}")
    private String faunaSecret;

    private RestTemplate restTemplate = new RestTemplate();

    public <T> T query(String query, Class<T> cls) {
        return query(query, Collections.emptyMap(), cls);
    }

    public <T, V> T query(String query, V variables, Class<T> cls) {
        var body = Map.of("query", query, "variables", variables);

        var request = RequestEntity.post(faunaUrl)
            .header("Authorization", "Bearer " + faunaSecret)
            .body(body);
        var response = restTemplate.exchange(request, cls);

        return response.getBody();
    }
}

이 클라이언트를 사용하면 애플리케이션의 다른 구성 요소에서 Fauna에 대한 GraphQL 호출을 수행할 수 있습니다. 두 가지 방법이 있습니다. 하나는 GraphQL 쿼리 문자열을 취하는 것이고 다른 하나는 이와 함께 사용할 몇 가지 변수를 추가로 취하는 것입니다.

또한 둘 다 쿼리 결과를 역직렬화할 유형을 사용합니다. 이것을 사용하면 Fauna와 대화하는 모든 세부 사항을 처리할 수 있으므로 대신 응용 프로그램 요구 사항에 집중할 수 있습니다.

6. 요약

이 기사에서는 Fauna 데이터베이스에 대한 간략한 소개를 통해 다음 프로젝트에서 매우 매력적인 선택이 될 수 있는 몇 가지 기능을 살펴보고 애플리케이션에서 어떻게 상호 작용할 수 있는지 살펴보았습니다 .

다음 프로젝트에서 여기서 언급한 기능 중 일부를 탐색해 보시지 않겠습니까?