logstash采集mysql数据同步到es中时间字段相差8小时的解决办法
最近在做的项目中,需要将MySQL中的数据通过logstash同步至elasticsearch,但是同步后发现es中的文档时间字段不对了,统统比实际时间提前8小时。
查了资料发现,这是由于logstash在获取时区的时候,默认获取的是UTC默认时间,同时elasticsearch在创建索引的时候,统一使用UTC时间,因为中国使用的为东8时区,源数据和实际创建的索引数据会相差8个小时。
所以如果获取的是UTC时间,会导致我们取es文档时间字段不符合实际,其实可以通过修改 logstash-db-sync.conf 同步配置文件来解决时间差的问题。
以下是我自己项目中用的配置文件,项目上logstash用的是6.8.4版本,该文件位于/usr/local/logstash-6.8.4/sync目录下。
input { jdbc { # 设置 MySql/MariaDB 数据库url以及数据库名称 jdbc_connection_string => "jdbc:mysql://10.1.1.129:3306/ctscm_uat?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai" # 用户名和密码 jdbc_user => "ctscm_uat" jdbc_password => "han2018chen" # 数据库驱动所在位置,可以是绝对路径或者相对路径 jdbc_driver_library => "/usr/local/logstash-6.8.4/sync/mysql-connector-java-8.0.19.jar" # 驱动类名 jdbc_driver_class => "com.mysql.jdbc.Driver" # 开启分页 jdbc_paging_enabled => "true" # 分页每页数量,可以自定义 jdbc_page_size => "1000" # 执行的sql文件路径 # statement_filepath => "/usr/local/logstash-6.8.4/sync/sync.sql" statement => "SELECT * FROM contract WHERE update_time > :sql_last_value" # 设置定时任务间隔 含义:分、时、天、月、年,全部为*默认含义为每分钟跑一次任务 schedule => "* * * * *" # 索引类型 type => "contract" # 是否开启记录上次追踪的结果,也就是上次更新的时间,这个会记录到 last_run_metadata_path 的文件 use_column_value => true # 记录上一次追踪的结果值 last_run_metadata_path => "/usr/local/logstash-6.8.4/sync/track_time" # 如果 use_column_value 为true, 配置本参数,追踪的 column 名,可以是自增id或者时间 tracking_column => "update_time" # tracking_column 对应字段的类型 tracking_column_type => "timestamp" # 是否清除 last_run_metadata_path 的记录,true则每次都从头开始查询所有的数据库记录 clean_run => false # 数据库字段名称大写转小写 lowercase_column_names => false jdbc_default_timezone => "Asia/Shanghai" #使用本地时区为local,否则sql_last_value如果是timestamp,时间会提前8小时
#值可以是任何的:utc,local,默认值为 "utc" plugin_timezone => "local" } } filter { # 因为时区问题需要修正时间 ruby { code => "event.set('timestamp', event.get('@timestamp').time.localtime + 8*60*60)" } ruby { code => "event.set('@timestamp',event.get('timestamp'))" } mutate { remove_field => ["timestamp"] } # 因为时区问题需要修正时间 ruby { code => "event.set('create_time', event.get('create_time').time.localtime + 8*60*60)" } # 因为时区问题需要修正时间 ruby { code => "event.set('update_time', event.get('update_time').time.localtime + 8*60*60)" } # 转换成日期格式 ruby { code => "event.set('start_date', event.timestamp.time.localtime.strftime('%Y-%m-%d'))" } # 转换成日期格式 ruby { code => "event.set('end_date', event.timestamp.time.localtime.strftime('%Y-%m-%d'))" } # 转换成日期格式 ruby { code => "event.set('sign_date', event.timestamp.time.localtime.strftime('%Y-%m-%d'))" } } output { elasticsearch { # ES的IP地址及端口 hosts => ["10.1.2.32:9200"] # 同步的索引名 index => "ctscm" # 设置_docID和数据相同 document_id => "%{contract_id}" } # 日志输出 stdout { codec => json_lines } }
说明:
主要是以下几个参数要正确配置
1.jdbc_connection_string配置上使用CTT(Asia/shanghai)时间
jdbc_connection_string => "jdbc:mysql://192.168.0.145:3306/db_example?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT"
或者
jdbc_connection_string => "jdbc:mysql://192.168.0.145:3306/db_example?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/shanghai"
2.新增时区参数
- jdbc_default_timezone
值类型为字符串,此设置没有默认值。
时区转换。Logstash(和Elasticsearch)期望时间戳以UTC术语表示。如果您的数据库记录了相对于另一个时区的时间戳,则将记录该数据库的时区,然后将此设置设置为数据库使用的时区。但是,由于SQL不允许在时间戳字段中提供时区数据,因此我们无法逐条记录地进行计算。此插件将以ISO8601格式的相对UTC时间自动将您的SQL时间戳字段转换为Logstash时间戳。
使用此设置将手动分配指定的时区偏移,而不是使用本地计算机的时区设置。
jdbc_default_timezone => "Asia/Shanghai"
- plugin_timezone
值可以是任何的:utc,local,默认值为 "utc"。
如果您希望此插件将时间戳偏移到UTC以外的时区,则可以将此设置设置为local,插件将使用OS时区进行偏移调整。
注意:当指定plugin_timezone和/或时jdbc_default_timezone,偏移量调整在两个地方进行,如果sql_last_value是时间戳,并且在语句中用作参数,则偏移量调整将从插件时区到数据时区,并且在处理记录时,时间戳从数据库时区偏移到插件时区。如果您的数据库时区为UTC,则无需设置这些设置中的任何一个。