当前位置: 首页 > news >正文

zk基础—5.Curator的使用与剖析一

大纲

1.基于Curator进行基本的zk数据操作

2.基于Curator实现集群元数据管理

3.基于Curator实现HA主备自动切换

4.基于Curator实现Leader选举

5.基于Curator实现分布式Barrier

6.基于Curator实现分布式计数器

7.基于Curator实现zk的节点和子节点监听机制

8.基于Curator创建客户端实例的源码分析

9.Curator在启动时是如何跟zk建立连接的

10.基于Curator进行增删改查节点的源码分析

11.基于Curator的节点监听回调机制的实现源码

12.基于Curator的Leader选举机制的实现源码

1.基于Curator进行基本的zk数据操作

Guava is to Java what Curator is to ZooKeeper,引入依赖如下:

<dependencies><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.12.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.12.0</version></dependency>
</dependencies>

Curator实现对znode进行增删改查的示例如下,其中CuratorFramework代表一个客户端实例。注意:可以通过creatingParentsIfNeeded()方法进行指定节点的级联创建。

public class CrudDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();//启动客户端并建立连接System.out.println("已经启动Curator客户端");client.create().creatingParentsIfNeeded()//进行级联创建.withMode(CreateMode.PERSISTENT)//指定节点类型.forPath("/my/path", "10".getBytes());//增byte[] dataBytes = client.getData().forPath("/my/path");//查System.out.println(new String(dataBytes));client.setData().forPath("/my/path", "11".getBytes());//改dataBytes = client.getData().forPath("/my/path");System.out.println(new String(dataBytes));List<String> children = client.getChildren().forPath("/my");//查System.out.println(children);client.delete().forPath("/my/path");//删Thread.sleep(Integer.MAX_VALUE);}
}

2.基于Curator实现集群元数据管理

Curator可以操作zk。比如自研了一套分布式系统类似于Kafka、Canal,想把集群运行的核心元数据都放到zk里去。此时就可以通过Curator创建一些znode,往里面写入对应的值。

写入的值推荐用json格式,比如Kafka就是往zk写json格式数据。这样,其他客户端在需要的时候,就可以从里面读取出集群元数据了。

3.基于Curator实现HA主备自动切换

HDFS、Kafka、Canal都使用了zk进行Leader选举,所以可以基于Curator实现HA主备自动切换。

HDFS的NameNode是可以部署HA架构的,有主备两台机器。如果主机器宕机了,备用的机器可以感知到并选举为Leader,这样备用的机器就可以作为新的NameNode对外提供服务。

Kafka里的Controller负责管理整个集群的协作,Kafka中任何一个Broker都可以变成Controller,类似于Leader的角色。

Canal也会部署主备两台机器,主机器挂掉了,备用机器就可以跟上去。

4.基于Curator实现Leader选举

(1)Curator实现Leader选举的第一种方式之LeaderLatch

(2)Curator实现Leader选举的第二种方式之LeaderSelector

(1)Curator实现Leader选举的第一种方式之LeaderLatch

通过Curator的LeaderLatch来实现Leader选举:

public class LeaderLatchDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();//"/leader/latch"这其实是一个znode顺序节点LeaderLatch leaderLatch = new LeaderLatch(client, "/leader/latch");leaderLatch.start();leaderLatch.await();//直到等待他成为Leader再往后执行//类似于HDFS里,两台机器,其中一台成为了Leader就开始工作//另外一台机器可以通过await阻塞在这里,直到Leader挂了,自己就会成为Leader继续工作Boolean hasLeaderShip = leaderLatch.hasLeadership();//判断是否成为LeaderSystem.out.println("是否成为leader:" + hasLeaderShip);Thread.sleep(Integer.MAX_VALUE);}
}

(2)Curator实现Leader选举的第二种方式之LeaderSelector

通过Curator的LeaderSelector来实现Leader选举如下:其中,LeaderSelector有两个监听器,可以关注连接状态。

public class LeaderSelectorDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();LeaderSelector leaderSelector = new LeaderSelector(client,"/leader/election",new LeaderSelectorListener() {public void takeLeadership(CuratorFramework curatorFramework) throws Exception {System.out.println("你已经成为了Leader......");//在这里干Leader所有的事情,此时方法不能退出Thread.sleep(Integer.MAX_VALUE);}public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {System.out.println("连接状态的变化,已经不是Leader......");if (connectionState.equals(ConnectionState.LOST)) {throw new CancelLeadershipException();}}});leaderSelector.start();//尝试和其他节点在节点"/leader/election"上进行竞争成为LeaderThread.sleep(Integer.MAX_VALUE);}
}

5.基于Curator实现的分布式Barrier

(1)分布式Barrier

(2)分布式双重Barrier

(1)分布式Barrier

很多台机器都可以创建一个Barrier,此时它们都被阻塞了。除非满足一个条件(setBarrier()或removeBarrier()),才能不再阻塞它们。

//DistributedBarrier
public class DistributedBarrierDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();DistributedBarrier barrier = new DistributedBarrier(client, "/barrier");barrier.waitOnBarrier();}
}

(2)分布式双重Barrier

//DistributedDoubleBarrier
public class DistributedDoubleBarrierDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();DistributedDoubleBarrier doubleBarrier = new DistributedDoubleBarrier(client, "/barrier/double", 10);doubleBarrier.enter();//每台机器都会阻塞在enter这里//直到10台机器都调用了enter,就会从enter这里往下执行//此时可以做一些计算任务doubleBarrier.leave();//每台机器都会阻塞在leave这里,直到10台机器都调用了leave//此时就可以继续往下执行}
}

6.基于Curator实现分布式计数器

如果真的要实现分布式计数器,最好用Redis来实现。因为Redis的并发量更高,性能更好,功能更加的强大,而且还可以使用lua脚本嵌入进去实现复杂的业务逻辑。但是Redis天生的异步同步机制,存在机器宕机导致的数据不同步风险。然而zk在ZAB协议下的数据同步机制,则不会出现宕机导致数据不同步的问题。

//SharedCount:通过一个节点的值来实现
public class SharedCounterDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();SharedCount sharedCount = new SharedCount(client, "/shared/count", 0);sharedCount.start();sharedCount.addListener(new SharedCountListener() {public void countHasChanged(SharedCountReader sharedCountReader, int i) throws Exception {System.out.println("分布式计数器变化了......");}public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {System.out.println("连接状态变化了.....");}});Boolean result = sharedCount.trySetCount(1);System.out.println(sharedCount.getCount());}
}

