All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xiaomi.infra.galaxy.sds.examples.stream.StreamDemo Maven / Gradle / Ivy

There is a newer version: 1.3.6
Show newest version
package com.xiaomi.infra.galaxy.sds.examples.stream;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiaomi.infra.galaxy.rpc.thrift.GrantType;
import com.xiaomi.infra.galaxy.rpc.thrift.Grantee;
import com.xiaomi.infra.galaxy.sds.client.ClientFactory;
import com.xiaomi.infra.galaxy.sds.thrift.AdminService;
import com.xiaomi.infra.galaxy.sds.thrift.CommonConstants;
import com.xiaomi.infra.galaxy.sds.thrift.Credential;
import com.xiaomi.infra.galaxy.sds.thrift.Datum;
import com.xiaomi.infra.galaxy.sds.thrift.DatumUtil;
import com.xiaomi.infra.galaxy.sds.thrift.IncrementRequest;
import com.xiaomi.infra.galaxy.sds.thrift.MutationLogEntry;
import com.xiaomi.infra.galaxy.sds.thrift.PutRequest;
import com.xiaomi.infra.galaxy.sds.thrift.PutResult;
import com.xiaomi.infra.galaxy.sds.thrift.RemoveRequest;
import com.xiaomi.infra.galaxy.sds.thrift.RemoveResult;
import com.xiaomi.infra.galaxy.sds.thrift.StreamSpec;
import com.xiaomi.infra.galaxy.sds.thrift.StreamViewType;
import com.xiaomi.infra.galaxy.sds.thrift.TableInfo;
import com.xiaomi.infra.galaxy.sds.thrift.TableSchema;
import com.xiaomi.infra.galaxy.sds.thrift.TableService;
import com.xiaomi.infra.galaxy.sds.thrift.TableSpec;
import com.xiaomi.infra.galaxy.sds.thrift.UserType;
import com.xiaomi.infra.galaxy.talos.admin.TalosAdmin;
import com.xiaomi.infra.galaxy.talos.client.SimpleTopicAbnormalCallback;
import com.xiaomi.infra.galaxy.talos.client.TalosClientConfig;
import com.xiaomi.infra.galaxy.talos.client.TalosClientConfigKeys;
import com.xiaomi.infra.galaxy.talos.consumer.MessageCheckpointer;
import com.xiaomi.infra.galaxy.talos.consumer.MessageProcessor;
import com.xiaomi.infra.galaxy.talos.consumer.MessageProcessorFactory;
import com.xiaomi.infra.galaxy.talos.consumer.TalosConsumer;
import com.xiaomi.infra.galaxy.talos.consumer.TalosConsumerConfig;
import com.xiaomi.infra.galaxy.talos.thrift.CreateTopicRequest;
import com.xiaomi.infra.galaxy.talos.thrift.CreateTopicResponse;
import com.xiaomi.infra.galaxy.talos.thrift.MessageAndOffset;
import com.xiaomi.infra.galaxy.talos.thrift.Permission;
import com.xiaomi.infra.galaxy.talos.thrift.TopicAndPartition;
import com.xiaomi.infra.galaxy.talos.thrift.TopicAttribute;
import com.xiaomi.infra.galaxy.talos.thrift.TopicInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;

/**
 * Copyright 2015, Xiaomi.
 * All rights reserved.
 * Author: [email protected]
 */
public class StreamDemo {
  private static final Logger LOG = LoggerFactory.getLogger(StreamDemo.class);
  static Random rand = new Random(0);
  static final int PARTITAL_DELETE_NUMBER = 2;
  static final int ADMIN_CONN_TIMEOUT = 3000;
  static final int ADMIN_SOCKET_TIMEOUT = 50000;
  static final int TABLE_CONN_TIMEOUT = 3000;
  static final int TABLE_SOCKET_TIMEOUT = 10000;


  private Credential createSdsCredential(String secretKeyId, String secretKey, UserType userType) {
    return new Credential()
        .setSecretKeyId(secretKeyId)
        .setSecretKey(secretKey)
        .setType(userType);
  }

