同步数据库数据到ES中代码
多节点部署保证HA,分布式锁代码
public class DistributedLock implements Watcher,Runnable{
private static final Logger logger = LoggerFactory.getLogger(DistributedLock.class);
private int threadId;
private ZKConnector zkClient;
private String selfPath;
private String waitPath;
private String LOG_PREFIX_OF_THREAD;
private AbstractApplicationContext ctx;
private static boolean hascreated = false;
//确保连接zookeeper成功
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
//确保每个进程运行结束
private static final CountDownLatch threadSemaphore = new CountDownLatch(Constant.THREAD_NUM);
public ZKConnector getZkClient() {
return zkClient;
}
public void setZkClient(ZKConnector zkClient) {
this.zkClient = zkClient;
}
public DistributedLock(int id,AbstractApplicationContext context,ZKConnector zkClient){
this.threadId = id;
this.zkClient = zkClient;
LOG_PREFIX_OF_THREAD = Thread.currentThread().getName().concat("_").concat(String.valueOf(Thread.currentThread().getId()));
try{
zkClient.createConnection(Constant.ZKSERVER, Constant.SESSION_TIMEOUT);
//GROUP_PATH 不存在的话,由一个线程创建即可
synchronized (threadSemaphore) {
if(!zkClient.exist(Constant.GROUP_PATH)){
zkClient.createPersistNode(Constant.GROUP_PATH, "该节点由线程"+threadId+"创建");
}
}
ctx = context;
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
getLock();
}
@Override
public void process(WatchedEvent event) {
if(event ==null){
return;
}
if(KeeperState.SyncConnected ==event.getState()){
if(EventType.None == event.getType()){
connectedSemaphore.countDown();
}else if(event.getType()==EventType.NodeDeleted && event.getPath().equals(waitPath)){
if(checkMinPath()){
getLockSuccess();
}
}
}
}
/**
* 获取锁逻辑:
* 首先是上来先在zookeeper上注册一把属于自己的锁,然后修改状态为已创建
* 第二步,检查自己是否是最小id的锁,若是则获取锁,不是则继续等待
*/
private void getLock(){
if(!hascreated){
selfPath = this.getZkClient().createEsquentialNode(Constant.SUB_PATH, "");
hascreated = true;
}
if(checkMinPath()){
getLockSuccess();
}else{
Executor.run(this, 1, 1,TimeUnit.SECONDS);
}
}
/**
* 检查自己是不是最小路径
* @return
*/
public boolean checkMinPath(){
List<String> subNodes = this.getZkClient().getChildren(Constant.GROUP_PATH);
Collections.sort(subNodes);
//查找"/syncLocks"后面的路径
int index = subNodes.indexOf(selfPath.substring(Constant.GROUP_PATH.length()+1));
switch(index){
case -1:{
return false;
}
case 0:{
return true;
}
default:{
this.waitPath = Constant.GROUP_PATH+"/"+subNodes.get(index-1);
//Logger.info("waitPath: "+waitPath);
this.getZkClient().readData(waitPath);
if(!this.getZkClient().exist(waitPath)){
return checkMinPath();
}
}
}
return false;
}
/**
* 获取锁成功
*/
public void getLockSuccess(){
if(!this.getZkClient().exist(selfPath)){
logger.error(LOG_PREFIX_OF_THREAD+"本节点已不存在.");
return;
}
logger.info(LOG_PREFIX_OF_THREAD + "获取锁成功,进行同步工作!");
try{
new Worker(ctx).doWork();
}catch(Exception ex){
logger.info(ex.getMessage());
Executor.run(this, 1, 1, TimeUnit.SECONDS);
return;
}
logger.info(LOG_PREFIX_OF_THREAD+"删除本节点:"+selfPath);
this.getZkClient().deleteNode(selfPath);
this.getZkClient().releaseConnection();
threadSemaphore.countDown();
}
}
执行同步工作代码
public class Worker {
private static final Logger logger = LoggerFactory.getLogger(Worker.class);
private static JdbcTemplate jdbcTemplate;
private final ObjectMapper mapper = new ObjectMapper();
private ZKConnector zkClient =null;
private TransportClient client =null;
private Timestamp currentTimestamp = null;
private Timestamp previousTimestamp = null;
private static final String oggSql = "select * from t_order t0 left join t_order_attachedinfo t1 on t0.order_id = t1.order_id where ";
private String sql;
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
private TransportClient getClient() {
Settings settings = Settings.settingsBuilder().put("cluster.name", Constant.CLUSTER).build();
TransportClient client = TransportClient.builder().settings(settings).build();
try {
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(Constant.ESHOST), Constant.ESPORT));
} catch (UnknownHostException e) {
e.printStackTrace();
}
return client;
}
public Worker(AbstractApplicationContext ctx){
//初始化Oracle连接
jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
client = getClient();
zkClient = new ZKConnector();
zkClient.createConnection(Constant.ZKSERVER, Constant.SESSION_TIMEOUT);
//初始化zookeeper锁,由于zookeeper不能联级创建
if(!zkClient.exist(Constant.ZK_PATH)){
zkClient.createPersistNode(Constant.ZK_PATH,"");
}
/**
* 获取zookeeper的最后同步时间
*/
if(currentTimestamp == null){
String zkTimestamp = zkClient.readData(Constant.NODE_PATH);
if(zkTimestamp != null && !zkTimestamp.equals(""))
{
try
{
currentTimestamp = Timestamp.valueOf(zkTimestamp);
logger.info("获取zookeeper最后同步时间: "+currentTimestamp);
}catch(Exception e){
zkClient.deleteNode(Constant.NODE_PATH);
}
}
}
}
/**
* 同步work的逻辑:
* 将Oracle里面的规则表同步到缓存当中
* 首先是访问Oracle里面数据,通过访问最小锁里面的同步时间戳,查询出大于同步时间戳的数据
* 如果在zookeeper中获取的时间戳为空,则查询条件增加时间戳,写入存储框架
* 写入成功之后,将最后一条记录的同步时间戳写到zookeeper集群中
* 若写入失败,和zookeeper握手失败,会话锁消失
* 然后导入ElasticSearch中
*/
public void doWork(){
logger.info("start ...");
//一直进行同步工作
while(true){
String sqlwhere = "";
//根据时间戳获取Mycat中规则表数据
String sql = "";
//若最后一次同步时间为空,则按最后更新时间排序,取最小的时间作为当前时间戳
if(currentTimestamp != null){
sql = "select order_id,timestamp from t_order_changes where rownum <= 10 and timestamp > to_timestamp('" + currentTimestamp.toString() + "','yyyy-mm-dd hh24:mi:ss.ff6')";
}else{
sql = "select order_id,timestamp from t_order_changes where rownum <= 10 order by timestamp";
}
//查詢该时间段的订单id
List<String> ids = new ArrayList<String>();
//升序会将最后一次的时间也就是最大的时间作为当前的currentTimeStamp
ids = jdbcTemplate.query(sql, new Object[] {}, new RowMapper<String>()
{
public String mapRow(ResultSet result, int rowNum) throws SQLException {
currentTimestamp = result.getTimestamp("timestamp");
return result.getString("order_id");
}
});
if(ids.size() ==0){
continue;
}
int i =0;
List<String> checkIds = new ArrayList<String>();
for (String id : ids) {
//若存在更新的id则跳过
if (checkIds.contains(id)) {
continue;
}
if (i == 0) {
sqlwhere = sqlwhere.concat(" t0.order_id = '" + id + "'");
} else {
sqlwhere = sqlwhere.concat(" or t0.order_id = '" + id + "'");
}
checkIds.add(id);
i++;
}
System.out.println(oggSql.concat(sqlwhere));
//objs 即是Oracle里面查询出来需要同步的数据
List<JSONObject> objs = jdbcTemplate.query(oggSql.concat(sqlwhere), new Object[] {}, new RowMapper<JSONObject>()
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public JSONObject mapRow(ResultSet result, int rowNum) throws SQLException {
int c = result.getMetaData().getColumnCount();
JSONObject obj = new JSONObject();
for(int t =1 ;t <= c;t++)
{
if(result.getObject(t) == null)
{
continue;
}
if(result.getMetaData().getColumnType(t) == Types.DATE)
{
obj.put(result.getMetaData().getColumnLabel(t).toLowerCase(), result.getDate(t));
}else if(result.getMetaData().getColumnType(t) == Types.TIMESTAMP)
{
Date date = new Date(result.getTimestamp(t).getTime());
String f = sdf.format(date);
obj.put(result.getMetaData().getColumnLabel(t).toLowerCase(),sdf.format(date));
}else
{
obj.put(result.getMetaData().getColumnLabel(t).toLowerCase(), result.getObject(t));
}
}
return obj;
}
});
/*for (JSONObject obj : objs) {
System.out.println(obj.toJSONString());
}*/
/**
* 将查询出来的数据写入到elasticsearch中
*/
BulkRequestBuilder bulkRequest =null;
try {
bulkRequest = client.prepareBulk();
for (JSONObject obj : objs) {
byte[] json;
try {
json = mapper.writeValueAsBytes(obj);
bulkRequest.add(new IndexRequest(Constant.INDEX, Constant.INDEX, obj.getString("order_id"))
.source(json));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
BulkResponse bulkResponse = bulkRequest.get();
if (bulkResponse.hasFailures()) {
logger.info("====================批量创建索引过程中出现错误 下面是错误信息==========================");
long count = 0L;
for (BulkItemResponse bulkItemResponse : bulkResponse) {
System.out.println("发生错误的 索引id为 : "+bulkItemResponse.getId()+" ,错误信息为:"+ bulkItemResponse.getFailureMessage());
count++;
}
logger.info("====================批量创建索引过程中出现错误 上面是错误信息 共有: "+count+" 条记录==========================");
currentTimestamp = previousTimestamp;
} else {
logger.info("The lastest currenttimestamp : ".concat(currentTimestamp.toString()));
previousTimestamp = currentTimestamp;
//将写入成功后的时间写到zookeeper中
zkClient.writeData(Constant.NODE_PATH, String.valueOf(currentTimestamp));
}
} catch (NoNodeAvailableException e) {
currentTimestamp = previousTimestamp;
e.printStackTrace();
}
}
}
}
调度工具代码
public class Executor {
private static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
public static void run(Runnable r,long init,long delay,TimeUnit u){
service.scheduleWithFixedDelay(r, init, delay, u);
}
}
启动类
public class StartRcpSync {
private static final Logger Logger = LoggerFactory.getLogger(StartRcpSync.class);
private static AbstractApplicationContext appContext = null;
private static String confPath = null;
static{
//后续来读取命令中的conf 例如 java -Dconf=conf/*.xml -classpath .:lib/*
if(System.getProperty("conf") !=null){
System.out.println(System.getProperty("user.dir"));
confPath = System.getProperty("conf");
System.out.println("读取配置路径conf目录:"+confPath);
appContext = new FileSystemXmlApplicationContext(confPath.concat("/applicationContext*.xml"));
}else{
confPath = "E:/aa/bb/src/main/resources/conf";
appContext = new FileSystemXmlApplicationContext(confPath.concat("/applicationContext*.xml"));
}
}
public static void main(String[] args) {
Logger.info("Sync will starting ...");
//加载配置文件
appContext.registerShutdownHook();
appContext.start();
Logger.info("Sync has been started successfully.");
//获取zookeeper的连接
ZKConnector zkClient = new ZKConnector();
DistributedLock dl = new DistributedLock(new Random().nextInt(),appContext,zkClient);
dl.run();
}
//just for Test
public static void DoTask(){
Worker w =new Worker(appContext);
w.doWork();
}
}
同步数据库数据到ES中代码的更多相关文章
- 使用logstash同步MySQL数据到ES
使用logstash同步MySQL数据到ES 版权声明:[分享也是一种提高]个人转载请在正文开头明显位置注明出处,未经作者同意禁止企业/组织转载,禁止私自更改原文,禁止用于商业目的. https:// ...
- solr 7+tomcat 8 + mysql实现solr 7基本使用(安装、集成中文分词器、定时同步数据库数据以及项目集成)
基本说明 Solr是一个开源项目,基于Lucene的搜索服务器,一般用于高级的搜索功能: solr还支持各种插件(如中文分词器等),便于做多样化功能的集成: 提供页面操作,查看日志和配置信息,功能全面 ...
- 快速同步mysql数据到redis中
MYSQL快速同步数据到Redis 举例场景:存储游戏玩家的任务数据,游戏服务器启动时将mysql中玩家的数据同步到redis中. 从MySQL中将数据导入到Redis的Hash结构中.当然,最直接的 ...
- 使用Logstash来实时同步MySQL数据到ES
上篇讲到了ES和Head插件的环境搭建和配置,也简单模拟了数据作测试 本篇我们来实战从MYSQL里直接同步数据 一.首先下载和你的ES对应的logstash版本,本篇我们使用的都是6.1.1 下载后使 ...
- 如何将爬取的数据写入ES中
前面章节一直在说ES相关知识点,现在是如何实现将爬取到的数据写入到ES中,首先的知道ES的python接口叫elasticsearch dsl 链接:https://github.com/elasti ...
- 使用logstash同步MongoDB数据到es
input{ mongodb{ codec => "json" uri => 'mongodb://127.0.0.1:27017/kuaibao' placehold ...
- Django 同步数据库的时候app中的models的表没有成功创建
出现 no changes detected python3 manage.py makemigrations --empty blog # blog就是你的app名字,此处要写成自己的app名字 ...
- 使用SSIS创建同步数据库数据任务
国外相关的文章:http://blog.dxuf.com/sql-tutorial/use-ssis-to-create-the-synchronization-database-data-task. ...
- [转]使用SSIS创建同步数据库数据任务
本文转自:http://www.cnblogs.com/heqichang/archive/2012/09/19/2693214.html SSIS(SQL Server Integration Se ...
随机推荐
- Mac OS 添加 MySQL 环境变量
1.打开终端,输入: cd ~ 会进入~文件夹 2.如果 ~ 文件夹中已经存在 .bash_profile 文件,则在 : 后面追加你想要添加的路径, 3. 否则输入:touch .bash_prof ...
- 从shell(终端)中退出python
从shell(终端)中退出python: 1.输入命令行:$ exit() 2.快捷键: ctrl+Z
- Dorado日常使用总结
1.360兼容模式下的控件虚线边框问题: 控件加载是onReady事件中加上:self.focusable=false;(用于指示该种控件是否支持获得控制焦点.) 2.360兼容模式下滚动条 cont ...
- 【bzoj4281】[ONTAK2015]Związek Harcerstwa Bajtockiego 树上倍增+LCA
题目描述 给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点.之后你将依次收到k个指令,每个指令包含两个整数d和t,你需要沿着最短路在t步之内(包含t步)走到d点,如果不能走到,则停在 ...
- Java实现简单的socket通信
今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了. 今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有pa ...
- HDU 3333 Turing Tree(离线树状数组)
Turing Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- [POJ1160] Post Office [四边形不等式dp]
题面: 传送门 思路: dp方程实际上很好想 设$dp\left[i\right]\left[j\right]$表示前$j$个镇子设立$i$个邮局的最小花费 然后状态转移: $dp\left[i\ri ...
- Java简明教程 11.异常
异常的感性认识 在没有异常机制的语言中,经常通过返回值来表示调用该函数产生的各种问题(异常),比如c语言. divide.c #include <stdio.h> int main() { ...
- callee返回正被执行的Function对象
arguments.length是实参长度, arguments.callee.length是形参长度. function fn(a, b, c, d) { console.log(arguments ...
- 【13】vuex2.0 之 state
Vuex 的核心是 store, 它是一个通过 Vuex.Store 构造函数生成的对象.为什么它会是核心呢?因为我们调用这个构造函数创建store 对象的时候,给它传递参数中包装了state, mu ...