Aerospike의 서열화 또는 압축 대상은?곰곰이 생각하다.

14443 단어 nosqlprotobufaerospike
Aerospike에 서열화되거나 압축된 blob을 저장하기 전에 이러한 균형을 고려해야 합니다.
데이터를 백엔드 데이터베이스에 저장하기 전에 클라이언트가 데이터를 서열화하고 압축하는 것은 흔히 볼 수 있는 모델이다.Aerospike 고객과 협력할 때 자주 이런 상황을 만났는데 보통 프로토콜 버퍼(protobuf)나 Gzip JSON 형식으로 나타난다.결국 네트워크 대역폭과 스토리지를 줄이려는 사람은 누구입니까?
단, 예를 들어 간단한 수령/출력 캐시가 아니라면, 당신은 아주 적은 수익을 위해 강력한 Aerospike 기능을 희생할 수 있습니다 - 있으면
클라이언트에서 객체를 시리얼화하고 압축하면 다음과 같은 이점이 있습니다.
  • 상호작용성: 응용 프로그램 개발자는 본 기기의 언어 구조에서 작업할 수 있고 언어와 무관한 형식으로 대상을 교환할 수 있다. 
  • 네트워크 대역폭: 압축된 객체를 가져오고 배치할 때 네트워크 대역폭이 비교적 낮습니다.
  • 스토리지: 일반적으로 압축된 객체는 디스크 스토리지를 적게 사용합니다.
  • 이것들은 모두 좋은 일이다.그러나 Aerospike는 이러한 이점을 실현하는 대체 메커니즘을 제공했다.Aerospike client libraries은 응용 프로그램 개발자가Aerospike 데이터의 본체 언어 구조를 사용할 수 있도록 하고 client policies은 네트워크에서 압축을 사용할 수 있으며 storage compression은 사용하거나 조정할 수 있다.
    또한 Aerospike는 응용 프로그램에서 어떠한 추가 작업도 하지 않고 합리적인 논리와 유연성을 증가시킬 것이다.
  • 에서 압축을 사용하면 압축된 결과가 실제로 더 크면 Aerospike는 압축된 대상을 저장하지 않습니다.
  • 압축은 CPU 의 대가입니다.응용 프로그램은 사무에 따라 네트워크의 데이터를 압축할 수 있고 저장 압축 알고리즘/레벨은 명칭 공간에 따라 설정할 수 있다.이로써 최적화는 모든 용례에서 가장 큰'원가 효율'을 얻을 수 있다.
  • 그래서 너는 이미 생각하고 있을지도 모른다. "세상에, 아마도 나는 클라이언트에서 나의 모든 대상을 서열화할 필요가 없을 것이다."그러나 진정으로 고려해야 할 균형은 상자를 열면 바로 사용할 수 있는 상황에서 Aerospike와 대등한 것을 실현하는 것이 아니라, Aerospike에 서열화와/또는 압축된 Blob을 저장할 때 무엇을 손실시킬 것인가이다.
  • Predicate Filtersqueries에서 Blob
  • 의 데이터를 scans으로 실행할 수 없습니다.
  • Bitwise Operations
  • 을 활용할 수 없음
  • 복잡한 데이터 유형(CDT) API는 ListsMaps
  • 에서 사용할 수 없습니다.
    이것들은 모두 매우 유용한 기능들이다 - 특히 CDT 업무는어리석은 get/put 캐시만 원한다는 것을 알지 않으면 놓치고 싶지 않다.
    하지만 넌 극객이야...나는 극객이다...이 점을 quick'n dirty Python으로 살펴봅시다.

    시리얼화/압축 물방울 vs Aerospike CDT 성능
    예를 들어 하나의 용례를 가정하면 그것은 날짜에 따라 모든 구매 거래를 정리하고 복합 키(예를 들어 monthly:<YYYYMM>:<Account ID>)를 사용하여 그것들을 달과 계정에 따라 구분된 기록에 저장한다.
    Python에서 각 레코드는 중첩된 목록과 사전이 있는 표준 사전으로 나타날 수 있습니다.
    'monthly:201901:00001' {
      'acct': '00001',
      'loc': 1,
      'txns': {
        '20190101': [
          {
            'txn': 1,
            'ts': 50607338,
            'sku': 5631,
            'cid': "GFOBVQPRCZVT",
            'amt': 873300,
            'qty': 23,
            'code': 'USD'
          },
          { ... }
        ]
        '20190102': [ ... ]
      }
    }
    
    txns키는 사전을 포함하는데, 이 사전의 키마다 YYMMDD 형식의 한 달 중 하루이며, 이 값은 해당 일의 업무 목록입니다.
    클라이언트를 서열화/압축하는 것과 Aerospike 내장 기능을 사용하는 장점과 단점을 강조하기 위해 두 개의 Aerospike 이름 공간을 설정하였다.
    첫 번째 명칭 공간 ns1은 압축을 사용하지 않은 파일 저장 엔진을 사용합니다.기록을 BLOB로 저장하는 데 사용됩니다. 이 BLOB는 JSON으로 서열화되었고, Python 코드에서 zlib 레벨 6 (기본값) 을 사용하여 압축됩니다.namespace 파일의 aerospike.conf 섹션은 다음과 같습니다.
    namespace ns1 {
        replication-factor 1
        memory-size 2G
    
        storage-engine device {
            file /opt/aerospike/data/ns1.dat
            filesize 100M
        }
    }
    
    두 번째 이름 공간 ns2은 ZStandard compression level 1(압축량이 가장 작고 성능이 가장 우수)의 파일 저장 엔진을 사용합니다.레코드를 Aerospike CDT로 저장하는 데 사용됩니다.namespace 파일의 aerospike.conf 섹션은 다음과 같습니다.
    namespace ns2 {
        replication-factor 1
        memory-size 2G
    
        storage-engine device {
        file /opt/aerospike/data/ns2.dat
        filesize 100M
        compression zstd
                compression-level 1
        }
    }
    
    generate-data.py이라는 파이톤 스크립트를 사용하여 상기 데이터 모델로 가상 데이터를 생성하여 두 개의 이름 공간에 불러옵니다.그것은 10개의 계좌를 위해 2년간의 역사 거래 데이터를 생성하고 계좌마다 매일 250건의 거래를 한다.generate-data.py에서 두 개의 명칭 공간에 데이터를 불러오는 부분을 살펴보자.'blob'버전은 먼저 파이톤의 대상을 JSON으로 변환한 다음,zlib을 사용하여 JSON 문자열을 압축한 다음, 기록을 ns1의 명칭 공간에 쓴다.'cdt' 버전은 파이톤 대상을 ns2 이름 공간에 그대로 기록할 뿐입니다.
    # write each record
    start = time()
    for pk, record in objects.items():
    
        if object_type == 'blob':
            record_data = {'object': zlib.compress(json.dumps(record).encode("utf-8"), zlib_level)}
    
        elif object_type == 'cdt':
            record_data = record
    
        key = (namespace, set_name, pk)
        client.put(key, record_data, 
                policy={'exists': aerospike.POLICY_EXISTS_CREATE_OR_REPLACE}
        )
    elapsed = time() - start
    
    generate-data.py은 각 Aerospike 이름 공간에 가상 객체를 로드하면 해당 이름 공간에 대한 통계를 출력합니다.
    $ python3 generate-data.py 
    Aerospike:          127.0.0.1:3000 ns1.example
    Run time:           9.354 seconds
    Object type:        blob
    Object count:       240
    Avg object size:    217.0 KiB
    Compression ratio:  -
    ---
    Aerospike:          127.0.0.1:3000 ns2.example
    Run time:           5.610 seconds
    Object type:        cdt
    Object count:       240
    Avg object size:    182.5 KiB
    Compression ratio:  0.349
    ---
    
    따라서 Aerospike 원본 CDT를 사용하고 압축 기능을 사용하면 더 작은 대상(더 좋은 저장 압축)을 생성하고 데이터를 더 빨리 불러올 수 있다는 것이 분명하다.
    그 중 일부 원인은 다음과 같다. (a) Aerospike가 데이터를 압축할 때 ZStandard compression을 사용하는 것이지 Python 코드에서 사용하는 zlib을 사용하는 것이 아니다. (b) Aerospike는 매우 빠르고 정적 형식의 컴파일러 언어(C lang)로 구축된 것이고 우리의 Python 코드는 해석기에서 실행되는 비교적 느리고 동적 유형의 언어이다.그러니까 이거 사과 아니야, 사과.
    그러나 응용 프로그램 개발의 측면에서 볼 때, 이곳의 두 가지 관건적인 요점은Aerospike 압축은 기본적으로 무료이며, 사용자가 사용하는 것은 모국어 유형이다.

    용례: 백그라운드 읽기/쓰기 스캔을 통해 데이터를 수정합니다
    클라이언트를 서열화/압축할 때 사용할 수 없는 고급 Aerospike 기능을 활용할 수 있는 가치를 설명하기 위해 데이터 교정 용례를 살펴보겠습니다.응용 프로그램에 오류가 있다고 가정하면 계정 하나(loc)의 위치(acct) 값이 정확하지 않습니다.
    클라이언트에 기록이 서열화되고 압축되면, 프로그램 코드는 네트워크를 통해 모든 기록을 프로그램 RAM으로 읽고, 이를 반서열화하고, 압축을 풀고, 수정한 다음, 네트워크를 통해 전체 기록을 다시 써야 한다.
    그러나 서버측 압축이 있는 Aerospike CDT를 사용하면 background read/write scan이 있는 predicate filter을 시작하여 Aerospike 노드에서 작업을 완전히 끝낼 수 있다.
    Python 스크립트 correct-data.py에서 설명합니다.이 스크립트는 위의 generate-data.py에서 생성한 것과 같은 데이터를 조작합니다.
    우선 술어 필터를 설정합니다. 이 필터는 계정 ID(acct)가 00007이고 현재 위치 ID(loc)가 5인 기록만 필터합니다.
    account_to_correct = '00007'
    incorrect_location = 5
    
    predicate_expressions = [
    
        # push expressions to filter by loc=5
        predexp.integer_bin('loc'),
        predexp.integer_value(incorrect_location),
        predexp.integer_equal(),
    
        # push expression to filter by acct=00007
        predexp.string_bin('acct'),
        predexp.string_value(account_to_correct),
        predexp.string_equal(),
    
        # filter by the `loc` AND `acct` expressions
        predexp.predexp_and(2)
    ]
    
    policy = {
        'predexp': predicate_expressions
    }
    
    다음에 상기 술어 표현식을 사용하여 모든 Aerospike 노드에 배경 스캔을 보내서 스캔 결과를 필터하고 모든 결과를 기록할 수 있도록 일련의 쓰기 작업을 전달합니다.이 경우 쓰기 작업에는 위치 ID(loc)를 2으로 업데이트하는 작업만 포함됩니다.
    correct_location = 2
    
    # Do a background scan, which runs server-side, to update the records that
    # match the predicate expression with the correct value for 'loc'.
    ops =  [
        operations.write('loc', correct_location)
    ]
    
    bgscan = client.scan(namespace, set_name)
    bgscan.add_ops(ops)
    scan_id = bgscan.execute_background(policy)
    print("Running background read/write scan. ID: {}".format(scan_id))
    
    # Wait for the background scan to complete.
    while True:
        response = client.job_info(scan_id, aerospike.JOB_SCAN)
        if response["status"] != aerospike.JOB_STATUS_INPROGRESS:
            break
        sleep(0.25)
    
    저것은 무엇입니까?당신은 백그라운드 읽기와 쓰기 스캔이 성능에 영향을 미칠까 봐 걱정합니까?걱정하지 마십시오. Aerospike는 background-scan-max-rps으로 초당 기록을 조절할 수 있습니다.
    Aerospike 데이터베이스 노드에 약 20만 개의 대상을 클라이언트에게 전달하는 대신 경량급 바이너리 조작을 보내서 모든 최적화 비용과 성능을 고려할 수 있습니다.네가 얼마를 절약할 수 있는지 생각해 봐라!너는 영웅이 될 거야!
  • View complete source code on Github
  • 좋은 웹페이지 즐겨찾기