  private com.xiaomi.infra.galaxy.rpc.thrift.Credential createTalosCredential(String secretKeyId,
      String secretKey, com.xiaomi.infra.galaxy.rpc.thrift.UserType userType) {
   return new com.xiaomi.infra.galaxy.rpc.thrift.Credential()
       .setSecretKeyId(secretKeyId)
       .setSecretKey(secretKey)
       .setType(userType);
  }

  private AdminService.Iface createAdminClient(String endpoint, Credential credential) {
    ClientFactory clientFactory = new ClientFactory().setCredential(credential);
    return clientFactory.newAdminClient(endpoint + CommonConstants.ADMIN_SERVICE_PATH,
        ADMIN_SOCKET_TIMEOUT, ADMIN_CONN_TIMEOUT);
  }

  private TableService.Iface createTableClient(String endpoint, Credential credential) {
    ClientFactory clientFactory = new ClientFactory().setCredential(credential);
    return clientFactory.newTableClient(endpoint + CommonConstants.TABLE_SERVICE_PATH,
        TABLE_SOCKET_TIMEOUT, TABLE_CONN_TIMEOUT);
  }

  private void initSdsClient() {
    Credential credential = createSdsCredential(accountKey, accountSecret, UserType.DEV_XIAOMI);
    adminClient = createAdminClient(sdsServiceEndpoint, credential);

    credential = createSdsCredential(appKey, appSecret, UserType.APP_SECRET);
    tableClient = createTableClient(sdsServiceEndpoint, credential);
  }

  private void initTalosClient() {
    Properties pro = new Properties();
    pro.setProperty(TalosClientConfigKeys.GALAXY_TALOS_SERVICE_ENDPOINT, talosServiceEndpoint);
    TalosClientConfig talosClientConfig = new TalosClientConfig(pro);
    com.xiaomi.infra.galaxy.rpc.thrift.Credential credential = createTalosCredential(
        accountKey, accountSecret, com.xiaomi.infra.galaxy.rpc.thrift.UserType.DEV_XIAOMI);
    talosAdmin = new TalosAdmin(talosClientConfig, credential);
  }

  public StreamDemo() {
    initSdsClient();
    initTalosClient();
  }

  private PutRequest getReplayPutRequest(String tableName, Map record) {
    return new PutRequest().setTableName(tableName)
        .setRecord(record);
  }

  private IncrementRequest getReplayIncrementRequest(String tableName, Map record) {
    Map keys = new HashMap();
    Map amounts = new HashMap();
    for (Map.Entry entry : record.entrySet()) {
      if (DataProvider.rowKeyDef(enableEntityGroup).keySet()
            .contains(entry.getKey())) {
        keys.put(entry.getKey(), entry.getValue());
      } else {
        amounts.put(entry.getKey(), entry.getValue());
      }
    }
    return new IncrementRequest().setTableName(tableName)
        .setKeys(keys)
        .setAmounts(amounts);
  }

  private RemoveRequest getReplayRemoveRequest(String tableName, Map record,
      boolean rowDeleted) {
    if (rowDeleted) {
      Preconditions.checkArgument(DataProvider.rowKeyDef(enableEntityGroup).keySet()
          .equals(record.keySet()));
      return new RemoveRequest().setTableName(tableName)
          .setKeys(record);
    } else {
      List attributes = new ArrayList();
      Map keys = new HashMap();
      for (Map.Entry entry : record.entrySet()) {
        if (DataProvider.rowKeyDef(enableEntityGroup).keySet()
            .contains(entry.getKey())) {
          keys.put(entry.getKey(), entry.getValue());
        } else {
          attributes.add(entry.getKey());
        }
      }
      return new RemoveRequest().setTableName(tableName)
          .setKeys(keys)
          .setAttributes(attributes);
    }
  }

