多节点部署保证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. cookie和session机制区别

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  2. 在iBatis中操作Blob数据类型

    这里的Blob数据类型指的是保存了文本的blob数据类型 直接读取blob类型存储的文本,可能会出现乱码,所以需要读取完后进行手动转码 这里使用ibatis作为持久层 SELECT urlconten ...

  3. How to modify a compiled Android application (.apk file)

    Today I’d like to share with you my findings about how an existing .apk file can be modified. An .ap ...

  4. Gym 100989E 字符串

    Description standard input/output Islam is usually in a hurry. He often types his passwords incorrec ...

  5. Python数据结构之列表

    1.Python列表是Python内置的数据结构对象之一,相当于数组 2.列表用[] 包含,内有任意的数据对象,每一个数据对象以 ,逗号分隔,每隔数据对象称之为元素 3.Python列表是一个有序的序 ...

  6. duilib入门简明教程 -- 界面设计器 DuiDesigner (10) (转)

    原文转自:http://www.cnblogs.com/Alberl/p/3343838.html     上一个教程讲解了怎么布局最大化.最小化.关闭按钮,但是如果手动去计算这三个按钮的位置和大小的 ...

  7. template相关

    template模板是c++中支持多态的工具,使用模板可以使用户为类或函数声明一种一般的模式,使得该模板试用于任意类型的参数. 函数模板: 定义如下: template <typename T& ...

  8. 2014年国内最热门的.NET开源平台

    http://developer.51cto.com/art/201501/464292.htm

  9. 搜狗拼音输入法LINUX版安装

    搜狗拼音输入法LINUX版官方下载: http://pinyin.sogou.com/linux/?r=pinyin 一.添加fcitx的nightlyPPA 在终端中输入: sudo add-apt ...

  10. 深度学习_2_CNN

    Basic Conception: 感受野(Reception Field) 权值共享(shared weights) 池化,即降采样(sub-Sampling) 卷积核(kernel,filter) ...