做外贸有哪些好的网站,做淘宝客网站用什么系统,软文广告范例大全,wordpress 域名配置目录
分布式命名服务
分布式API目录 分布式节点的命名
分布式的ID生成器
分布式的ID生成器方案#xff1a;
基于Zookeeper实现分布式ID生成器
基于Zookeeper实现SnowFlakeID算法 分布式命名服务 命名服务是为系统中的资源提供标识能力。ZooKeeper的命名服务主要是利用Z…目录
分布式命名服务
分布式API目录 分布式节点的命名
分布式的ID生成器
分布式的ID生成器方案
基于Zookeeper实现分布式ID生成器
基于Zookeeper实现SnowFlakeID算法 分布式命名服务 命名服务是为系统中的资源提供标识能力。ZooKeeper的命名服务主要是利用ZooKeeper节点的树形分层结构和子节点的顺序维护能力来为分布式系统中的资源命名。需要用到分布式命名服务的应用场景典型的有分布式API目录、分布式节点命名、分布式ID生成器。
分布式API目录 为分布式系统中各种API接口服务的名称、链接地址提供类似JNDIJava命名和目录接口中的文件系统的功能。借助于ZooKeeper的树形分层结构就能提供分布式的API调用功能。著名的Dubbo分布式框架就是应用了ZooKeeper的分布式的JNDI功能。在Dubbo中使用ZooKeeper维护的全局服务接口API的地址列表。大致的思路为
服务提供者Service Provider 在启动的时候向ZooKeeper上的指定节点/dubbo/${serviceName}/providers写入自己的API地址这个操作就相当于服务的公开。服务消费者Consumer 启动的时候订阅节点/dubbo/{serviceName}/providers下的服务提供者的URL地址获得所有服务提供者的API。 分布式节点的命名 一个分布式系统通常会由很多的节点组成节点的数量不是固定的而是不断动态变化的。比如说 当业务不断膨胀和流量洪峰到来时大量的节点可能会动态加入到集群中。而一旦流量洪峰过去了 就需要下线大量的节点。这就需要用到分布式节点的命名服务。
可用于生成集群节点的编号的方案
1. 使用数据库的自增ID特性用数据表存储机器的MAC地址或者IP来维护。
2. 使用ZooKeeper持久顺序节点的顺序特性来维护节点的NodeId编号。
在第2种方案中集群节点命名服务的基本流程是 启动节点服务连接ZooKeeper检查命名服务根节点是否存在如果不存在就创建系统的根节点。 在根节点下创建一个临时顺序ZNode节点取回ZNode的编号把它作为分布式系统中节点的NODEID。 如果临时节点太多可以根据需要删除临时顺序ZNode节点。 分布式的ID生成器 分布式系统中分布式ID生成器的使用场景非常多比如大量的数据记录、大量的系统消息 、大量的请求日志、分布式节点的命名服务等 传统的数据库自增主键已经不能满足需求。在分布式系统环境中需要一种全新的唯一ID系统 这种系统需要满足以下需求
全局唯一不能出现重复ID。
高可用ID生成系统是基础系统被许多关键系统调用一旦宕机就会造成严重影响。 分布式的ID生成器方案
1. Java的UUID。 2. 分布式缓存Redis生成ID利用Redis的原子操作INCR和INCRBY生成全局唯一的ID。 3. Twitter的SnowFlake算法。 4. ZooKeeper生成ID利用ZooKeeper的顺序节点生成全局唯一的ID。 5. MongoDB的ObjectId:MongoDB是一个分布式的非结构化NoSQL数据库每插入一条记录会自动生成全局唯 一的一个“_id”字段值它是一个12字节的字符串可以作为分布式系统中全局唯一的ID。 基于Zookeeper实现分布式ID生成器
在ZooKeeper节点的四种类型中其中有以下两种类型具备自动编号的能力
PERSISTENT_SEQUENTIAL持久化顺序节点。
EPHEMERAL_SEQUENTIAL临时顺序节点。 ZooKeeper的每一个节点都会为它的第一级子节点维护一份顺序编号会记录每个子节点创建的先后 顺序这个顺序编号是分布式同步的也是全局唯一的。可以通过创建ZooKeeper的临时顺序节点的方法生成全局唯一的ID
Slf4j
public class IDMaker extends CuratorBaseOperations {private String createSeqNode(String pathPefix) throws Exception {CuratorFramework curatorFramework getCuratorFramework();//创建一个临时顺序节点String destPath curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(pathPefix);return destPath;}public String makeId(String path) throws Exception {String str createSeqNode(path);if(null ! str){//获取末尾的序号int index str.lastIndexOf(path);if(index0){indexpath.length();return indexstr.length() ? str.substring(index):;}}return str;}
}
Slf4j
public class IDMakerTest {Testpublic void testMarkId() throws Exception {IDMaker idMaker new IDMaker();idMaker.init();String pathPrefix /idmarker/id-;//模拟5个线程创建idfor(int i0;i5;i){new Thread(()-{for (int j0;j10;j){String id null;try {id idMaker.makeId(pathPrefix);log.info(线程{}第{}次创建id为{},Thread.currentThread().getName(),j,id);} catch (Exception e) {e.printStackTrace();}}},threadi).start();}}
}
执行结果如下 如果是每秒钟要几万、几十万的id这种方案是不行的受限于zookeeper的顺序节点写操作。 基于Zookeeper实现SnowFlakeID算法 Twitter推特的SnowFlake算法是一种著名的分布式服务器用户ID生成算法。SnowFlake算法所生成的ID是一个64bit的长整型数字。这个64bit被划分成四个部分其中后面三个部分分别表示时间戳、工作机器ID、序列号。 SnowFlakeID的四个部分具体介绍如下
1. 第一位 占用1 bit其值始终是0没有实际作用。
2. 时间戳 占用41 bit精确到毫秒总共可以容纳约69年的时间。
3. 工作机器id占用10 bit最多可以容纳1024个节点。
4. 序列号占用12 bit。这个值在同一毫秒同一节点上从0开始不断累加最多可以累加到4095。 在工作节点达到1024顶配的场景下SnowFlake算法在同一毫秒最多可以生成的ID数量为 1024 * 4096 4194304在绝大多数并发场景下都是够用的。
SnowFlake算法的优点 1. 生成ID时不依赖于数据库完全在内存生成高性能和高可用性。 2. 容量大每秒可生成几百万个ID。 3. ID呈趋势递增后续插入数据库的索引树时性能较高。
SnowFlake算法的缺点
1. 依赖于系统时钟的一致性如果某台机器的系统时钟回拨了有可能造成ID冲突或者ID乱序。 2. 在启动之前如果这台机器的系统时间回拨过那么有可能出现ID重复的危险。
基于zookeeper实现雪花算法
public class SnowflakeIdGenerator {/*** 单例*/public static SnowflakeIdGenerator instance new SnowflakeIdGenerator();/*** 初始化单例** param workerId 节点Id,最大8091* return the 单例*/public synchronized void init(long workerId) {if (workerId MAX_WORKER_ID) {// zk分配的workerId过大throw new IllegalArgumentException(woker Id wrong: workerId);}instance.workerId workerId;}private SnowflakeIdGenerator() {}/*** 开始使用该算法的时间为: 2017-01-01 00:00:00*/private static final long START_TIME 1483200000000L;/*** worker id 的bit数最多支持8192个节点*/private static final int WORKER_ID_BITS 13;/*** 序列号支持单节点最高每毫秒的最大ID数1024*/private final static int SEQUENCE_BITS 10;/*** 最大的 worker id 8091* -1 的补码二进制全1右移13位, 然后取反*/private final static long MAX_WORKER_ID ~(-1L WORKER_ID_BITS);/*** 最大的序列号1023* -1 的补码二进制全1右移10位, 然后取反*/private final static long MAX_SEQUENCE ~(-1L SEQUENCE_BITS);/*** worker 节点编号的移位*/private final static long WORKER_ID_SHIFT SEQUENCE_BITS;/*** 时间戳的移位*/private final static long TIMESTAMP_LEFT_SHIFT WORKER_ID_BITS SEQUENCE_BITS;/*** 该项目的worker 节点 id*/private long workerId;/*** 上次生成ID的时间戳*/private long lastTimestamp -1L;/*** 当前毫秒生成的序列*/private long sequence 0L;/*** Next id long.** return the nextId*/public Long nextId() {return generateId();}/*** 生成唯一id的具体实现*/private synchronized long generateId() {long current System.currentTimeMillis();if (current lastTimestamp) {// 如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过出现问题返回-1return -1;}if (current lastTimestamp) {// 如果当前生成id的时间还是上次的时间那么对sequence序列号进行1sequence (sequence 1) MAX_SEQUENCE;if (sequence MAX_SEQUENCE) {// 当前毫秒生成的序列数已经大于最大值那么阻塞到下一个毫秒再获取新的时间戳current this.nextMs(lastTimestamp);}} else {// 当前的时间戳已经是下一个毫秒sequence 0L;}// 更新上次生成id的时间戳lastTimestamp current;// 进行移位操作生成int64的唯一ID//时间戳右移动23位long time (current - START_TIME) TIMESTAMP_LEFT_SHIFT;//workerId 右移动10位long workerId this.workerId WORKER_ID_SHIFT;return time | workerId | sequence;}/*** 阻塞到下一个毫秒*/private long nextMs(long timeStamp) {long current System.currentTimeMillis();while (current timeStamp) {current System.currentTimeMillis();}return current;}}