GeoMesa-Kafka

GeoMesa Kafka

GeoMesa 2.3.0和2.3.1支持kafka 0.9之后的版本,但是对于kafka1.0之前的版本有些特性不支持

GeoMesa 2.2.X支持的kafka版本相同。

一、GeoMesa Kafka安装

1、直接从github上下载最新版本(2.3.1)进行安装。

github地址:<https://github.com/locationtech/geomesa/releases>

# download and unpackage the most recent distribution:
$ wget "https://github.com/locationtech/geomesa/releases/download/geomesa_2.11-$VERSION/geomesa-kafka_2.11-$VERSION-bin.tar.gz"
$ tar xzvf geomesa-kafka_2.11-$VERSION-bin.tar.gz
$ cd geomesa-kafka_2.11-$VERSION
$ ls
bin/  conf/  dist/  docs/  examples/  lib/  LICENSE.txt

2、通过maven/sbt (具体安装方法去看官网)。

3、通过命令行安装

命令行工具位于 geomesa-kafka_2.11-$VERSION/bin/

可以在geomesa-kafka_2.11-$VERSION/bin/geomesa-env.sh 中设置环境变量和类路径

可以在geomesa-kafka_2.11-$VERSION 目录下执行bin/geomesa-kafka configure 命令安装命令行:

### in geomesa-kafka_2.11-$VERSION:
$ bin/geomesa-kafka configure
Using GEOMESA_KAFKA_HOME as set: /path/to/geomesa-kafka_2.11-$VERSION
Is this intentional? Y\n y
Current value is /path/to/geomesa-kafka_2.11-$VERSION/lib.

Is this intentional? Y\n y

To persist the configuration please update your bashrc file to include:
export GEOMESA_KAFKA_HOME=/path/to/geomesa-kafka_2.11-$VERSION
export PATH=${GEOMESA_KAFKA_HOME}/bin:$PATH

geomesa-kafka 会读取 $KAKFA_HOME 和$ZOOKEEPER_HOME 来加载所需要的jar包。或者执行bin目录中的install-kafka.sh来进行jar包拷贝。

测试是否安装成功:

$ geomesa-kafka
Usage: geomesa-kafka [command] [command options]
  Commands:
    ...

二、GeoMesa Kafka Data Store的使用

1、创建 Data Store

要想创建Kafka DataStore,需要制定两个参数:

  • kafka的连接参数:kafka.brokers
  • zookeeper的连接参数:kafka.zookeepers
  • 可选参数:kafka.zk.path (指定在zookeeper中的存储路径,如果没有指定,则使用默认路径)
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;

Map<String, Serializable> parameters = new HashMap<>();
parameters.put("kafka.zookeepers", "localhost:2181");
parameters.put("kafka.brokers", "localhost:9092");
DataStore dataStore = DataStoreFinder.getDataStore(parameters);

2、Kafka Data Store 参数

Kafka Data Store 的数据完全存储在内存中。

具体参数(*号为必须)

