O Simple Log service (SLS) oferece suporte ao Spark Streaming para consumir dados de log em tempo real. Use o Alibaba Cloud Spark SDK para consumir dados de log do SLS no modo Receiver ou no modo Direct.
Limites
O consumo com o Spark Streaming é compatível apenas com o Spark 2.x.
O Alibaba Cloud Spark SDK oferece suporte a dois modos de consumo: Receiver e Direct. Adicione a seguinte dependência do Maven ao seu projeto:
<dependency>
<groupId>com.aliyun.emr</groupId>
<artifactId>emr-logservice_2.11</artifactId>
<version>1.7.2</version>
</dependency>
Consuma dados de log no modo Receiver
No modo Receiver, um grupo de consumidores consome dados do SLS e os armazena temporariamente em um executor do Spark. Após o início de um job do Spark Streaming, o executor lê e processa os dados. O SLS retorna cada entrada de log como uma string json. O grupo de consumidores salve automaticamente os checkpoints no SLS. Para mais informações, consulte Use consumer groups to consume log data.
-
Parâmetros
Parâmetro
Tipo
Descrição
project
String
O nome do projeto no SLS.
logstore
String
O nome do logstore no SLS.
consumerGroup
String
O nome do grupo de consumidores.
endpoint
String
O endpoint da região que hospeda o projeto do SLS. Para mais informações, consulte Endpoints.
accessKeyId
String
O AccessKey ID para acesso ao SLS.
accessKeySecret
String
O AccessKey Secret para acesso ao SLS.
-
Exemplo
NotaNo modo Receiver, pode ocorrer perda de dados com as configurações padrão. Para evitar a perda de dados, ative os Write-Ahead Logs (disponíveis no Spark 1.2 e versões posteriores). Para mais informações, consulte Spark.
import org.apache.spark.storage.StorageLevel import org.apache.spark.streaming.aliyun.logservice.LoghubUtils import org.apache.spark.streaming.{ Milliseconds, StreamingContext} import org.apache.spark.SparkConf object TestLoghub { def main(args: Array[String]): Unit = { if (args.length < 7) { System.err.println( """Usage: TestLoghub <project> <logstore> <loghub group name> <endpoint> | <access key id> <access key secret> <batch interval seconds> """.stripMargin) System.exit(1) } val project = args(0) val logstore = args(1) val consumerGroup = args(2) val endpoint = args(3) val accessKeyId = args(4) val accessKeySecret = args(5) val batchInterval = Milliseconds(args(6).toInt * 1000) def functionToCreateContext(): StreamingContext = { val conf = new SparkConf().setAppName("Test Loghub") val ssc = new StreamingContext(conf, batchInterval) val loghubStream = LoghubUtils.createStream( ssc, project, logstore, consumerGroup, endpoint, accessKeyId, accessKeySecret, StorageLevel.MEMORY_AND_DISK) loghubStream.checkpoint(batchInterval * 2).foreachRDD(rdd => rdd.map(bytes => new String(bytes)).top(10).foreach(println) ) ssc.checkpoint("hdfs:///tmp/spark/streaming") // set checkpoint directory ssc } val ssc = StreamingContext.getOrCreate("hdfs:///tmp/spark/streaming", functionToCreateContext _) ssc.start() ssc.awaitTermination() } }
Consuma dados de log no modo Direct
O modo Direct não exige um grupo de consumidores. Em vez disso, ele invoca operações de api para solicitar dados diretamente do SLS. O modo Direct oferece os seguintes benefícios:
Concorrência simplificada: O número de partições do Spark corresponde ao número de shards no Logstore. Divida os shards para aumentar a concorrência das tarefas.
Maior eficiência: Não é necessário usar Write-Ahead Logs para evitar a perda de dados.
-
Semântica exactly-once: O Spark lê os dados diretamente do SLS e confirma os checkpoints apenas após a conclusão bem-sucedida da tarefa.
Se o Spark encerrar inesperadamente, o sistema poderá consumir alguns dados mais de uma vez.
O modo Direct requer um service ZooKeeper para armazenar o estado intermediário, portanto defina um diretório de checkpoint no ZooKeeper para persistir os dados intermediários. Para reconsumir os dados após reiniciar uma tarefa, exclua o diretório correspondente no ZooKeeper e altere o nome do grupo de consumidores.
-
Parâmetros
Parâmetro
Tipo
Descrição
project
String
O nome do projeto no SLS.
logstore
String
O nome do logstore no SLS.
consumerGroup
String
O nome do grupo de consumidores. Este nome serve apenas para salve os checkpoints de consumo.
endpoint
String
O endpoint da região que hospeda o projeto do SLS. Para mais informações, consulte Endpoints.
accessKeyId
String
O AccessKey ID para acesso ao SLS.
accessKeySecret
String
O AccessKey Secret para acesso ao SLS.
zkAddress
String
A URL de conexão do service ZooKeeper.
-
Limitação de taxa
O Spark Streaming processa dados em microlotes. Especifique o número de entradas de log consumidas por lote e por shard.
No SLS, o sistema armazena cada solicitação de gravação como um grupo de logs. Uma solicitação de gravação típica contém várias entradas de log em um único grupo de logs. Ao usar o rastreamento web (web tracking), cada solicitação de gravação contém apenas uma entrada de log por grupo de logs. Os parâmetros a seguir controlam a quantidade de dados consumidos em um único lote.
Parâmetro
Descrição
Padrão
spark.loghub.batchGet.step
O número máximo de grupos de logs buscados por solicitação de consumo.
100
spark.streaming.loghub.maxRatePerShard
O número máximo de entradas de log consumidas por shard e por lote.
10000
O parâmetro spark.streaming.loghub.maxRatePerShard define o limite máximo de entradas de log por shard e por lote. O SDK busca grupos de logs em incrementos de spark.loghub.batchGet.step e acumula a contagem de entradas de log. Quando a contagem atinge ou excede o valor de spark.streaming.loghub.maxRatePerShard, o SDK interrompe a busca. Como a granularidade do consumo está no nível do grupo de logs, o limite de spark.streaming.loghub.maxRatePerShard é aproximado. A contagem real por lote depende de spark.loghub.batchGet.step e do número de entradas de log em cada grupo de logs.
-
Exemplo
import com.aliyun.openservices.loghub.client.config.LogHubCursorPosition import org.apache.spark.SparkConf import org.apache.spark.streaming.{ Milliseconds, StreamingContext} import org.apache.spark.streaming.aliyun.logservice.{ CanCommitOffsets, LoghubUtils} object TestDirectLoghub { def main(args: Array[String]): Unit = { if (args.length < 7) { System.err.println( """Usage: TestDirectLoghub <project> <logstore> <loghub group name> <endpoint> | <access key id> <access key secret> <batch interval seconds> <zookeeper host:port=localhost:2181> """.stripMargin) System.exit(1) } val project = args(0) val logstore = args(1) val consumerGroup = args(2) val endpoint = args(3) val accessKeyId = args(4) val accessKeySecret = args(5) val batchInterval = Milliseconds(args(6).toInt * 1000) val zkAddress = if (args.length >= 8) args(7) else "localhost:2181" def functionToCreateContext(): StreamingContext = { val conf = new SparkConf().setAppName("Test Direct Loghub") val ssc = new StreamingContext(conf, batchInterval) val zkParas = Map("zookeeper.connect" -> zkAddress, "enable.auto.commit" -> "false") val loghubStream = LoghubUtils.createDirectStream( ssc, project, logStore, consumerGroup, accessKeyId, accessKeySecret, endpoint, zkParas, LogHubCursorPosition.END_CURSOR) loghubStream.checkpoint(batchInterval).foreachRDD(rdd => { println(s"count by key: ${rdd.map(s => { s.sorted (s.length, s) }).countByKey().size}") loghubStream.asInstanceOf[CanCommitOffsets].commitAsync() }) ssc.checkpoint("hdfs:///tmp/spark/streaming") // set checkpoint directory ssc } val ssc = StreamingContext.getOrCreate("hdfs:///tmp/spark/streaming", functionToCreateContext _) ssc.start() ssc.awaitTermination() } }