7.基于Curator实现zk的节点和子节点监听机制

(1)基于Curator实现zk的子节点监听机制

(2)基于Curator实现zk的节点数据监听机制

我们使用zk主要用于:

一.对元数据进行增删改查、监听元数据的变化

二.进行Leader选举

有三种类型的节点可以监听:

一.子节点监听PathCache

二.节点监听NodeCache

三.整个节点以下的树监听TreeCache

(1)基于Curator实现zk的子节点监听机制

下面是PathCache实现的子节点监听示例:

public class PathCacheDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/cluster", true);//cache就是把zk里的数据缓存到客户端里来//可以针对这个缓存的数据加监听器,去观察zk里的数据的变化pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {}});pathChildrenCache.start();}
}

(2)基于Curator实现zk的节点数据监听机制

下面是NodeCache实现的节点监听示例:

public class NodeCacheDemo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);final CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 3000, retryPolicy);client.start();final NodeCache nodeCache = new NodeCache(client, "/cluster");nodeCache.getListenable().addListener(new NodeCacheListener() {public void nodeChanged() throws Exception {Stat stat = client.checkExists().forPath("/cluster");if (stat == null) {} else {nodeCache.getCurrentData();}}});nodeCache.start();}
}

8.基于Curator创建客户端实例的源码分析

(1)创建CuratorFramework实例使用了构造器模式

(2)创建CuratorFramework实例会初始化CuratorZooKeeperClient实例

(1)创建CuratorFramework实例使用了构造器模式

CuratorFrameworkFactory.newClient()方法使用了构造器模式。首先通过builder()方法创建出Builder实例对象,然后把参数都设置成Builder实例对象的属性,最后通过build()方法把Builder实例对象传入目标类的构造方法中。