  private void replayMutationLogEntry(List messages, String destTableName)
      throws Exception {
    for (MutationLogEntry entry : messages) {
      LOG.info("Consuming mutation log entry : " + entry);
      switch (entry.getType()) {
      case PUT:
        PutRequest put = getReplayPutRequest(destTableName, entry.getRecord());
        PutResult putResult = tableClient.put(put);
        Preconditions.checkArgument(putResult.isSuccess());
        LOG.info("record " + entry.getRecord() + " is put to " + destTableName);
        break;
      case INCREMENT:
        IncrementRequest increment = getReplayIncrementRequest(destTableName, entry.getRecord());
        tableClient.increment(increment);
        LOG.info("record " + entry.getRecord() + " is increment to " + destTableName);
        break;
      case DELETE:
        RemoveRequest remove = getReplayRemoveRequest(destTableName, entry.getRecord(), entry.isRowDeleted());
        RemoveResult removeResult = tableClient.remove(remove);
        Preconditions.checkArgument(removeResult.isSuccess());
        LOG.info("record " + entry.getRecord() + " is removed from " + destTableName);
        break;
      default:
        Preconditions.checkArgument(false);
      }
    }
  }

  // callback for consumer to process messages, that is, consuming logic
  private class MutateLogProcessor implements MessageProcessor {
    @Override
    public void init(TopicAndPartition topicAndPartition, long messageOffset) {
    }

    @Override
    public void process(List messages, MessageCheckpointer messageCheckpointer) {
      try {
        if (messages.size() > 0) {
          List logEntries = new ArrayList(messages.size());
          for (MessageAndOffset entry : messages) {
            try {
              MutationLogEntry logEntry = DatumUtil.deserialize(entry.getMessage().getMessage(),
                  MutationLogEntry.class);
              logEntries.add(logEntry);
            } catch (Exception e) {
              LOG.error("Deserialize message " + entry + " got exception ", e);
              throw e;
            }
          }

          if (!logEntries.isEmpty()) {
            try {
              replayMutationLogEntry(logEntries, destTableName);
            } catch (Exception e) {
              LOG.error("Replay mutation log entries " + logEntries + " got exception ", e);
              throw e;
            }
          }
        }
      } catch (Exception e) {
        LOG.error("Process mutation log entries for topic " + topicName + " get exception ", e);
        throw new RuntimeException(e);
      }
    }

    @Override
    public void shutdown(MessageCheckpointer messageCheckpointer) {
    }
  }

  // using for thread-safe when processing different partition data
  private class MutateLogProcessorFactory implements MessageProcessorFactory {

    public MutateLogProcessorFactory() {
    }

    @Override
    public MutateLogProcessor createProcessor() {
      return new MutateLogProcessor();
    }
  }

  private TalosConsumer createTalosConsumer()
      throws Exception {
    if (!streamViewType.equals(StreamViewType.MUTATE_LOG)) {
      throw new RuntimeException("Unexpected stream view type : " + streamViewType);
    }

    Properties pro = new Properties();
    pro.setProperty(TalosClientConfigKeys.GALAXY_TALOS_SERVICE_ENDPOINT, talosServiceEndpoint);
    TalosConsumerConfig talosConsumerConfig = new TalosConsumerConfig(pro);
    com.xiaomi.infra.galaxy.rpc.thrift.Credential credential = createTalosCredential(
        appKey, appSecret, com.xiaomi.infra.galaxy.rpc.thrift.UserType.APP_SECRET);

    return new TalosConsumer(consumerGroup, talosConsumerConfig, credential,
        topicInfo.getTopicTalosResourceName(), new MutateLogProcessorFactory(), clientPrefix,
        new SimpleTopicAbnormalCallback());
  }

  private boolean shouldDo() {
    return rand.nextBoolean();
  }

  public void produceData()
      throws Exception {
    LOG.info("Begin to produce data for table " + tableName);
    for (int i = 0; i < 100; i++) {
      Map record = DataProvider.randomRecord(
          DataProvider.attributesDef(enableEntityGroup));
      Map keys = DataProvider.getRecordKeys(tableSchema, record);
      Map dataRecord = Maps.difference(record, keys).entriesOnlyOnLeft();

      // put
      PutRequest put = new PutRequest();
      put.setTableName(tableName)
          .setRecord(record);
      PutResult putResult = tableClient.put(put);
      Preconditions.checkArgument(putResult.isSuccess());

      // increment
      if (shouldDo()) {
        Map amounts = DataProvider.randomIncrementAmounts(tableSchema,
            dataRecord.keySet());
        IncrementRequest increment = new IncrementRequest();
        increment.setTableName(tableName)
            .setKeys(keys)
            .setAmounts(amounts);
        tableClient.increment(increment);
      }

      // partial delete
      if (shouldDo()) {
        List attributes = DataProvider.randomSelect(dataRecord.keySet(),
            PARTITAL_DELETE_NUMBER);
        RemoveRequest remove = new RemoveRequest();
        remove.setTableName(tableName)
            .setAttributes(attributes)
            .setKeys(keys);
        RemoveResult removeResult = tableClient.remove(remove);
        Preconditions.checkArgument(removeResult.isSuccess());
      }
    }
    LOG.info("Produce data finished for table " + tableName);
  }