ParameterTypeDescription
kafka.brokers *StringKafka brokers地址(可以使多个) e.g. “localhost:9092”
kafka.zookeepers *StringKafka zookeepers地址(可以使多个), e.g “localhost:2181”
kafka.zk.pathStringZookeeper 路径,可以命名feature types
kafka.producer.configString通过properties文件配置kafka生产者, 详情请看 Producer Configs
kafka.producer.clearBooleantrue时,可以忽略在kafka启动之前主题中的所有消息
kafka.consumer.configString通过properties文件配置kafka消费者, 详情请看 New Consumer Configs
kafka.consumer.read-backString在启动时,读取在这个时间框架内编写的消息。使用“Inf”读取所有消息。如果启用此功能,在处理所有现有消息之前,将无法查询功能。但是,功能监听器仍然会像正常情况一样被调用。 详情请看 Initial Load (Replay)
kafka.consumer.countInteger每个 feature type 的消费者的个数,设置为0时禁用消费者 (只能生产)
kafka.consumer.start-on-demandBooleanStart consuming a topic only when that feature type is first requested. This can reduce load if some layers are never queried。当feature type第一次被请求时才去消费主题。 如果某些层永远不会被查询,可以减少负载 。
kafka.topic.partitionsIntegerkafka主题中的分区数
kafka.topic.replicationInteger对kafka主题进行重新分区
kafka.serialization.typeStringkafka内消息的存储格式,必须为kryo or avro
kafka.cache.expiryString设置内存中数据的过期时间, e.g. “10 minutes”. 详情请看 Feature Expiration
kafka.cache.event-timeString根据feature确定过期时间而不是消息时间, 详情请看 Feature Event Time
kafka.cache.event-time.orderingBoolean根据feature时间而不是message时间对feature进行排序。详情请看 Feature Event Time
kafka.index.cqengineString为内存中的feature使用基于cqengine的属性索引. 详情请看 CQEngine Indexing
kafka.index.resolution.xInteger设置x维空间索引的桶的个数。默认为360. 详情请看 Spatial Index Resolution
kafka.index.resolution.yInteger设置y维空间索引的桶的个数。默认为180. 详情请看 Spatial Index Resolution
kafka.index.tiersString用于索引具有区段的几何图形的层的数量和大小,格式为 x1:y1,x2:y2. 详情请看 Spatial Index Tiering
kafka.serialization.lazyBoolean使用features的懒执行反序列化。这可能会提高处理负载,但代价是查询时间稍微变慢
geomesa.query.loose-bounding-boxBoolean使用松散的(?)边框,它提供了更好的性能,但并不精确
geomesa.query.auditBoolean审计传入的查询。默认情况下,审计被写入日志文件
geomesa.security.authsString用于查询数据的默认授权,以逗号分隔

三、数据生产者

GeoMesa Kafka Data Store可以将feature写入kafka中的特定主题。

可将kafka.consumer.count 设置为0来史消息禁止消费。

使用过程:

1、创建Data Store:

import org.geotools.data.DataStoreFinder;

String brokers = ...
String zookeepers = ...

// build parameters map
Map<String, Serializable> params = new HashMap<>();
params.put("kafka.brokers", brokers);
params.put("kafka.zookeepers", zookeepers);

// create the data store
KafkaDataStore ds = (KafkaDataStore) DataStoreFinder.getDataStore(params);

2、创建Schema,其中一个DataStore可以有多个Schema。

SimpleFeatureType sft = ...
ds.createSchema(sft);

3、Kafka Data Store只允许通过 feature ID来更新feature。

​ 可以使用ID过滤器来显示的创建一个feature修改器。

​ 也可以使用 feature writer ,来覆盖相同ID的feature。

// the name of the simple feature type -  will be the same as sft.getTypeName();
String typeName = sft.getTypeName();

SimpleFeatureWriter fw = ds.getFeatureWriterAppend(typeName, Transaction.AUTO_COMMIT);
SimpleFeature sf = fw.next();
// set properties on sf
fw.write();

删除 simple feature:

SimpleFeatureStore store = (SimpleFeatureStore) ds.getFeatureSource(typeName);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();

String id = ...
store.removeFeatures(ff.id(ff.featureId(id)));

删除所有simple feature:

store.removeFeatures(Filter.INCLUDE);

删除、新增、修改都会想kafka主题发送一条消息。

四、数据消费者

创建Data Store:

import org.geotools.data.DataStoreFinder;

 String brokers = ...
 String zookeepers = ...

 // build parameters map
 Map<String, Serializable> params = new HashMap<>();
 params.put("kafka.brokers", brokers);
 params.put("kafka.zookeepers", zookeepers);

 // optional - to read all existing messages on the kafka topic
 params.put("kafka.consumer.from-beginning", java.lang.Boolean.TRUE);

 // create the data store
 KafkaDataStore ds = (KafkaDataStore) DataStoreFinder.getDataStore(params);

消费:

String typeName = ...
SimpleFeatureStore store = ds.getFeatureSource(typeName);

Filter filter = ...
store.getFeatures(filter);

Data Store不会去消费提供的SimpleFeatureType ,除非你通过getFeatureSource() or getFeatureReader() 去访问。一旦进行访问,会在dispose() 之前一直进行访问。

五、kafka索引配置

大多数这些选项都可以在消费者数据存储上配置并立即生效 。

初始加载(Replay)

默认情况下,Kafka消费者数据存储将从主题的末尾开始消费。这意味着它只会看到在它启动之后编写的新更新。消费者可以选择从主题的前面开始,通过设置kafka.consumer.read-back来指定一个持续时间,例如1 hour 。这允许使用者重播旧消息并建立基线状态。要读取整个消息队列,可以将值设置为Inf

