Тиринг данных в объектном хранилище

Объектное хранилище Object Storage Service поддерживает три класса хранения в зависимости от частоты обращения к данным:

  • Standard — стандартный с высоким уровнем доступа (так называемое «горячее» хранение);

  • Warm — редкий или «теплый» для информации, доступ к которой требуется несколько раз в год;

  • Cold — архивный или «холодный» для редко используемых объектов.

Чтобы уменьшить затраты на хранение, вы можете использовать правила управления жизненным циклом. Эти правила позволяют реализовать тиринг данных вниз — автоматически перемещать в класс с редким доступом (Warm) или на архивное хранение (Cold) данные, к которым больше не нужен частый доступ.

В некоторых сценариях редко используемые данные могут стать востребованными. Например, может вырасти спрос на игру, видеозапись, песню или книгу из электронной библиотеки. Такие объекты нужно перемещать в «горячий» класс хранения, чтобы обеспечить высокий уровень доступа.

В этой инструкции описано, как настроить тиринг данных вверх — автоматическое перемещение данных в «горячий» класс хранения при увеличении количества запросов к объектам.

Архитектура решения

../_images/schm__data-tiering-algorithm.svg
  1. Клиент (пользователь или приложение) отправляет GET-запрос к объекту с классом хранения Cold или Warm.

  2. Информация об обращении к целевой корзине попадает в Cloud Trace Sevice — сервис для логгирования событий.

  3. Cloud Trace Sevice формирует лог и отправляет его в корзину для хранения логов.

  4. Появление файла лога в корзине формирует уведомление в Simple Message Notification — сервисе для отправки уведомлений о событиях.

  5. Уведомление из Simple Message Notification становится триггером для запуска функции в FunctionGraph — сервисе для выполнения кода в бессерверной среде по триггеру.

  6. Функция в FunctionGraph отрабатывает и перемещает объект в целевой корзине в класс хранения Standard.

Подготовьте корзину для хранения логов в OBS

  1. На панели управления в разделе Storage откройте Object Storage Service (OBS).

  2. Перейдите к созданию корзины — нажмите Create Bucket.

  3. В поле Bucket Name введите название корзины, например «logs-for-tiering».

  4. Выберите Storage Class — класс хранения. Для анализа логов подходит класс хранения Standard или Warm.

  5. Выберите созданный ранее проект в поле Enterprise Project.

  6. Подтвердите создание — нажмите Create Now.

Создайте трекер в CTS

  1. На панели управления в разделе Management & Deployment откройте Cloud Trace Service (CTS).

  2. Убедитесь, что в качестве IAM-проекта на верхней панели выбран проект по умолчанию «ru-moscow».

  3. На вкладке Trackers перейдите к созданию трекера — нажмите Create Tracker.

  4. Задайте параметры трекера:

    • Tracker Type — укажите тип Data;

    • Tracker Name — введите название, например «obs-logs»;

    • OBS Bucket — выберите корзину с объектами, для которых вы настраиваете тиринг данных. CTS будет фиксировать обращения к объектам этой корзины и отправлять логи о таких событиях;

    • в блоке Transfer to OBS в поле OBS Bucket выберите созданную ранее корзину для хранения логов;

    • в поле Retention Period задайте время хранения логов в корзине, например 60 дней;

  5. Сохраните трекер — нажмите OK.

Настройте топик в SMN

  1. На панели управления в разделе Application откройте Simple Message Notification (SMN).

  2. В разделе Topic Management → Topics перейдите к созданию топика — нажмите Create Topic.

  3. Задайте параметры топика:

    • Topic Name — введите название топика, например «bucket-request»;

    • Enterprise Project — выберите созданный ранее проект.

  4. Сохраните топик — нажмите OK.

  5. В строке с созданным топиком нажмите More → Configure Topic Policy, чтобы задать политику работы топика.

  6. В списке Services that can publish messages to this topic отметьте сервис OBS и сохраните политику кнопкой OK.

