使用工具是logstash6.2.4
首先要知道的是,logstash抽取Oracle的数据是通过追踪某一个递增列实现增量导入的,所以就要求在查询结果有一个递增列,这并不是说需要一个自动增长列,因为在Oracle中,rownum可以作为查询结果中的一个递增列,如
SELECT * FROM(SELECT NP.*, ROWNUM RN FROM (SELECT * FROM NPMIS_ZW_YSDFMX) NP ) WHERE RN BETWEEN 5000001 AND 6000000;
所以logstash可以追踪rownum来增量导入。
有自动增长列
orderid为自动增长列
input { jdbc { jdbc_driver_library => "/opt/app/logstash-6.2.4/orcl-lib/ojdbc6.jar" jdbc_driver_class => "Java::oracle.jdbc.driver.OracleDriver" jdbc_connection_string => "jdbc:oracle:thin:@10.10.10.13:1521:testdb11g" jdbc_user => "udvmp" jdbc_password => "pwdvmp" schedule => "*/2 * * * *" statement => "SELECT * FROM NPMIS_ZW_YSDFMX_BAK_BAK WHERE orderid > :sql_last_value" record_last_run => "true" use_column_value => "true" tracking_column => "orderid" last_run_metadata_path => "/opt/app/logstash-6.2.4/config/last_id" clean_run => "false" } } filter { mutate { convert => { "zdl" => "float_eu"} } } output { elasticsearch { hosts => "cdh05.codsway.com" index => "obak-npmis_zw_ysdfmx_bak" document_id => "%{orderid}" } } |
没有自动增长列
把rownum查询出来作为一列,rn模拟自动增长列
input { jdbc { jdbc_driver_library => "/opt/app/logstash-6.2.4/orcl-lib/ojdbc6.jar" jdbc_driver_class => "Java::oracle.jdbc.driver.OracleDriver" jdbc_connection_string => "jdbc:oracle:thin:@10.10.10.13:1521:testdb11g" jdbc_user => "udvmp" jdbc_password => "pwdvmp" schedule => "*/2 * * * *" statement => "SELECT * FROM(SELECT NP.*, ROWNUM RN FROM (SELECT * FROM NPMIS_ZW_YSDFMX_BAK) NP) WHERE RN > :sql_last_val ue" record_last_run => "true" use_column_value => "true" tracking_column => "rn" last_run_metadata_path => "/opt/app/logstash-6.2.4/config/last_id" clean_run => "false" } } filter { mutate { convert => { "zdl" => "float_eu"} } } output { elasticsearch { hosts => "cdh03.codsway.com" index => "orcl-npmis_zw_ysdfmx_bak" document_id => "%{rn}" } } |
数据重复问题和Oracle增量数据ES同步慢问题
在默认配置下,tracking_column这个值是@timestamp,存在elasticsearch就是_id值,是logstash存入elasticsearch的时间,这个值的主要作用类似mysql的主键,是唯一的,但是我们的时间戳其实是一直在变的,所以我们每次使用select语句查询的数据都会存入elasticsearch中,导致数据重复。
解决方法:在要查询的表中,找主键或者自增值的字段,将它设置为_id的值,因为_id值是唯一的,所以,当有重复的_id的时候,数据就不会重复
input // 是否记录上次执行结果, 如果为真,将会把上次执行到的 tracking_column 字段的值记录下来,保存到 last_run_metadata_path 指定的文件中 record_last_run => "true" // 是否需要记录某个column 的值,如果record_last_run为真,可以自定义我们需要 track 的 column 名称,此时该参数就要为 true. 否则默认 track 的是 timestamp 的值. use_column_value => "true" // 如果 use_column_value 为真,需配置此参数. track 的数据库 column 名,该 column 必须是递增的. 一般是mysql主键,由于我们是用rownum也是递增的,可以在sql语句中查询出rownum作为这一列,orderid是rownum别名 tracking_column => "orderid " last_run_metadata_path => "/opt/app/logstash-6.2.4/config/last_id" //如果不设置,会从头开始再查询一次,因为数据量巨大所以导致同步的时间会很长,可能导致Oracle数据没有同步到ES clean_run => "false" //sql语句最后添加WHERE orderid > :sql_last_value,如果不适用where,那么之前的所有配置同步的配置都没有生效,每次都执行查询全部的语句,然后在大量的结果集中比较orderid,再将符合要求的数据插入ES,所以非常耗时间,:sql_last_value会读取last_run文件的值,如果没有这个文件就赋值为0开始 statement => "SELECT np.*,ROWNUM orderid FROM NPMIS_ZW_YSDFMX_BAK_BAK np WHERE orderid > :sql_last_value" |
output //index必须固定,不能随时间增长 index => "ORCL-NPMIS_ZW_YSDFMX_BAK" //把查询出来的rownum赋值给document_id,document_id在文档中具有唯一性,所以不会重复,也就不会插入重复数据 document_id => "%{orderid }" |
实际上并不是不同步,而是没有记录上次Oracle查询的位置,所以保存上次的查询记录就行了
数据丢失问题
logstash读取数据类型是由第一行或前几行决定的,所以如果某一列第一行值是整数,那么logstash就认定这一列是整数,第二行是小数,可能会把小数强转成整数,然后因为出现error丢失第二行或多行,丢失行可以在日志文件中看到,所以我们需要设置filter对列类型进行转换。
通过查看日志文件,查看出问题的是第几列,然后强转该列的类型。
float_eu是因为oracle查询出来的数据带有,号分隔符,比如12,340.99,所以需要写成float_eu,写成float会报错。如果是其他数据库可以试试float
filter { mutate { convert => { "zdl" => "float_eu"} } } |