从0.10.1版本开始,Kafka只支持按给定的间隔读取数据。较老的版本将会从主题的最开始读取。

一个 feature store 在初始加载期间不会返回任何查询结果,直到它达到head状态。

Feature过期时间

通常,Kafka消费者DataStore将保留由生产者DataStore编写的任何feature,直到生产者使用修改后的feature编写器显式地删除它们。可选地,消费者DataStore可以通过kafka.cache.expiry指定feature的过期时间。当生产者向现有feature写入更新时,使用者将重置过期超时。一旦超时被命中而没有任何更新,该feature将从消费者缓存中删除,并且在查询时不再返回。

Feature事件时间

默认情况下,过期和更新时间由Kafka消息时间决定。feature更新将替换任何先前的feature消息,并且feature将根据读取的时间过期。

要想启用事件时间,需要指定配置名或者配置kafka.cache.event-time (值为CQL表达式)。这个表达式将根据每个feature进行计算,并且必须计算到一个日期或一个毫秒数。 这个值会和kafka.cache.expiry 一起为一个feature 设置一个过期时间。

kafka.cache.event-time.ordering 设置为true来将事件时间进行排序。当启用时,如果读取的feature更新的事件时间比当前feature的事件时间长,则将丢弃该消息。这对于处理不规则的更新流非常有用。

空间索引分辨率

Kafka消费者DataStore使用内存中的空间索引进行查询

空间索引将世界划分为网格,然后只在运行空间查询时检查相关网格单元 。

可通过kafka.index.resolution.xkafka.index.resolution.y来进行设置默认分别为360和180

提高网格分辨率可以减少查询时必须考虑feature的数量,并可以减少同步更新、删除和查询之间的争用。然而,它也需要更多的内存。

空间索引分层

对于不是点(point)的geometries ,kafka 消费者DataStore使用分层内存空间索引进行查询,根据轮廓大小来确定在哪一层。可通过kafka.index.tiers 来设置层数和大小。默认情况下,四层大小分别为1x14x432x32 and 360x180(值的书写格式为1:1,4:4,32:32,360:180 ) 。通常,层的大小要与索引的图形的大小一致。大于任何层的几何图形将不会被索引到,所以要包括一个能够覆盖整个世界的层。

CQEngine 索引

默认情况下,kafka消费者Data Store只会创建一个空间索引,因此对于非空间查询(根据时间进行查询)都会遍历索引中的所有feature(这也是非常快的)。

可以创建额外的内存索引来满足非空间查询,可通过kafka.index.cqengine来进行设置,值应该为name:type的逗号分隔列表,name是属性名,type是索引的类型。如果没有配置geom:geometry,则几何图形是不会被索引的。

例如:如果将kafka.index.cqengine设置为name:String,age:Int,dtg:Date,*geom:Point:srid=4326 ,则会为每个属性设置索引。

懒序列化

默认,kafka消费之Data Store为feature的属性使用懒序列化。对于写操作不频繁或者所有feature和属性都是一致读取的,可以通过设置kafka.serialization.lazyfalse。懒序列化会使运行时的损失非常小。

六、数据管理

kafka主题

每一个SimpleFeatureType 或者schema都会写入一个kafka主题。默认,主题名由kafka.zk.path的值和SimpleFeatureType的名连在一起,并且会将 “/”替换为的 “-”。例如:kafka.zk.path的值为 “geomesa/ds/kafka”,SimpleFeatureType的名为 “foo”,则kafka中主题的名为 geomesa-ds-kafka-foo 。

也可以自己指定kafka的主题名,需要通过geomesa.kafka.topic参数指定:

SimpleFeatureType sft = ....;
sft.getUserData().put("geomesa.kafka.topic", "myTopicName");

kafka主题配置

当调用createSchema(如果它还不存在)时,将创建给定SimpleFeatureType的Kafka主题。

kafka中的并行性是指一个主题中的多个分区实现的。每个分区只能有一个kafka消费者读取。消费者的数量可以通过kafka.consumer.count来指定。如果只有一个参数的话,这个参数不会产生任何影响。要想创建多个分区,可通过kafka.topic.prations来指定分区个数。要想对现有的主题进行重新分区,可通过kafka.topic.replication来指定重新分区的个数。