  public TableSchema createSrcTable(String tableName, String topicName, StreamSpec streamSpec)
      throws Exception {
    Map streamSpecs = new HashMap();
    streamSpecs.put(topicName, streamSpec);
    TableSpec tableSpec = DataProvider.createTableSpec(appId, enableEntityGroup,
        enableEntityGroupHash, streamSpecs);

    TableInfo tableInfo = adminClient.createTable(tableName, tableSpec);
    LOG.info("Src table " + tableName + " is created");
    return tableInfo.getSpec().getSchema();
  }

  public void createDestTable() throws Exception {
    TableSpec tableSpec = DataProvider.createTableSpec(appId, enableEntityGroup,
        enableEntityGroupHash);

    adminClient.createTable(destTableName, tableSpec);
    LOG.info("Dest table " + destTableName + " is created");
  }

  private TopicInfo createTopic() throws Exception {
    CreateTopicRequest createTopicRequest = new CreateTopicRequest();
    createTopicRequest.setTopicName(topicName);

    Map aclMap = new HashMap();
    Grantee grantee = new Grantee();
    grantee.setIdentifier(appId)
        .setType(GrantType.APP_ROOT);
    aclMap.put(grantee, Permission.TOPIC_READ_AND_MESSAGE_FULL_CONTROL);
    createTopicRequest.setAclMap(aclMap);

    TopicAttribute topicAttribute = new TopicAttribute();
    topicAttribute.setPartitionNumber(topicPartitionNumber);
    createTopicRequest.setTopicAttribute(topicAttribute);
    CreateTopicResponse createTopicResponse = talosAdmin.createTopic(createTopicRequest);
    LOG.info("Topic " + topicName + " is created");
    return createTopicResponse.getTopicInfo();
  }

  private StreamSpec createStreamSpec() throws Exception {
    StreamSpec streamSpec = new StreamSpec();
    streamSpec.setViewType(streamViewType)
        .setAttributes(Lists.newArrayList(DataProvider.columnsDef().keySet()))
        .setEnableStream(true);
    LOG.info("Stream " + streamSpec + " is created");
    return streamSpec;
  }

  public void createTable() throws Exception {
    topicInfo = createTopic();
    streamSpec = createStreamSpec();
    tableSchema = createSrcTable(tableName, topicName, streamSpec);
  }

  // sds config
  private static final String sdsServiceEndpoint = "$sdsServiceEndpoint";
  private static final String tableName = "streamDemoTable";
  private static final String destTableName = "destStreamDemoTable";
  private static final boolean enableEntityGroup = true;
  private static final boolean enableEntityGroupHash = true;
  private static final StreamViewType streamViewType = StreamViewType.MUTATE_LOG;
  private static final String accountKey = "$your_accountKey";
  private static final String accountSecret = "$your_accountSecret";
  private static final String appId = "$your_appId";
  private static final String appKey = "$your_appKey";
  private static final String appSecret = "$your_appSecret";
  private static AdminService.Iface adminClient;
  private static TableService.Iface tableClient;

  private static TableSchema tableSchema;
  private static StreamSpec streamSpec;

  // talos config
  private static final String talosServiceEndpoint = "$talosServiceEndpoint";
  private static final String topicName = "streamDemoTopic";
  private static final int topicPartitionNumber = 8;
  private static final String clientPrefix = "departmentName-";
  private static final String consumerGroup = "groupName";

  private static TalosAdmin talosAdmin;
  private static TopicInfo topicInfo;

  public static void main(String[] args) throws Exception {
    StreamDemo streamDemo = new StreamDemo();

    streamDemo.createTable();
    streamDemo.createDestTable();

    streamDemo.createTalosConsumer();
    streamDemo.produceData();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy