添加雪花算法

This commit is contained in:
zhaoyong 2022-01-17 17:07:28 +08:00
parent 220d9f17ca
commit 17719b5201
7 changed files with 400 additions and 1 deletions

77
canal-alarm/pom.xml Normal file
View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.axzo.framework</groupId>
<artifactId>canal-alarm</artifactId>
<version>1.0.0</version>
<name>canal-alarm</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.common</artifactId>
<version>1.1.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.instance.manager</artifactId>
<version>1.1.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<!-- 两个ID必须与 setting.xml中的<server><id>Releases</id></server>保持一致 -->
<repository>
<id>rdc-releases</id>
<name>Nexus Release Repository</name>
<url>https://packages.aliyun.com/maven/repository/2005773-release-XI7cl5/</url>
</repository>
<snapshotRepository>
<id>rdc-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>https://packages.aliyun.com/maven/repository/2005773-snapshot-V5Gjdf/</url>
</snapshotRepository>
</distributionManagement>
</project>

View File

@ -0,0 +1,131 @@
package cn.axzo.framework.canal.alarm;
import com.alibaba.fastjson.JSON;
import com.alibaba.otter.canal.common.AbstractCanalLifeCycle;
import com.alibaba.otter.canal.common.alarm.CanalAlarmHandler;
import com.alibaba.otter.canal.common.alarm.LogAlarmHandler;
import com.alibaba.otter.canal.instance.manager.plain.HttpHelper;
import com.google.common.base.Joiner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Canal 钉钉报警
*
* @author zhaoyong
* @see DingCanalAlarmHandler
* @since 2022-01-10 18:03
*/
public class DingCanalAlarmHandler extends AbstractCanalLifeCycle implements CanalAlarmHandler, EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(LogAlarmHandler.class);
/**
* 通知地址
*/
private String alarmUrl;
/**
* 密钥
*/
private String secretKey;
/**
* 接收者
*/
private String receive;
/**
* HTTP 请求
*/
private HttpHelper httpHelper;
private Environment environment;
@Override
public void sendAlarm(String destination, String msg) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String text = String.format(
"<font color='#FF0000'>[警报] </font>%s - Canal异常服务报警 \n\n" +
" --- \n\n " +
"<font color='#708090' size=2>destination%s</font> \n\n " +
"<font color='#778899' size=2>OWNER@%s</font> \n\n" +
"<font color='#778899' size=2>异常信息:%s</font> \n\n " +
" --- \n\n " +
"**播报时间:%s**",
// 环境
getProfile(),
// destination
destination,
// 告警手机号
getReceives(),
// 响应参数
msg,
// 当前时间
sdf.format(new Date())
);
MarkdownMessageRequest request = new MarkdownMessageRequest();
request.setMsgtype("markdown");
MarkdownMessage markdown = new MarkdownMessage();
markdown.setTitle("Canal服务报警");
markdown.setText(text);
request.setMarkdown(markdown);
try {
logger.info("[canal -> ding] DingCanalAlarmHandler.sendAlarm request param is {}", JSON.toJSONString(request));
String response = httpHelper.post(alarmUrl + secretKey, null, request,5000);
logger.info("[canal <- ding] DingCanalAlarmHandler.sendAlarm response is {}", response);
} catch (Exception e) {
logger.error("[canal <- ding] DingCanalAlarmHandler.sendAlarm response is error", e);
}
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public void setAlarmUrl(String alarmUrl) {
this.alarmUrl = alarmUrl;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public void setHttpHelper(HttpHelper httpHelper) {
this.httpHelper = httpHelper;
}
public void setReceive(String receive) {
this.receive = receive;
}
private String getProfile() {
String[] activeProfiles = environment.getActiveProfiles();
if(activeProfiles == null || activeProfiles.length == 0) {
return "dev";
}
return activeProfiles[0];
}
private String getReceives() {
if(StringUtils.isEmpty(receive)) {
return "13585844124";
}
String[] receives = receive.split(",");
return Joiner.on(", @").join(receives);
}
public static void main(String[] args) {
DingCanalAlarmHandler handler = new DingCanalAlarmHandler();
handler.setAlarmUrl("https://oapi.dingtalk.com/robot/send?access_token=");
handler.setSecretKey("4adbec74d777b6052cdae2ab25edb2ec1f32ef2d9b2c46a521a9b8258a1cdf47");
handler.setReceive("13585844124");
handler.setHttpHelper(new HttpHelper());
handler.sendAlarm("test", "test");
}
}

View File

@ -0,0 +1,46 @@
package cn.axzo.framework.canal.alarm;
/**
* markdown
*
* @author zhaoyong
* @see MarkdownMessage
* @since 2021-11-27 10:47
*/
public class MarkdownMessage {
/**
* 首屏会话透出的展示内容
*/
private String title;
/**
* markdown格式的消息
*/
private String text;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public String toString() {
return "MarkdownMessage{" +
"title='" + title + '\'' +
", text='" + text + '\'' +
'}';
}
}

View File

@ -0,0 +1,31 @@
package cn.axzo.framework.canal.alarm;
/**
* Markdown 消息
*
* @author zhaoyong
* @see MarkdownMessageRequest
* @since 2022-01-10 18:06
*/
public class MarkdownMessageRequest {
private String msgtype;
private MarkdownMessage markdown;
public String getMsgtype() {
return msgtype;
}
public void setMsgtype(String msgtype) {
this.msgtype = msgtype;
}
public MarkdownMessage getMarkdown() {
return markdown;
}
public void setMarkdown(MarkdownMessage markdown) {
this.markdown = markdown;
}
}

View File

@ -7,7 +7,7 @@
<groupId>cn.axzo.framework</groupId> <groupId>cn.axzo.framework</groupId>
<artifactId>common-common</artifactId> <artifactId>common-common</artifactId>
<!-- release --> <!-- release -->
<version>1.1.4</version> <version>1.1.5</version>
<!-- snapshot --> <!-- snapshot -->
<!-- <version>1.0.0-SNAPSHOT</version>--> <!-- <version>1.0.0-SNAPSHOT</version>-->

View File

@ -0,0 +1,113 @@
package cn.azxo.framework.common.service;
/**
* 雪花算法
*
* @author zhaoyong
* @see SnowflakeIdWorker
* @since 2021-12-12 04:25
*/
public class SnowflakeIdWorker {
/** 开始时间截 (建议用服务第一次上线的时间,到毫秒级的时间戳) */
private final long twepoch = 687888001020L;
/** 机器id所占的位数 */
private final long workerIdBits = 10L;
/** 支持的最大机器id结果是1023 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 时间截向左移22位(10+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits;
/** 生成序列的掩码这里为4095 (0b111111111111=0xfff=4095)
* <<为左移每左移动1位则扩大1倍
* */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/** 工作机器ID(0~1024) */
private long workerId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间截 */
private long lastTimestamp = -1L;
//==============================Constructors=====================================
/**
* 构造函数
* @param workerId 工作ID (0~1023)
*/
public SnowflakeIdWorker(long workerId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", maxWorkerId));
}
this.workerId = workerId;
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全的)
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的则进行毫秒内序列
if (lastTimestamp == timestamp) {
//如果毫秒相同则从0递增生成序列号
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间从1970-01-01 08:00:00算起
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
}

View File

@ -16,6 +16,7 @@
<module>smart-datasource</module> <module>smart-datasource</module>
<module>asyncTool</module> <module>asyncTool</module>
<module>alarm-spring-boot-starter</module> <module>alarm-spring-boot-starter</module>
<module>canal-alarm</module>
</modules> </modules>
<build> <build>