多节点部署保证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中代码的更多相关文章

  1. 使用logstash同步MySQL数据到ES

    使用logstash同步MySQL数据到ES 版权声明:[分享也是一种提高]个人转载请在正文开头明显位置注明出处,未经作者同意禁止企业/组织转载,禁止私自更改原文,禁止用于商业目的. https:// ...

  2. solr 7+tomcat 8 + mysql实现solr 7基本使用(安装、集成中文分词器、定时同步数据库数据以及项目集成)

    基本说明 Solr是一个开源项目,基于Lucene的搜索服务器,一般用于高级的搜索功能: solr还支持各种插件(如中文分词器等),便于做多样化功能的集成: 提供页面操作,查看日志和配置信息,功能全面 ...

  3. 快速同步mysql数据到redis中

    MYSQL快速同步数据到Redis 举例场景:存储游戏玩家的任务数据,游戏服务器启动时将mysql中玩家的数据同步到redis中. 从MySQL中将数据导入到Redis的Hash结构中.当然,最直接的 ...

  4. 使用Logstash来实时同步MySQL数据到ES

    上篇讲到了ES和Head插件的环境搭建和配置,也简单模拟了数据作测试 本篇我们来实战从MYSQL里直接同步数据 一.首先下载和你的ES对应的logstash版本,本篇我们使用的都是6.1.1 下载后使 ...

  5. 如何将爬取的数据写入ES中

    前面章节一直在说ES相关知识点,现在是如何实现将爬取到的数据写入到ES中,首先的知道ES的python接口叫elasticsearch dsl 链接:https://github.com/elasti ...

  6. 使用logstash同步MongoDB数据到es

    input{ mongodb{ codec => "json" uri => 'mongodb://127.0.0.1:27017/kuaibao' placehold ...

  7. Django 同步数据库的时候app中的models的表没有成功创建

    出现  no  changes detected python3 manage.py makemigrations --empty blog # blog就是你的app名字,此处要写成自己的app名字 ...

  8. 使用SSIS创建同步数据库数据任务

    国外相关的文章:http://blog.dxuf.com/sql-tutorial/use-ssis-to-create-the-synchronization-database-data-task. ...

  9. [转]使用SSIS创建同步数据库数据任务

    本文转自:http://www.cnblogs.com/heqichang/archive/2012/09/19/2693214.html SSIS(SQL Server Integration Se ...

随机推荐

  1. c4d 帮助 prime r16 usage

    c4d   帮助 prime cinema 4d   prime    c4d  基础 前言   usage 开始 双击程序图标   双击一个场景文件   用开始菜单  windows 二选一   从 ...

  2. 关于C++ STL标准库中map 的多元素应用

    map的特性是,所有的元素会根据键值自动排序.map的所有元素都是pair,同时拥有实值(value)和键值(key).pair的第一个元素被视为键值,第二个被视为实质piar 的定义 templat ...

  3. python 文件(file)操作

    操作文件的一般流程有: 打开文件.文件处理.关闭文件 开开文件的模式有: r,只读模式(默认). w,只写模式.[不可读:不存在则创建:存在则删除内容:] a,追加模式.[不可读: 不存在则创建:存在 ...

  4. 什么是虚假唤醒 spurious wakeup

    解释一下什么是虚假唤醒? 说具体的例子,比较容易说通. pthread_mutex_t lock; pthread_cond_t notempty; pthread_cond_t notfull; v ...

  5. maven学习(九)——maven中的坐标、依赖以及仓库

    一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平面中唯一的一点. 1.2.Maven坐标主要组成 groupId:组织标识(包名) artifactId:项目名称 ver ...

  6. Unity3D_异步加载场景(进度条)

    创建两个场景:现在的场景“NowScene”,要加载的场景“LoadScene”: “NowScene”如图所示,“LoadScene”任意: 创建脚本“AsyncLoadScene”,复制如下代码, ...

  7. 谈谈Python中元类Metaclass(一):什么是元类

    简单的讲,元类创建了Python中所有的对象. 我们说Python是一种动态语言,而动态语言和静态语言最大的不同,就是函数和类不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个HelloW ...

  8. [LOJ#2327]「清华集训 2017」福若格斯

    [LOJ#2327]「清华集训 2017」福若格斯 试题描述 小d是4xx9小游戏高手. 有一天,小d发现了一个很经典的小游戏:跳青蛙. 游戏在一个 \(5\) 个格子的棋盘上进行.在游戏的一开始,最 ...

  9. [BZOJ2036]聪明的阿卑多

    [BZOJ2036]聪明的阿卑多 试题描述 也许你从没听说过阿卑多,但你一定知道他爷爷的爷爷的爷爷,那就是聪明绝顶的阿凡提先生.是的,阿卑多也是个聪明的小孩. 一天,阿卑多骑着他的小毛驴,在小镇上晃悠 ...

  10. redis学习(二)redis.conf文件配置

    转自: https://www.cnblogs.com/pqchao/p/6558688.html 为了更好的使用redis,我们需要详细的了解redis配置文件及相关参数作用. bind 127.0 ...