kafka主题压缩

kafka有多种方式来防止数据的无限增长。最简单的方式就是设置基于数据大小或时间的保留策略,当主题达到某个阈值时,可以使旧的数据删除。

从geomesa2.1.0开始,kafka Data Store支持kafka的日志压缩。这将允许管理主题的大小,并且保留每个feature的最新状态,这将可以在停机或者重启时仍可维护系统状态。注意,当使用日志压缩时,需要对每个feature进行显示的删除 。否则该feature将永远不会从日志中压缩出来,并且日志大小将无限增长。

如果使用的geomesa版本为2.1.0之前,在启用压缩之前,kafka主题应该使用基于数据大小或者时间的保留策略运行一段时间,因为在旧版本中kafka中的消息永远不会被压缩。

与其他系统进行集成

通过kafka的主题可以很轻松的与其他系统进行集成。每个消息的key是simple feature 的id(utf-8字节),每个消息体是序列化之后的simple feature,或者为null表示删除。在使用kafka0.11.X及其之后的版本时,内部序列化被设置为键 “v”的消息头。

默认情况下,消息体会通过Kryo进行序列化,对于java/scala,可以通过org.locationtech.geomesa.features.kryo.KryoFeatureSerializer 来进行反序列化。

或者,可以在kafka生产者端,通过kafka.serialization.type 参数来指定序列化器(可以指定为avro)。

七、监听feature事件

GeoTools的API包括了一种机制:可以在每次出现 event时触发一个FeatureEvent对象挡在SimpleFeatureSource中添加、删除、修改数据时触发 event,它有一个 changed()方法,每当触发FeatureEvent时调用此方法。

生产者可以向GeoMesa Kafka生产三种类型的数据,当对GeoMesa Kafka进行消费时,每个消费者都会触发一个FeatureEvent。所有的feature事件都继承自org.locationtech.geomesa.kafka.utils.KafkaFeatureEvent

Message read触发的事件类别FeatureEvent.TypeFilter
CreateOrUpdateKafkaFeatureChangedCHANGEDIN (<id>)
添加一个新的simple feature,或者对现有的simple feature进行更新
DeleteKafkaFeatureRemovedREMOVEDIN (<id>)
T根据给定的id删除simple feature
ClearKafkaFeatureClearedREMOVEDFilter.INCLUDE
删除所有的simple feature

要想注册FeatureListener,可以从GeoMesa Kafka消费者 Data Store中创建SimpleFeatureSource,并且使用addFeatureListener()

import org.geotools.data.FeatureEvent;
import org.geotools.data.FeatureListener;
import org.locationtech.geomesa.kafka.utils.KafkaFeatureEvent.KafkaFeatureChanged;
import org.locationtech.geomesa.kafka.utils.KafkaFeatureEvent.KafkaFeatureRemoved;
import org.locationtech.geomesa.kafka.utils.KafkaFeatureEvent.KafkaFeatureCleared;

// unless specified, the consumer will only read data written after its instantiation
SimpleFeatureSource source = ds.getFeatureSource(sftName);
FeatureListener listener = new FeatureListener() {
  @Override
  public void changed(FeatureEvent featureEvent) {
    if (featureEvent instanceof KafkaFeatureChanged) {
      KafkaFeatureChanged event = ((KafkaFeatureChanged) featureEvent);
      System.out.println("Received add/update for " + event.feature() +
                         " at " + new java.util.Date(event.time()));
    } else if (featureEvent instanceof KafkaFeatureRemoved) {
      KafkaFeatureRemoved event = ((KafkaFeatureRemoved) featureEvent);
      System.out.println("Received delete for " + event.id() + " " + event.feature() +
                         " at " + new java.util.Date(event.time()));
    } else if (featureEvent instanceof KafkaFeatureCleared) {
      KafkaFeatureCleared event = ((KafkaFeatureCleared) featureEvent);
      System.out.println("Received clear at " + new java.util.Date(event.time()));
    }
  }
};
store.addFeatureListener(listener);

在运行结束时,需要调用removeFeatureListener()

@PreDestroy
public void dispose() throws Exception {
    store.removeFeatureListener(listener);
    // other cleanup
}

八、融合集成

现在只是试验阶段,先不写了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值