Настройте уведомление о создании файла в корзине

  1. На панели управления в разделе Storage откройте Object Storage Service (OBS).

  2. Выберите созданную для хранения логов корзину.

  3. Нажмите Event Notification → Create, чтобы добавить уведомление.

  4. Задайте параметры уведомления:

    • Name — введите название, например «event-create-file»;

    • Events — выберите тип события ObjectCreated;

    • в выпадающем списке Select the project to which the SMN topic belongs выберите IAM-проект, в котором создан топик;

    • в выпадающем списке Select an SML topic выберите созданный ранее топик.

  5. Сохраните уведомление — нажмите OK.

Создайте агентство для FunctionGraph в IAM

  1. На панели управления в разделе Management & Deployment откройте Identity and Access Management (IAM).

  2. На странице Agencies перейдите к созданию агентства — нажмите Create Agency.

  3. Задайте параметры агентства:

    • Agency Name — введите название агентства, например «for-functiongraph»;

    • Agency Type — задайте тип Cloud Service;

    • Cloud Service — выберите FunctionGraph;

    • Validity Period — выберите Unlimited;

    • нажмите Assign Permissions и выберите политики OBS Administrator и SMN Administrator.

  4. Сохраните агентство — нажмите OK.

Создайте функцию в FunctionGraph

  1. На панели управления в разделе Computing откройте FunctionGraph.

  2. На странице Functions → Function List перейдите к созданию функции — нажмите Create Function.

  3. Задайте параметры функции:

    • Function Name — введите название, например «data-tiering»;

    • Agency — выберите созданное на предыдущем шаге агентство;

    • Enterprise Project — выберите созданный ранее проект;

      Важно

      Функция должна принадлежать тому же проекту, что и топик SMN.

    • Runtime — укажите среду выполнения кода. В нашем примере код написан на Python 3.6

    • в редактор вставьте код функции.

      Пример реализации функции тиринга на Python 3.6

      import os
      
      from com.obs.client.obs_client import ObsClient
      from obs import PutObjectHeader
      from obs import RestoreTier
      import time
      
      import json
      import gzip
      
      def handler (event, context):
          # Obtain and print an event
          print("event:" + json.dumps(event) )
      
          # Obtain and print the content of an SMN message
          message = event['record'][0]['smn']['message']
          print("message:" + message)
      
          # Parse content of an SMN message (JSON string) and convert it into a Python Dictionary
          data = json.loads(message)
      
          # Obtain and print region for event from the content of an SMN message
          event_region = data['Records'][0]['eventRegion']
          print("event_region:" + event_region)
      
          # Obtain and print name of bucket with trace files (according to tracking bucket, from CTS service) from the content of an SMN message
          bucket_name_tracker = data['Records'][0]['obs']['bucket']['name']
          print("bucket_name_tracker:" + bucket_name_tracker)
      
          # Obtain and print name of created .json.gz trace file with operation logs (according to tracking bucket, from CTS service) from the content of an SMN message
          object_key_tracker = data['Records'][0]['obs']['object']['key']
          print("object_key_tracker:" + object_key_tracker)
      
          # Obtain an Access Key
          ak = context.getAccessKey()
          # Obtain an Secret Key
          sk = context.getSecretKey()
      
          # Set up endpoint for OBS
          endpoint = "obs.ru-moscow-1.hc.sbercloud.ru"
      
          # Open connection to OBS
          conn = ObsClient(access_key_id=ak, secret_access_key=sk, server=endpoint, path_style=True, region="ru-moscow-1")
      
          # Construct the local path of the incoming file
          local_incoming_file_name = os.path.join(os.sep, "tmp", object_key_tracker)
      
          # Download the trace file with operation logs (according to tracking bucket, from CTS service) from the bucket with trace files
          resp = conn.getObject(bucket_name_tracker, object_key_tracker, local_incoming_file_name)
      
          # Decompress .json.gz trace file, read, parse, convert it into a Python Dictionary and print the operation logs from it
          with gzip.open(local_incoming_file_name, "rb") as f:
            logs_data = json.loads(f.read())
          print(json.dumps(logs_data))
          print (len(logs_data))
      
          # Obtain operation logs details for traces with GET.OBJECT tracker name (to make following operations ONLY for objects to which GET request were made)
          for i in logs_data:
              if "GET.OBJECT" in i['trace_name']:
                  resource_name = i['resource_name']
                  print("resource_name:" + resource_name)
                  # Obtain and print name of bucket with objects (tracking bucket) from operation logs details
                  backet_name_logs = resource_name.split(':')[0]
                  print("backet_name_logs:" + backet_name_logs)
                  # Obtain and print object name with objects (tracking bucket) from operation logs details
                  object_key_logs = resource_name.split(':')[1]
                  print("object_key_logs:" + object_key_logs)
      
                  # Obtain and print storage class of the object (Standard storage class value is None, Warm storage class value is STANDARD_IA, Cold storage class value is GLACIER)
                  resp = conn.getObjectMetadata(bucketName = backet_name_logs, objectKey = object_key_logs)
                  object_storageClass = resp.body.storageClass
                  print(object_storageClass)
      
                  # Change storage class to STANDARD if storage class of the tracking object is WARM (value is STANDARD_IA)
                  if object_storageClass == 'STANDARD_IA':
                      headers = PutObjectHeader()
                      headers.storageClass = 'STANDARD'
                      # Change storage class in object header to STANDARD and print the message after this operation is completed
                      resp = conn.putContent(bucketName = backet_name_logs, objectKey = object_key_logs, headers = headers)
                      print("object " + object_key_logs + " has STANDARD storage class now!")
      
                  # Change storage class to STANDARD if storage class of the tracking object is COLD (value is GLACIER)
                  if object_storageClass == 'GLACIER':
                      # Obtain and print restore status of the tracking object (Unrestored (when object is in archive and can not be downloaded) or Restored). If the tracking object is Unrestored, the value is None.
                      object_restore = resp.body.restore
                      print(object_restore)
      
                      # If the tracking object is Unrestored (in archive)
                      if object_restore is None:
                          # Restore the tracking object with the fastest restoration option - Expedited. Expedited restoration restores an object in 1 to 5 minutes.
                          resp = conn.restoreObject(bucketName = backet_name_logs, objectKey = object_key_logs, days = 1, tier = RestoreTier.EXPEDITED)
                          # Wait for 6 minutes
                          time.sleep(6 * 60)
                          headers = PutObjectHeader()
                          headers.storageClass = 'STANDARD'
                          # Change storage class in object header to STANDARD and print the message after this operation is completed
                          resp = conn.putContent(bucketName = backet_name_logs, objectKey = object_key_logs, headers = headers)
                          print("object " + object_key_logs + " has STANDARD storage class now!")
      
                      # If the tracking object is Restored
                      else:
                          headers = PutObjectHeader()
                          headers.storageClass = 'STANDARD'
                          # Change storage class in object header to STANDARD and print the message after this operation is completed
                          resp = conn.putContent(bucketName = backet_name_logs, objectKey = object_key_logs, headers = headers)
                          print("object " + object_key_logs + " has STANDARD storage class now!")
      
                  # If storage class of the tracking object is already STANDARD (value is None) print the message about it
                  if object_storageClass is None:
                      print("object " + object_key_logs + " already has STANDARD storage class")
      
          return "ok"
      
  4. Сохраните функцию — нажмите Create Now.

  5. На вкладке Code в поле Dependencies нажмите Select, чтобы прикрепить зависимость.

  6. Выберите obssdk-3.0.2 для Python и нажмите OK. Этот SDK поддерживает Python версии 2.7.8 и позднее, а также Python 3.3–3.6.

  7. На вкладке Configuration убедитесь, что в поле Agency выбрано нужное агентство.

  8. В поле Execution Timeout (s) укажите время таймаута в секундах. С учетом восстановления из класса хранения Cold необходимо задать не менее 370 секунд.

  9. На вкладке Triggers нажмите Create Trigger, чтобы создать триггер.

  10. Задайте параметры триггера:

    • Trigger Type — выберите тип Simple Message Notification (SMN);

    • Topic Name — выберите созданный ранее топик.

  11. Сохраните триггер — нажмите OK.

Теперь при GET-запросе к объектам корзины класс хранения объектов будет автоматически изменяться на Standard («горячие данные»).

Примечание

На изменение класса хранения объекта с Cold на Standard может потребоваться несколько минут.