public class Demo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",//zk的地址5000,//客户端和zk的心跳超时时间,超过该时间没心跳,Session就会被断开3000,//连接zk时的超时时间retryPolicy);client.start();System.out.println("已经启动Curator客户端");}
}public class CuratorFrameworkFactory {//创建CuratorFramework实例使用了构造器模式public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy) {return builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).build();}...public static Builder builder() {return new Builder();}public static class Builder {...private EnsembleProvider ensembleProvider;private int sessionTimeoutMs = DEFAULT_SESSION_TIMEOUT_MS;private int connectionTimeoutMs = DEFAULT_CONNECTION_TIMEOUT_MS;private RetryPolicy retryPolicy;...public Builder connectString(String connectString) {ensembleProvider = new FixedEnsembleProvider(connectString);return this;}public Builder sessionTimeoutMs(int sessionTimeoutMs) {this.sessionTimeoutMs = sessionTimeoutMs;return this;}public Builder connectionTimeoutMs(int connectionTimeoutMs) {this.connectionTimeoutMs = connectionTimeoutMs;return this;}public Builder retryPolicy(RetryPolicy retryPolicy) {this.retryPolicy = retryPolicy;return this;}...public CuratorFramework build() {return new CuratorFrameworkImpl(this);}}...
}public class CuratorFrameworkImpl implements CuratorFramework {...public CuratorFrameworkImpl(CuratorFrameworkFactory.Builder builder) {ZookeeperFactory localZookeeperFactory = makeZookeeperFactory(builder.getZookeeperFactory());this.client = new CuratorZookeeperClient(localZookeeperFactory,builder.getEnsembleProvider(),builder.getSessionTimeoutMs(),builder.getConnectionTimeoutMs(),builder.getWaitForShutdownTimeoutMs(),new Watcher() {//这里注册了一个zk的watcher@Overridepublic void process(WatchedEvent watchedEvent) {CuratorEvent event = new CuratorEventImpl(CuratorFrameworkImpl.this, CuratorEventType.WATCHED, watchedEvent.getState().getIntValue(), unfixForNamespace(watchedEvent.getPath()), null, null, null, null, null, watchedEvent, null, null);processEvent(event);}},builder.getRetryPolicy(),builder.canBeReadOnly(),builder.getConnectionHandlingPolicy());...}...
}

(2)创建CuratorFramework实例会初始化CuratorZooKeeperClient实例

CuratorFramework实例代表了一个zk客户端,CuratorFramework初始化时会初始化一个CuratorZooKeeperClient实例。

CuratorZooKeeperClient是Curator封装ZooKeeper的客户端。

初始化CuratorZooKeeperClient时会传入一个Watcher监听器。

所以CuratorFrameworkFactory的newClient()方法的主要工作是:初始化CuratorFramework -> 初始化CuratorZooKeeperClient -> 初始化ZookeeperFactory + 注册一个Watcher。

客户端发起与zk的连接,以及注册Watcher监听器,则是由CuratorFramework的start()方法触发的。

9.Curator启动时是如何跟zk建立连接的

ConnectionStateManager的start()方法会启动一个线程处理eventQueue。eventQueue里存放了与zk的网络连接变化事件,eventQueue收到这种事件便会通知ConnectionStateListener。

CuratorZookeeperClient的start()方法会初始化好原生zk客户端,和zk服务器建立一个TCP长连接,而且还会注册一个ConnectionState类型的Watcher监听器,以便能收到zk服务端发送的通知事件。

public class CuratorFrameworkImpl implements CuratorFramework {private final CuratorZookeeperClient client;private final ConnectionStateManager connectionStateManager;private volatile ExecutorService executorService;...public CuratorFrameworkImpl(CuratorFrameworkFactory.Builder builder) {...this.client = new CuratorZookeeperClient(...);connectionStateManager = new ConnectionStateManager(this, builder.getThreadFactory(), builder.getSessionTimeoutMs(), builder.getConnectionHandlingPolicy().getSimulatedSessionExpirationPercent(), builder.getConnectionStateListenerDecorator());...}...@Overridepublic void start() {log.info("Starting");if (!state.compareAndSet(CuratorFrameworkState.LATENT, CuratorFrameworkState.STARTED)) {throw new IllegalStateException("Cannot be started more than once");}...//1.启动一个线程监听和zk网络连接的变化事件connectionStateManager.start();//2.添加一个监听器监听和zk网络连接的变化final ConnectionStateListener listener = new ConnectionStateListener() {@Overridepublic void stateChanged(CuratorFramework client, ConnectionState newState) {if (ConnectionState.CONNECTED == newState || ConnectionState.RECONNECTED == newState) {logAsErrorConnectionErrors.set(true);}}@Overridepublic boolean doNotDecorate() {return true;}};this.getConnectionStateListenable().addListener(listener);//3.创建原生zk客户端client.start();//4.创建一个线程池,执行后台的操作executorService = Executors.newSingleThreadScheduledExecutor(threadFactory);executorService.submit(new Callable<Object>() {@Overridepublic Object call() throws Exception {backgroundOperationsLoop();return null;}});if (ensembleTracker != null) {ensembleTracker.start();}log.info(schemaSet.toDocumentation());}...
}public class ConnectionStateManager implements Closeable {private final ExecutorService service;private final BlockingQueue<ConnectionState> eventQueue = new ArrayBlockingQueue<ConnectionState>(QUEUE_SIZE);...public ConnectionStateManager(CuratorFramework client, ThreadFactory threadFactory, int sessionTimeoutMs, int sessionExpirationPercent, ConnectionStateListenerDecorator connectionStateListenerDecorator) {...service = Executors.newSingleThreadExecutor(threadFactory);...}...public void start() {Preconditions.checkState(state.compareAndSet(State.LATENT, State.STARTED), "Cannot be started more than once");//启动一个线程service.submit(new Callable<Object>() {@Overridepublic Object call() throws Exception {processEvents();return null;}});}private void processEvents() {while (state.get() == State.STARTED) {int useSessionTimeoutMs = getUseSessionTimeoutMs();long elapsedMs = startOfSuspendedEpoch == 0 ? useSessionTimeoutMs / 2 : System.currentTimeMillis() - startOfSuspendedEpoch;long pollMaxMs = useSessionTimeoutMs - elapsedMs;final ConnectionState newState = eventQueue.poll(pollMaxMs, TimeUnit.MILLISECONDS);if (newState != null) {if (listeners.size() == 0) {log.warn("There are no ConnectionStateListeners registered.");}listeners.forEach(listener -> listener.stateChanged(client, newState));} else if (sessionExpirationPercent > 0) {synchronized(this) {checkSessionExpiration();}}}}...
}public class CuratorZookeeperClient implements Closeable {private final ConnectionState state;...public CuratorZookeeperClient(ZookeeperFactory zookeeperFactory, EnsembleProvider ensembleProvider,int sessionTimeoutMs, int connectionTimeoutMs, int waitForShutdownTimeoutMs, Watcher watcher,RetryPolicy retryPolicy, boolean canBeReadOnly, ConnectionHandlingPolicy connectionHandlingPolicy) {...state = new ConnectionState(zookeeperFactory, ensembleProvider, sessionTimeoutMs, connectionTimeoutMs, watcher, tracer, canBeReadOnly, connectionHandlingPolicy);...}...public void start() throws Exception {log.debug("Starting");if (!started.compareAndSet(false, true)) {throw new IllegalStateException("Already started");}state.start();}...
}class ConnectionState implements Watcher, Closeable {private final HandleHolder zooKeeper;ConnectionState(ZookeeperFactory zookeeperFactory, EnsembleProvider ensembleProvider, int sessionTimeoutMs, int connectionTimeoutMs, Watcher parentWatcher, AtomicReference<TracerDriver> tracer, boolean canBeReadOnly, ConnectionHandlingPolicy connectionHandlingPolicy) {this.ensembleProvider = ensembleProvider;this.sessionTimeoutMs = sessionTimeoutMs;this.connectionTimeoutMs = connectionTimeoutMs;this.tracer = tracer;this.connectionHandlingPolicy = connectionHandlingPolicy;if (parentWatcher != null) {parentWatchers.offer(parentWatcher);}//把自己作为Watcher注册给HandleHolderzooKeeper = new HandleHolder(zookeeperFactory, this, ensembleProvider, sessionTimeoutMs, canBeReadOnly);}...void start() throws Exception {log.debug("Starting");ensembleProvider.start();reset();}synchronized void reset() throws Exception {log.debug("reset");instanceIndex.incrementAndGet();isConnected.set(false);connectionStartMs = System.currentTimeMillis();//创建客户端与zk的连接zooKeeper.closeAndReset();zooKeeper.getZooKeeper();//initiate connection}...
}class HandleHolder {private final ZookeeperFactory zookeeperFactory;private final Watcher watcher;private final EnsembleProvider ensembleProvider;private final int sessionTimeout;private final boolean canBeReadOnly;private volatile Helper helper;...HandleHolder(ZookeeperFactory zookeeperFactory, Watcher watcher, EnsembleProvider ensembleProvider, int sessionTimeout, boolean canBeReadOnly) {this.zookeeperFactory = zookeeperFactory;this.watcher = watcher;this.ensembleProvider = ensembleProvider;this.sessionTimeout = sessionTimeout;this.canBeReadOnly = canBeReadOnly;}private interface Helper {ZooKeeper getZooKeeper() throws Exception;String getConnectionString();int getNegotiatedSessionTimeoutMs();}ZooKeeper getZooKeeper() throws Exception {return (helper != null) ? helper.getZooKeeper() : null;}void closeAndReset() throws Exception {internalClose(0);helper = new Helper() {private volatile ZooKeeper zooKeeperHandle = null;private volatile String connectionString = null;@Overridepublic ZooKeeper getZooKeeper() throws Exception {synchronized(this) {if (zooKeeperHandle == null) {connectionString = ensembleProvider.getConnectionString();//创建和zk的连接,初始化变量zooKeeperHandlezooKeeperHandle = zookeeperFactory.newZooKeeper(connectionString, sessionTimeout, watcher, canBeReadOnly);}...return zooKeeperHandle;}}@Overridepublic String getConnectionString() {return connectionString;}@Overridepublic int getNegotiatedSessionTimeoutMs() {return (zooKeeperHandle != null) ? zooKeeperHandle.getSessionTimeout() : 0;}};}...
}//创建客户端与zk的连接
public class DefaultZookeeperFactory implements ZookeeperFactory {@Overridepublic ZooKeeper newZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) throws Exception {return new ZooKeeper(connectString, sessionTimeout, watcher, canBeReadOnly);}
}

10.基于Curator进行增删改查节点的源码分析

(1)基于Curator创建znode节点

(2)基于Curator查询znode节点

(3)基于Curator修改znode节点

(4)基于Curator删除znode节点

Curator的CURD操作,底层都是通过调用zk原生的API来完成的。

(1)基于Curator创建znode节点

创建节点也使用了构造器模式:首先通过CuratorFramework的create()方法创建一个CreateBuilder实例,然后通过CreateBuilder的withMode()等方法设置CreateBuilder的变量,最后通过CreateBuilder的forPath()方法 + 重试调用来创建znode节点。

创建节点时会调用CuratorFramework的getZooKeeper()方法获取zk客户端实例,之后就是通过原生zk客户端的API去创建节点了。

public class Demo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",//zk的地址5000,//客户端和zk的心跳超时时间,超过该时间没心跳,Session就会被断开3000,//连接zk时的超时时间retryPolicy);client.start();System.out.println("已经启动Curator客户端");//创建节点client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/my/path", "100".getBytes());}
}public class CuratorFrameworkImpl implements CuratorFramework {...@Overridepublic CreateBuilder create() {checkState();return new CreateBuilderImpl(this);}...
}public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, BackgroundOperation<PathAndBytes>, ErrorListenerPathAndBytesable<String> { private final CuratorFrameworkImpl client;private CreateMode createMode;private Backgrounding backgrounding;private boolean createParentsIfNeeded;...CreateBuilderImpl(CuratorFrameworkImpl client) {this.client = client;createMode = CreateMode.PERSISTENT;backgrounding = new Backgrounding();acling = new ACLing(client.getAclProvider());createParentsIfNeeded = false;createParentsAsContainers = false;compress = false;setDataIfExists = false;storingStat = null;ttl = -1;}@Overridepublic String forPath(final String givenPath, byte[] data) throws Exception {if (compress) {data = client.getCompressionProvider().compress(givenPath, data);}final String adjustedPath = adjustPath(client.fixForNamespace(givenPath, createMode.isSequential()));List<ACL> aclList = acling.getAclList(adjustedPath);client.getSchemaSet().getSchema(givenPath).validateCreate(createMode, givenPath, data, aclList);String returnPath = null;if (backgrounding.inBackground()) {pathInBackground(adjustedPath, data, givenPath);} else {//创建节点String path = protectedPathInForeground(adjustedPath, data, aclList);returnPath = client.unfixForNamespace(path);}return returnPath;}private String protectedPathInForeground(String adjustedPath, byte[] data, List<ACL> aclList) throws Exception {return pathInForeground(adjustedPath, data, aclList);}private String pathInForeground(final String path, final byte[] data, final List<ACL> aclList) throws Exception {OperationTrace trace = client.getZookeeperClient().startAdvancedTracer("CreateBuilderImpl-Foreground");final AtomicBoolean firstTime = new AtomicBoolean(true);//重试调用String returnPath = RetryLoop.callWithRetry(client.getZookeeperClient(),new Callable<String>() {@Overridepublic String call() throws Exception {boolean localFirstTime = firstTime.getAndSet(false) && !debugForceFindProtectedNode;protectedMode.checkSetSessionId(client, createMode);String createdPath = null;if (!localFirstTime && protectedMode.doProtected()) {debugForceFindProtectedNode = false;createdPath = findProtectedNodeInForeground(path);}if (createdPath == null) {//在创建znode节点的时候,首先会调用CuratorFramework.getZooKeeper()获取zk客户端实例//之后就是通过原生zk客户端的API去创建节点了try {if (client.isZk34CompatibilityMode()) {createdPath = client.getZooKeeper().create(path, data, aclList, createMode);} else {createdPath = client.getZooKeeper().create(path, data, aclList, createMode, storingStat, ttl);}} catch (KeeperException.NoNodeException e) {if (createParentsIfNeeded) {//这就是级联创建节点的实现ZKPaths.mkdirs(client.getZooKeeper(), path, false, acling.getACLProviderForParents(), createParentsAsContainers);if (client.isZk34CompatibilityMode()) {createdPath = client.getZooKeeper().create(path, data, acling.getAclList(path), createMode);} else {createdPath = client.getZooKeeper().create(path, data, acling.getAclList(path), createMode, storingStat, ttl);}} else {throw e;}} catch (KeeperException.NodeExistsException e) {if (setDataIfExists) {Stat setStat = client.getZooKeeper().setData(path, data, setDataIfExistsVersion);if (storingStat != null) {DataTree.copyStat(setStat, storingStat);}createdPath = path;} else {throw e;}}}if (failNextCreateForTesting) {failNextCreateForTesting = false;throw new KeeperException.ConnectionLossException();}return createdPath;}});trace.setRequestBytesLength(data).setPath(path).commit();return returnPath;}...
}public class CuratorFrameworkImpl implements CuratorFramework {private final CuratorZookeeperClient client;public CuratorFrameworkImpl(CuratorFrameworkFactory.Builder builder) {ZookeeperFactory localZookeeperFactory = makeZookeeperFactory(builder.getZookeeperFactory());this.client = new CuratorZookeeperClient(localZookeeperFactory,builder.getEnsembleProvider(),builder.getSessionTimeoutMs(),builder.getConnectionTimeoutMs(),builder.getWaitForShutdownTimeoutMs(),new Watcher() {...},builder.getRetryPolicy(),builder.canBeReadOnly(),builder.getConnectionHandlingPolicy());...}...ZooKeeper getZooKeeper() throws Exception {return client.getZooKeeper();}...
}public class CuratorZookeeperClient implements Closeable {private final ConnectionState state;...public ZooKeeper getZooKeeper() throws Exception {Preconditions.checkState(started.get(), "Client is not started");return state.getZooKeeper();}...
}class ConnectionState implements Watcher, Closeable {private final HandleHolder zooKeeper;...ZooKeeper getZooKeeper() throws Exception {if (SessionFailRetryLoop.sessionForThreadHasFailed()) {throw new SessionFailRetryLoop.SessionFailedException();}Exception exception = backgroundExceptions.poll();if (exception != null) {new EventTrace("background-exceptions", tracer.get()).commit();throw exception;}boolean localIsConnected = isConnected.get();if (!localIsConnected) {checkTimeouts();}//通过HandleHolder获取ZooKeeper实例return zooKeeper.getZooKeeper();}...
}

(2)基于Curator查询znode节点

查询节点也使用了构造器模式:首先通过CuratorFramework的getData()方法创建一个GetDataBuilder实例,然后通过GetDataBuilder的forPath()方法 + 重试调用来查询znode节点。

public class Demo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",//zk的地址5000,//客户端和zk的心跳超时时间,超过该时间没心跳,Session就会被断开3000,//连接zk时的超时时间retryPolicy);client.start();System.out.println("已经启动Curator客户端");//查询节点byte[] dataBytes = client.getData().forPath("/my/path");System.out.println(new String(dataBytes));//查询子节点List<String> children = client.getChildren().forPath("/my");System.out.println(children);}
}public class CuratorFrameworkImpl implements CuratorFramework {...@Overridepublic GetDataBuilder getData() {checkState();return new GetDataBuilderImpl(this);}@Overridepublic GetChildrenBuilder getChildren() {checkState();return new GetChildrenBuilderImpl(this);}...
}public class GetDataBuilderImpl implements GetDataBuilder, BackgroundOperation<String>, ErrorListenerPathable<byte[]> {private final CuratorFrameworkImpl  client;...@Overridepublic byte[] forPath(String path) throws Exception {client.getSchemaSet().getSchema(path).validateWatch(path, watching.isWatched() || watching.hasWatcher());path = client.fixForNamespace(path);byte[] responseData = null;if (backgrounding.inBackground()) {client.processBackgroundOperation(new OperationAndData<String>(this, path, backgrounding.getCallback(), null, backgrounding.getContext(), watching), null);} else {//查询节点responseData = pathInForeground(path);}return responseData;}private byte[] pathInForeground(final String path) throws Exception {OperationTrace trace = client.getZookeeperClient().startAdvancedTracer("GetDataBuilderImpl-Foreground");//重试调用byte[] responseData = RetryLoop.callWithRetry(client.getZookeeperClient(),new Callable<byte[]>() {@Overridepublic byte[] call() throws Exception {byte[] responseData;//通过CuratorFramework获取原生zk客户端实例,然后调用其getData()获取节点if (watching.isWatched()) {responseData = client.getZooKeeper().getData(path, true, responseStat);} else {responseData = client.getZooKeeper().getData(path, watching.getWatcher(path), responseStat);watching.commitWatcher(KeeperException.NoNodeException.Code.OK.intValue(), false);}return responseData;}});trace.setResponseBytesLength(responseData).setPath(path).setWithWatcher(watching.hasWatcher()).setStat(responseStat).commit();return decompress ? client.getCompressionProvider().decompress(path, responseData) : responseData;}...
}

(3)基于Curator修改znode节点

修改节点也使用了构造器模式:首先通过CuratorFramework的setData()方法创建一个SetDataBuilder实例,然后通过SetDataBuilder的forPath()方法 + 重试调用来修改znode节点。

public class Demo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",//zk的地址5000,//客户端和zk的心跳超时时间,超过该时间没心跳,Session就会被断开3000,//连接zk时的超时时间retryPolicy);client.start();System.out.println("已经启动Curator客户端");//修改节点client.setData().forPath("/my/path", "110".getBytes());byte[] dataBytes = client.getData().forPath("/my/path");System.out.println(new String(dataBytes));}
}public class CuratorFrameworkImpl implements CuratorFramework {...@Overridepublic SetDataBuilder setData() {checkState();return new SetDataBuilderImpl(this);}...
}public class SetDataBuilderImpl implements SetDataBuilder, BackgroundOperation<PathAndBytes>, ErrorListenerPathAndBytesable<Stat> {private final CuratorFrameworkImpl client;...@Overridepublic Stat forPath(String path, byte[] data) throws Exception {client.getSchemaSet().getSchema(path).validateGeneral(path, data, null);if (compress) {data = client.getCompressionProvider().compress(path, data);}path = client.fixForNamespace(path);Stat resultStat = null;if (backgrounding.inBackground()) {client.processBackgroundOperation(new OperationAndData<>(this, new PathAndBytes(path, data), backgrounding.getCallback(), null, backgrounding.getContext(), null), null);} else {//修改节点resultStat = pathInForeground(path, data);}return resultStat;}private Stat pathInForeground(final String path, final byte[] data) throws Exception {OperationTrace trace = client.getZookeeperClient().startAdvancedTracer("SetDataBuilderImpl-Foreground");//重试调用Stat resultStat = RetryLoop.callWithRetry(client.getZookeeperClient(),new Callable<Stat>() {@Overridepublic Stat call() throws Exception {//通过CuratorFramework获取原生zk客户端实例,然后调用其setData()修改节点return client.getZooKeeper().setData(path, data, version);}});trace.setRequestBytesLength(data).setPath(path).setStat(resultStat).commit();return resultStat;}...
}

(4)基于Curator删除znode节点

删除节点也使用了构造器模式:首先通过CuratorFramework的delete()方法创建一个DeleteBuilder实例,然后通过DeleteBuilder的forPath()方法 + 重试调用来删除znode节点。

public class Demo {public static void main(String[] args) throws Exception {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",//zk的地址5000,//客户端和zk的心跳超时时间,超过该时间没心跳,Session就会被断开3000,//连接zk时的超时时间retryPolicy);client.start();System.out.println("已经启动Curator客户端");//删除节点client.delete().forPath("/my/path");}
}public class CuratorFrameworkImpl implements CuratorFramework {...@Overridepublic DeleteBuilder delete() {checkState();return new DeleteBuilderImpl(this);}...
}public class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>, ErrorListenerPathable<Void> {private final CuratorFrameworkImpl client;...@Overridepublic Void forPath(String path) throws Exception {client.getSchemaSet().getSchema(path).validateDelete(path);final String unfixedPath = path;path = client.fixForNamespace(path);if (backgrounding.inBackground()) {OperationAndData.ErrorCallback<String> errorCallback = null;if (guaranteed) {errorCallback = new OperationAndData.ErrorCallback<String>() {@Overridepublic void retriesExhausted(OperationAndData<String> operationAndData) {client.getFailedDeleteManager().addFailedOperation(unfixedPath);}};}client.processBackgroundOperation(new OperationAndData<String>(this, path, backgrounding.getCallback(), errorCallback, backgrounding.getContext(), null), null);} else {//删除节点pathInForeground(path, unfixedPath);}return null;}private void pathInForeground(final String path, String unfixedPath) throws Exception {OperationTrace trace = client.getZookeeperClient().startAdvancedTracer("DeleteBuilderImpl-Foreground");//重试调用RetryLoop.callWithRetry(client.getZookeeperClient(),new Callable<Void>() {@Overridepublic Void call() throws Exception {try {//通过CuratorFramework获取原生zk客户端实例,然后调用其delete()删除节点client.getZooKeeper().delete(path, version);} catch (KeeperException.NoNodeException e) {if (!quietly) {throw e;}} catch (KeeperException.NotEmptyException e) {if (deletingChildrenIfNeeded) {ZKPaths.deleteChildren(client.getZooKeeper(), path, true);} else {throw e;}}return null;}});trace.setPath(path).commit();}
}

相关文章:

zk基础—5.Curator的使用与剖析一

大纲 1.基于Curator进行基本的zk数据操作 2.基于Curator实现集群元数据管理 3.基于Curator实现HA主备自动切换 4.基于Curator实现Leader选举 5.基于Curator实现分布式Barrier 6.基于Curator实现分布式计数器 7.基于Curator实现zk的节点和子节点监听机制 8.基于Curator创…...

VSCode中结合DeepSeek使用Cline插件的感受

前言 听网上有传言说AI智能插件Cline非常的好用&#xff0c;而且相对Cursor而言还是免费的&#xff0c;捆绑的大模型选择也比较的广泛。所以&#xff0c;特意安装试用了一下。 我的采用IDE是VSCode&#xff0c;捆绑的大模型是最近比较火的DeepSeek。总体使用下来感觉非常的棒。…...

安卓开发工程师-Java 常用数据结构

1. Java 中的数组和集合有什么区别&#xff1f; 数组&#xff1a; 长度固定&#xff1a;一旦声明&#xff0c;长度不能改变。类型单一&#xff1a;只能存储相同类型的元素。存储效率高&#xff1a;底层是连续的内存空间&#xff0c;访问速度快。示例代码&#xff1a; int[] …...

thinkphp8.0上传图片到阿里云对象存储(oss)

1、开通oss,并获取accessKeyId、accessKeySecret <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><tit…...

Angular 2 模板语法详解

Angular 2 模板语法详解 引言 Angular 2 作为一款强大的前端框架,以其组件化的开发模式和高效的性能被众多开发者所青睐。模板语法是Angular 2中用于定义组件UI的关键部分。本文将详细介绍Angular 2的模板语法,帮助开发者更好地理解和运用这一功能。 模板语法概述 Angula…...

进行性核上性麻痹护理攻略:多维度守护健康

日常起居护理 保证患者居住环境安全&#xff0c;清除地面障碍物&#xff0c;避免患者跌倒。家具摆放固定且合理&#xff0c;方便患者活动。为患者准备宽松、舒适、易于穿脱的衣物&#xff0c;减轻穿衣时的困难。在饮食上&#xff0c;提供富含营养、易于吞咽的食物&#xff0c;…...

MessageQueue --- RabbitMQ WorkQueue

MessageQueue --- RabbitMQ WorkQueue 什么是WorkQueue如何分发RoundRobinFair dispatch (Prefetch) --- 能者多劳 什么是WorkQueue Work queues&#xff0c;任务模型。简单来说就是让多个消费者绑定到一个队列&#xff0c;共同消费队列中的消息。当消息处理比较耗时的时候&…...

Redis内存碎片详解!

目录 一、 什么是内存碎片&#xff1f;&#x1f914;二、 为什么 Redis 会有内存碎片呢&#xff1f;&#x1f937;‍♀️三、 如何查看 Redis 内存碎片的信息&#xff1f;&#x1f50d;四、 如何清理 Redis 内存碎片&#xff1f;&#x1f9f9;五、总结&#x1f4dd; &#x1f3…...

如何使用 Nginx 代理 Easysearch 服务

Nginx 是一个高性能的 HTTP 服务器和反向代理服务器&#xff0c;广泛用于负载均衡、缓存、SSL 终端和服务代理等场景。本篇将尝试使用 Nginx 代理 Easysearch 服务&#xff0c;方法同样适用于 Elasticsearch 和 Opensearch。 测试环境 Easysearch 集群版本为 1.10.0&#xff…...

用python输出OLED字模库的符号

提示&#xff1a;博主是小白&#xff0c;如有不足&#xff0c;望海涵和指出 在单片机上练习使用OLED显示屏时&#xff0c;可以看到有个OLED字模库 本文用python将这些字符打印出来&#xff0c;代码如下&#xff08;本文只适用与128*64的OLED&#xff0c;如果是其它OLED&#xf…...

【java】Class.newInstance()

在 Java 中&#xff0c;Class.newInstance()是一个用于创建类的新实例的方法。它调用类的无参构造函数来创建对象。然而&#xff0c;从 Java 9 开始&#xff0c;Class.newInstance()方法已经被标记为废弃&#xff0c;推荐使用其他替代方法。 Class.newInstance()的使用 Class.…...

Apache Arrow 使用

下述操作参考 Building Arrow C — Apache Arrow v20.0.0.dev267 安装依赖组件 sudo apt-get install \build-essential \ninja-build \cmake 下载源码 git clone --recursive --shallow-submodules gitgithub.com:apache/arrow.git 配置 创建build目录并且进入 mkdir a…...

第二届图像处理与人工智能国际学术会议(ICIPAI2025)

重要信息 时间&#xff1a;2025年4月18日-20日 地点&#xff1a;吉林-长春&#xff08;线上线下结合&#xff09; 官网&#xff1a;www.icipai.org 简介&#xff08;部分&#xff09; 主题 其他 图像处理与人工智能&#xff08;Image Processing & Artificial Intell…...

Kafka 消息堆积的原因有哪些?

Kafka 产生消息堆积的本质原因是&#xff1a; ⚠️ “消费速度 < 生产速度”&#xff0c;也就是&#xff1a;写入太快&#xff0c;处理太慢。 下面我从实际场景出发&#xff0c;帮你梳理出常见的几种堆积情况&#xff0c;结合原因和例子&#xff0c;便于你对号入座排查问题 …...

解决cline等免费使用deepseek模型的问题

OpenAI、OpenRouter、Claude等都无法在国内免费正常使用&#xff0c;cline作为在vscode中应对cursor比较好的替代方案&#xff0c;怎么使用免费Deepseek&#xff0c;最核心的是在点击模型名称打开配置以下几项&#xff1a; 1、打开VSCode左侧的Cline\Roo Cline插件面板 2、点…...

ROS多设备交互

ROS多设备连接同一个Master&#xff1a;ROS Master多设备连接-CSDN博客 在多个PC端连接同一个ROS Master后&#xff0c;接下来就可以实现不同设备之间的话题交流&#xff0c;Master主机端启动不同PC端的功能包等功能了 尽管多个PC端拥有不同的ROS工作空间&#xff0c;但是只要…...

浅谈 MVVM 模式

MVVM&#xff08;Model-View-ViewModel&#xff09; 是一种软件架构设计模式&#xff0c;旨在将用户界面&#xff08;UI&#xff09;与业务逻辑分离&#xff0c;从而提高代码的可维护性和可测试性。它在现代前端开发和桌面应用开发中得到了广泛应用&#xff0c;尤其是在构建复杂…...

flutter点击事件教程

在 Flutter 中&#xff0c;处理点击事件是非常常见的操作。Flutter 提供了多种方式来实现用户交互&#xff0c;比如按钮点击、手势检测等。下面是一个详细的教程&#xff0c;帮助你理解如何在 Flutter 中实现点击事件。 一、使用 onPressed 实现按钮点击事件 Flutter 提供了 E…...

[SAP SD] 常用事务码

在SAP系统中&#xff0c;事务码(Transaction Code)是一个具有特定功能的代码标识符&#xff0c;用于快速调用和执行SAP系统内的各种业务模块的功能 /NT-code: 关闭当前业务窗口&#xff0c;退回到SAP初始界面&#xff0c;进入对应的T-Code窗口 /OT-code: 新建SAP GUI窗口&…...

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 的未来:从微服务到云原生的演进

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、引子&…...

保留格式地一键翻译英文ppt

我手头上有一个贝叶斯推断的英文ppt&#xff0c;假如我想翻译成中文&#xff0c;整合起来进行pre&#xff0c;你会怎么做&#xff1f; 1&#xff0c;复制粘贴型&#xff1a; 在翻译软件与源文件ppt之间不断流转&#xff0c;效率太低 2&#xff0c;office ppt自带翻译插入整合…...

晶晨S905L3S/S905L3SB_安卓9.0_10秒开机_通刷-线刷固件包

晶晨S905L3S&#xff0f;S905L3SB_安卓9.0_10秒开机_通刷-线刷固件包 线刷方法&#xff1a;&#xff08;新手参考借鉴一下&#xff09; 使用晶晨刷机工具USB_Burning_Tool进行刷机&#xff1b;请使用Amlogic USB Burning Tool v2.2.5或v2.2.7&#xff08;晶晨线刷烧录工具v2.2…...

Android Transition转场动效使用全解析

Transition的使用和原理 项目效果 1. 简述 Android 4.4.2 中引入了 Transition 过渡动画&#xff0c;不过功能比较简单。在 Android 5.0 的 Material Design 中引入更完整和强大的 Transition 框架。通过Transition可以实现&#xff1a; 同一个页面中的场景过渡动画Activit…...

第九章Python语言高阶加强-面向对象篇

目录 一.初始对象 二.成员方法 1.成员变量和成员方法 三.类和对象 四.构造方法 五.其他内置方法&#xff08;魔术方法&#xff09; 1.__str__字符串方法 2.__lt__小于符号比较方法 3.__le__小于等于比较符号方法 4.__eq__比较运算符实现方法 六.封装 七.继承 1.继承…...

AI重构SEO关键词智能布局

内容概要 随着人工智能技术在搜索引擎优化领域的深入发展&#xff0c;AI驱动的关键词智能布局正在重塑传统SEO策略的核心逻辑。通过整合自然语言处理、深度学习与语义分析技术&#xff0c;现代SEO系统已形成包含智能分词、意图解码、动态优化的三维技术框架&#xff0c;使关键…...

言同数字:法新社AFP海外新闻媒体发稿成功案例——出海品牌背书必备

作者&#xff1a;言同数字全球传播团队 一、品牌困境&#xff1a;当中国技术遇上海外认知壁垒 案例背景&#xff1a; 某中国光伏储能企业&#xff08;应保密要求匿名&#xff0c;代号"GreenTech"&#xff09;&#xff0c;其家用储能系统在欧洲市场遭遇&#xff1…...

第三章 react redux的学习之redux和react-redux,@reduxjs/toolkit依赖结合使用

redux系列文章目录 第一章 简单学习redux,单个reducer 第二章 简单学习redux,多个reducer 第四章 react-redux&#xff0c;reduxjs/toolkit依赖&#xff0c;学习 第五章 两张图告诉你redux常使用的api有哪些 前言 前面两章&#xff0c;我们是只使用的redux的依赖。 本章…...

【HTML】纯前端网页小游戏-戳破彩泡

分享一个简单有趣的网页小游戏 - 彩色泡泡爆破。玩家需要点击屏幕上随机出现的彩色泡泡来得分。 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…...

【Python使用】嘿马云课堂web完整实战项目第3篇:增加数据,修改数据【附代码文档】

教程总体简介&#xff1a;项目概述 项目背景 项目的功能构架 项目的技术架构 CMS 什么是CMS CMS需求分析与工程搭建 静态门户工程搭建 SSI服务端包含技术 页面预览开发 4 添加“页面预览”链接 页面发布 需求分析 技术方案 测试 环境搭建 数据字典 服务端 前端 数据模型 页面原…...

数据结构【栈和队列附顺序表应用算法】

栈和队列和顺序表应用算法练习 1.栈1.1概念与结构1.2栈的实现 2.队列2.1概念与结构2.2队列的实现 3.附&#xff08;顺序表应用算法&#xff09;3.1移除元素3.2删除有序数组中的重复项3.3合并两个有序数组 1.栈 1.1概念与结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只…...

Redis数据结构之String

目录 1.概述2.常见操作2.1 SET/GET2.2 MSET/MGET/MSETNX2.3 GETRANGE/SETRANGE2.4 INCR(BY)/DECR(BY)2.5 STRLEN2.6 APPEND2.7 GETSET 3.小结 1.概述 String是最常用的数据类型&#xff0c;一个key对应一个value。String是二进制安全的&#xff0c;可以包含任何数据&#xff0…...

Maven 远程仓库推送方法

步骤 1&#xff1a;配置 pom.xml 中的远程仓库地址 在项目的 pom.xml 文件中添加 distributionManagement 配置&#xff0c;指定远程仓库的 URL。 xml 复制 <project>...<distributionManagement><!-- 快照版本仓库 --><snapshotRepository><id…...

uname

在 C 语言中&#xff0c;uname 函数用于获取当前操作系统的相关信息。 它是 POSIX 标准的一部分&#xff0c;定义在 <sys/utsname.h> 头文件中。 通过调用 uname 函数&#xff0c;可以获取系统名称、节点名称&#xff08;主机名&#xff09;、操作系统版本、机器硬件架构…...

【无标题】object,wait,notifyAll

在 Java 中&#xff0c;Object类提供了wait()方法&#xff0c;用于线程间的协作和同步。wait()方法使得当前线程暂停执行&#xff0c;并释放当前对象的锁&#xff0c;直到其他线程调用该对象的notify()或notifyAll()方法将其唤醒。这是实现线程间通信和同步的重要机制之一。 w…...

【Vue】 核心特性实战解析:computed、watch、条件渲染与列表渲染

目录 一、计算属性&#xff08;computed&#xff09; ✅ 示例&#xff1a; 计算属性-methods实现&#xff1a;在插值模块里&#xff0c;实现函数的调用功能 计算属性-computed的实现&#xff1a; 计算属性-简写&#xff1a; ✅ 特点&#xff1a; ⚠️ 与 methods 的区别…...

精品可编辑PPT | 基于湖仓一体构建数据中台架构大数据湖数据仓库一体化中台解决方案

本文介绍了基于湖仓一体构建数据中台架构的技术创新与实践。它详细阐述了数据湖、数据仓库和数据中台的概念&#xff0c;分析了三者的区别与协作关系&#xff0c;指出数据湖可存储大规模结构化和非结构化数据&#xff0c;数据仓库用于高效存储和快速查询以支持决策&#xff0c;…...

基于Python网络爬虫的智能音乐可视化系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;智能音乐可视化系统当然不能排除在外。我本次开发的基于网络爬虫的智能音乐可视化系统是在实际应用和软件工程的开发原理之上&#xff0c;…...

基于STM32与应变片的协作机械臂力反馈控制系统设计与实现----2.2 机械臂控制系统硬件架构设计

2.2 机械臂控制系统硬件架构设计 一、总体架构拓扑 1.1 典型三级硬件架构 #mermaid-svg-MWmxD3zX6bu4iFCv {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MWmxD3zX6bu4iFCv .error-icon{fill:#552222;}#mermaid-s…...

在线记事本——支持Markdown

项目地址 https://github.com/Anyuersuper/CloudNotebook 百度网盘 通过网盘分享的文件&#xff1a;CloudNotebook-master.zip 链接: https://pan.baidu.com/s/1kd2qNvm0eXc6_7oYDR769A?pwdyuer 提取码: yuer &#x1f4dd; 云笔记 (Cloud Notebook) 云笔记是一个简洁、安全…...

DDPM 做了什么

本博客主要侧重点在于HOW也就是DDPM怎么做的而不是WHY为什么要这样做 那么第一个问题DDPM做了一件什么事&#xff1a;这个算法通过逐渐向原图像添加噪声来破坏图像&#xff0c;然后再学习如何从噪声成恢复图像。 第二件事如何做到的&#xff1a;通过训练一个网络&#xff0c;…...

Redis数据结构之List

目录 1.概述2.常见操作2.1 LPUSH/RPUSH/LRANGE2.2 LPOP/RPOP2.3 LINDEX2.4 LLEN2.5 LREM2.6 LTRIM2.7 RPOPLPUSH2.8 LSET2.9 LINSERT 1.概述 List是简单的字符串列表&#xff0c;单key多个value&#xff0c;按照插入顺序排序。 支持添加一个元素到列表的头部(左边)或者尾部(右…...

L2-023 图着色问题 #DFS C++邻接矩阵存图

文章目录 题目解读输入格式输出格式 思路Ac CODE 参考 题目解读 给定一个无向图V&#xff0c;询问是否可以用K种颜色为V中每一个顶点分配一种颜色&#xff0c;使得不会有两个相邻顶点具有同一种颜色 输入格式 第一行给出V,E,K&#xff0c; 分别代表无向图的顶点&#xff0c;…...

架构下的按钮效果设置

以下是一个完整的跨QML/Qt Widgets的主题方案实现&#xff0c;包含对按钮阴影的统一管理&#xff1a; 一、项目结构 Project/ ├── core/ │ ├── thememanager.h │ └── thememanager.cpp ├── widgets/ │ ├── mainwindow.h │ ├── mainwindow.cpp …...

Unhandled exception: org.apache.poi.openxml4j.exceptions.InvalidFormatException

代码在main方法里面没有报错&#xff0c;在Controller里面就报错了。 原来Controller类里面少了行代码 import org.apache.poi.openxml4j.exceptions.InvalidFormatException; 加上去就解决了。...

Vue2_Vue.js教程

目录 一、Vue.js安装 1、独立版本 2、CDN 方法 3、npm 方法 二、Vue Al编程助手 三、Vue.js目录结构 目录解析 四、Vue.js 起步 1.如何定义数据对象和方法并渲染进页面 五、Vue.js 模板语法 插值 文本_{{}} Html_v-html 指令 属性_v-bind (数据传输工具)指令 表…...

2025/4/2 心得

第一题 题目描述 给定1001个范围在[1,1000]的数字&#xff0c;保证只有1个数字重复出现2次&#xff0c;其余数字只出现1次。试用O(n)时间复杂度来求出出现2次的这个数字。 不允许用数组 输入格式 第一行&#xff1a;一个整数1001&#xff1b; 第二行&#xff1a;1001个用…...

Deep Reinforcement Learning for Robotics翻译解读

a. 机器人能力 1 单机器人能力&#xff08;Single-robot competencies&#xff09; 运动能力&#xff08;Mobility&#xff09; 行走&#xff08;Locomotion&#xff09;导航&#xff08;Navigation&#xff09; 操作能力&#xff08;Manipulation&#xff09; 静态操作&…...

【Linux】日志模块实现详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…...

AT_abc212_d [ABC212D] Querying Multiset

链接&#xff1a;AT_abc212_d [ABC212D] Querying Multiset - 洛谷 题目描述 高橋君は何も書かれていないたくさんのボールと 1 つの袋を持っています。 最初、袋は空で、高橋君は Q 回の操作を行います。 それぞれの操作は以下の 3 種類のうちのいずれかです。 操作 1 : ま…...

Android使用OpenGL和MediaCodec录制

目录 一,什么是opengl 二,什么是Android OpenGL ES 三, OpenGL 绘制流程 四, OpenGL坐标系 五, OpenGL 着色器 六, GLSL编程语言 七,使用MediaCodec录制在Opengl中渲染架构 八,代码实现 8.1 自定义渲染view继承GLSurfaceView 8.2 自定义渲染器TigerRender 8.3 创建编…...