多节点部署保证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. C#知识点<2>

    1. ? : 运算符(真2假3) 我们已经在前面的章节中讲解了 条件运算符 ? :,可以用来替代 if...else 语句.它的一般形式如下: Exp1 ? Exp2 : Exp3; 其中,Exp1. ...

  2. 浅谈JavaScript中的函数问题

    前面的话:JavaScript可运行在所有主要平台的主流浏览器上,也可运行在每一个主流操作系统的服务器端上.所以呢,要想成为一名优秀的全栈工程师,必须懂得JavaScript语言.这是我整理的JS的部 ...

  3. web自动化测试:watir+minitest(二)

    环境搭建: 我已经安装了一台全新的win7虚拟机.下面将开始搭建watir环境. 安装包清单. 安装ruby.执行rubyinstaller-2.2.4-x64.exe 选择语言: 勾选添加到环境变量 ...

  4. [luoguP2224] [HNOI2001]产品加工(背包DP)

    传送门 f[i][j]表示第一个机器耗时j,第二个机器耗时f[i][j] 第一维可以滚掉 #include <cstdio> #include <cstring> #inclu ...

  5. 无序字母对 character

    无序字母对 character 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入 ...

  6. Codeforces Round #323 (Div. 2) B 贪心,暴力

    B. Robot's Task time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  7. c#byte数组和string类型转换

    http://blog.csdn.net/rowanhaoa/article/details/42144313/ 用system.text中的encoding这个类

  8. python面试模拟真题讲解

    一.选择题(32分) 1.python不支持的数据类型有:(A) A.char B.int C.float D.list 2.x = “foo” y = 2 print(x+y)           ...

  9. 【BZOJ4476&JSOI2015】送礼物(二分,RMQ)

    ANS明显是有二分性的 二分答案,设二分值为b M(i,j)−m(i,j)j−i+k>b 显然当l<长度<r时,一端是最小值,一端是最大值. 等于l或r的时候因为可能不满足以上性质, ...

  10. Javascript&Ajax-深入浅出JSONP--解决ajax跨域问题

    Javascript&Ajax-深入浅出JSONP--解决ajax跨域问题 原理讲解: 链接地址:http://www.cnblogs.com/chopper/archive/2012/03/ ...