程序的发展,需要引入集中配置

  • 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址……
  • 并且对配置的期望也越来越高,配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制……
  • 并且随着采用分布式的开发模式,项目之间的相互引用随着服务的不断增多,相互之间的调用复杂度成指数升高,每次投产或者上线新的项目时苦不堪言,因此需要引用配置中心治理。

有哪些开源配置中心

    1. spring-cloud/spring-cloud-config
      https://github.com/spring-cloud/spring-cloud-config
      spring出品,可以和spring cloud无缝配合

    2. 淘宝 diamond
      https://github.com/takeseem/diamond
      已经不维护

    3. disconf
      https://github.com/knightliao/disconf
      java开发,蚂蚁金服技术专家发起,业界使用广泛

    4. ctrip apollo
      https://github.com/ctripcorp/apollo/
      Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,具备规范的权限、流程治理等特性。

配置中心的实现方式可以使用数据库如mysql,可以使用缓存数据如redis,mongodb等,也可以使用zookeeper,zookeeper的watcher特性使它天然具有配置中心的属性。

1.solr zookeeper配置中心搭建(windows环境)

  1.1 下载solr

  下载最新的solr https://lucene.apache.org/solr/mirrors-solr-latest-redir.html

  我此时下载的最新版本为 solr-7.7.0.zip

  解压到本地目录

  E:\demo\solr-7.7.0

1.2 启动solr

  CMD进入bin目录下,执行 solr.cmd start -e cloud

   按照提示创建solr cloud实例和分片和collection:

  1.   techproducts

,详细参考官方文档:https://lucene.apache.org/solr/guide/7_6/solr-tutorial.html

   回到E:\demo\solr-7.7.0目录,CMD执行导入数据命令:

  1.   java -jar -Dc=techproducts -Dauto example\exampledocs\post.jar example\exampledocs\* 

1.3  访问admin

http://localhost:8983

查看内置zookeeper状态

  创建了一个9983端口的zk实例

1.4 使用ZooInspector监控查看

运行脚本

  1. @echo off
  2. cd D:\software\zookeeper-3.4.6\ZooInspector\build
  3. d:
  4. Java -Dfile.encoding=UTF-8 -jar zookeeper-dev-ZooInspector.jar

2.配置中心文件的上传,下载功能实现

本文仅实现上传功能,下载功能由读者自行实现

2.1 上传配置文件:进入E:\demo\solr-7.7.0/bin目录,CMD执行

  1. solr.cmd zk cp ../LICENSE.txt zk:/test/LICENSE.txt -z localhost:

此时在zk下面创建了一个test目录,目录下面有一个license.txt节点,数据即为license.txt文件内容。

2.2 源码分析

用记事本打开solr.cmd命令,找到parse_zk_args参数的地方,发现解析完zk参数就启动了运行zk命令方法run_zk

  1. :run_zk
  2. IF "!ZK_OP!"=="" (
  3. set "ERROR_MSG=Invalid command specified for zk sub-command"
  4. goto zk_short_usage
  5. )
  6.  
  7. IF "!ZK_HOST!"=="" (
  8. set "ERROR_MSG=Must specify -z zkHost"
  9. goto zk_short_usage
  10. )
  11.  
  12. IF "!ZK_OP!"=="-upconfig" (
  13. set ZK_OP="upconfig"
  14. )
  15. IF "!ZK_OP!"=="-downconfig" (
  16. set ZK_OP="downconfig"
  17. )
  18.  
  19. IF "!ZK_OP!"=="upconfig" (
  20. IF "!CONFIGSET_NAME!"=="" (
  21. set ERROR_MSG="-n option must be set for upconfig"
  22. goto zk_short_usage
  23. )
  24. IF "!CONFIGSET_DIR!"=="" (
  25. set ERROR_MSG="The -d option must be set for upconfig."
  26. goto zk_short_usage
  27. )
  28. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  29. -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
  30. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  31. org.apache.solr.util.SolrCLI !ZK_OP! -confname !CONFIGSET_NAME! -confdir !CONFIGSET_DIR! -zkHost !ZK_HOST! %ZK_VERBOSE%^
  32. -configsetsDir "%SOLR_TIP%/server/solr/configsets"
  33. ) ELSE IF "!ZK_OP!"=="downconfig" (
  34. IF "!CONFIGSET_NAME!"=="" (
  35. set ERROR_MSG="-n option must be set for downconfig"
  36. goto zk_short_usage
  37. )
  38. IF "!CONFIGSET_DIR!"=="" (
  39. set ERROR_MSG="The -d option must be set for downconfig."
  40. goto zk_short_usage
  41. )
  42. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  43. -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
  44. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  45. org.apache.solr.util.SolrCLI !ZK_OP! -confname !CONFIGSET_NAME! -confdir !CONFIGSET_DIR! -zkHost !ZK_HOST! %ZK_VERBOSE%
  46. ) ELSE IF "!ZK_OP!"=="cp" (
  47. IF "%ZK_SRC%"=="" (
  48. set ERROR_MSG="<src> must be specified for 'cp' command"
  49. goto zk_short_usage
  50. )
  51. IF "%ZK_DST%"=="" (
  52. set ERROR_MSG=<dest> must be specified for 'cp' command"
  53. goto zk_short_usage
  54. )
  55. IF NOT "!ZK_SRC:~0,3!"=="zk:" (
  56. IF NOT "!%ZK_DST:~0,3!"=="zk:" (
  57. set ERROR_MSG="At least one of src or dst must be prefixed by 'zk:'"
  58. goto zk_short_usage
  59. )
  60. )
  61. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  62. -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
  63. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  64. org.apache.solr.util.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -src !ZK_SRC! -dst !ZK_DST! -recurse !ZK_RECURSE! %ZK_VERBOSE%
  65. ) ELSE IF "!ZK_OP!"=="mv" (
  66. IF "%ZK_SRC%"=="" (
  67. set ERROR_MSG="<src> must be specified for 'mv' command"
  68. goto zk_short_usage
  69. )
  70. IF "%ZK_DST%"=="" (
  71. set ERROR_MSG="<dest> must be specified for 'mv' command"
  72. goto zk_short_usage
  73. )
  74. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  75. -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
  76. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  77. org.apache.solr.util.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -src !ZK_SRC! -dst !ZK_DST! %ZK_VERBOSE%
  78. ) ELSE IF "!ZK_OP!"=="rm" (
  79. IF "%ZK_SRC"=="" (
  80. set ERROR_MSG="Zookeeper path to remove must be specified when using the 'rm' command"
  81. goto zk_short_usage
  82. )
  83. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  84. -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
  85. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  86. org.apache.solr.util.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -path !ZK_SRC! -recurse !ZK_RECURSE! %ZK_VERBOSE%
  87. ) ELSE IF "!ZK_OP!"=="ls" (
  88. IF "%ZK_SRC"=="" (
  89. set ERROR_MSG="Zookeeper path to remove must be specified when using the 'ls' command"
  90. goto zk_short_usage
  91. )
  92. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  93. -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
  94. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  95. org.apache.solr.util.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -path !ZK_SRC! -recurse !ZK_RECURSE! %ZK_VERBOSE%
  96. ) ELSE IF "!ZK_OP!"=="mkroot" (
  97. IF "%ZK_SRC"=="" (
  98. set ERROR_MSG="Zookeeper path to create must be specified when using the 'mkroot' command"
  99. goto zk_short_usage
  100. )
  101. "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^
  102. -Dlog4j.configurationFile="file:///%SOLR_SERVER_DIR%\resources\log4j2-console.xml" ^
  103. -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
  104. org.apache.solr.util.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -path !ZK_SRC! %ZK_VERBOSE%
  105. ) ELSE (
  106. set ERROR_MSG="Unknown zk option !ZK_OP!"
  107. goto zk_short_usage
  108. )
  109. goto done

红色即为zk cp命令时执行

  1. org.apache.solr.util.SolrCLI

不同的命令,使用不同的Tool类

  1. // Creates an instance of the requested tool, using classpath scanning if necessary
  2. private static Tool newTool(String toolType) throws Exception {
  3. if ("healthcheck".equals(toolType))
  4. return new HealthcheckTool();
  5. else if ("status".equals(toolType))
  6. return new StatusTool();
  7. else if ("api".equals(toolType))
  8. return new ApiTool();
  9. else if ("create_collection".equals(toolType))
  10. return new CreateCollectionTool();
  11. else if ("create_core".equals(toolType))
  12. return new CreateCoreTool();
  13. else if ("create".equals(toolType))
  14. return new CreateTool();
  15. else if ("delete".equals(toolType))
  16. return new DeleteTool();
  17. else if ("config".equals(toolType))
  18. return new ConfigTool();
  19. else if ("run_example".equals(toolType))
  20. return new RunExampleTool();
  21. else if ("upconfig".equals(toolType))
  22. return new ConfigSetUploadTool();
  23. else if ("downconfig".equals(toolType))
  24. return new ConfigSetDownloadTool();
  25. else if ("rm".equals(toolType))
  26. return new ZkRmTool();
  27. else if ("mv".equals(toolType))
  28. return new ZkMvTool();
  29. else if ("cp".equals(toolType))
  30. return new ZkCpTool();
  31. else if ("ls".equals(toolType))
  32. return new ZkLsTool();
  33. else if ("mkroot".equals(toolType))
  34. return new ZkMkrootTool();
  35. else if ("assert".equals(toolType))
  36. return new AssertTool();
  37. else if ("utils".equals(toolType))
  38. return new UtilsTool();
  39. else if ("auth".equals(toolType))
  40. return new AuthTool();

cp执行ZkCpTool的runImpl方法

  1. protected void runImpl(CommandLine cli) throws Exception {
  2. raiseLogLevelUnlessVerbose(cli);
  3. String zkHost = getZkHost(cli);
  4. if (zkHost == null) {
  5. throw new IllegalStateException("Solr at " + cli.getOptionValue("solrUrl") +
  6. " is running in standalone server mode, cp can only be used when running in SolrCloud mode.\n");
  7. }
  8.  
  9. try (SolrZkClient zkClient = new SolrZkClient(zkHost, 30000)) {
  10. echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...", cli);
  11. String src = cli.getOptionValue("src");
  12. String dst = cli.getOptionValue("dst");
  13. Boolean recurse = Boolean.parseBoolean(cli.getOptionValue("recurse"));
  14. echo("Copying from '" + src + "' to '" + dst + "'. ZooKeeper at " + zkHost);
  15.  
  16. boolean srcIsZk = src.toLowerCase(Locale.ROOT).startsWith("zk:");
  17. boolean dstIsZk = dst.toLowerCase(Locale.ROOT).startsWith("zk:");
  18.  
  19. String srcName = src;
  20. if (srcIsZk) {
  21. srcName = src.substring(3);
  22. } else if (srcName.toLowerCase(Locale.ROOT).startsWith("file:")) {
  23. srcName = srcName.substring(5);
  24. }
  25.  
  26. String dstName = dst;
  27. if (dstIsZk) {
  28. dstName = dst.substring(3);
  29. } else {
  30. if (dstName.toLowerCase(Locale.ROOT).startsWith("file:")) {
  31. dstName = dstName.substring(5);
  32. }
  33. }
  34. zkClient.zkTransfer(srcName, srcIsZk, dstName, dstIsZk, recurse);
  35. } catch (Exception e) {
  36. log.error("Could not complete the zk operation for reason: " + e.getMessage());
  37. throw (e);
  38. }
  39. }

调用SolrZkClient的zkTransfer

  1. public void zkTransfer(String src, Boolean srcIsZk,
  2. String dst, Boolean dstIsZk,
  3. Boolean recurse) throws SolrServerException, KeeperException, InterruptedException, IOException {
  4. ZkMaintenanceUtils.zkTransfer(this, src, srcIsZk, dst, dstIsZk, recurse);
  5. }

实现由ZkMaintenanceUtils来做

  1. /**
  2. * Copy between local file system and Zookeeper, or from one Zookeeper node to another,
  3. * optionally copying recursively.
  4. *
  5. * @param src Source to copy from. Both src and dst may be Znodes. However, both may NOT be local
  6. * @param dst The place to copy the files too. Both src and dst may be Znodes. However both may NOT be local
  7. * @param recurse if the source is a directory, reccursively copy the contents iff this is true.
  8. * @throws SolrServerException Explanatory exception due to bad params, failed operation, etc.
  9. * @throws KeeperException Could not perform the Zookeeper operation.
  10. * @throws InterruptedException Thread interrupted
  11. */
  12. public static void zkTransfer(SolrZkClient zkClient, String src, Boolean srcIsZk,
  13. String dst, Boolean dstIsZk,
  14. Boolean recurse) throws SolrServerException, KeeperException, InterruptedException, IOException {
  15.  
  16. if (srcIsZk == false && dstIsZk == false) {
  17. throw new SolrServerException("One or both of source or destination must specify ZK nodes.");
  18. }
  19.  
  20. // Make sure -recurse is specified if the source has children.
  21. if (recurse == false) {
  22. if (srcIsZk) {
  23. if (zkClient.getChildren(src, null, true).size() != 0) {
  24. throw new SolrServerException("Zookeeper node " + src + " has children and recurse is false");
  25. }
  26. } else if (Files.isDirectory(Paths.get(src))) {
  27. throw new SolrServerException("Local path " + Paths.get(src).toAbsolutePath() + " is a directory and recurse is false");
  28. }
  29. }
  30.  
  31. if (dstIsZk && dst.length() == 0) {
  32. dst = "/"; // for consistency, one can copy from zk: and send to zk:/
  33. }
  34. dst = normalizeDest(src, dst, srcIsZk, dstIsZk);
  35.  
  36. // ZK -> ZK copy.
  37. if (srcIsZk && dstIsZk) {
  38. traverseZkTree(zkClient, src, VISIT_ORDER.VISIT_PRE, new ZkCopier(zkClient, src, dst));
  39. return;
  40. }
  41.  
  42. //local -> ZK copy
  43. if (dstIsZk) {
  44. uploadToZK(zkClient, Paths.get(src), dst, null);
  45. return;
  46. }
  47.  
  48. // Copying individual files from ZK requires special handling since downloadFromZK assumes the node has children.
  49. // This is kind of a weak test for the notion of "directory" on Zookeeper.
  50. // ZK -> local copy where ZK is a parent node
  51. if (zkClient.getChildren(src, null, true).size() > 0) {
  52. downloadFromZK(zkClient, src, Paths.get(dst));
  53. return;
  54. }
  55.  
  56. // Single file ZK -> local copy where ZK is a leaf node
  57. if (Files.isDirectory(Paths.get(dst))) {
  58. if (dst.endsWith(File.separator) == false) dst += File.separator;
  59. dst = normalizeDest(src, dst, srcIsZk, dstIsZk);
  60. }
  61. byte[] data = zkClient.getData(src, null, null, true);
  62. Path filename = Paths.get(dst);
  63. Files.createDirectories(filename.getParent());
  64. log.info("Writing file {}", filename);
  65. Files.write(filename, data);
  66. }

注意:这个copy 可以是本地文件到znode之间的copy,也可以是znode之间的copy

本文以本地文档到znode之间的copy

  1. public static void uploadToZK(SolrZkClient zkClient, final Path fromPath, final String zkPath,
  2. final Pattern filenameExclusions) throws IOException {
  3.  
  4. String path = fromPath.toString();
  5. if (path.endsWith("*")) {
  6. path = path.substring(0, path.length() - 1);
  7. }
  8.  
  9. final Path rootPath = Paths.get(path);
  10.  
  11. if (!Files.exists(rootPath))
  12. throw new IOException("Path " + rootPath + " does not exist");
  13.  
  14. Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
  15. @Override
  16. public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  17. String filename = file.getFileName().toString();
  18. if (filenameExclusions != null && filenameExclusions.matcher(filename).matches()) {
  19. log.info("uploadToZK skipping '{}' due to filenameExclusions '{}'", filename, filenameExclusions);
  20. return FileVisitResult.CONTINUE;
  21. }
  22. String zkNode = createZkNodeName(zkPath, rootPath, file);
  23. try {
  24. // if the path exists (and presumably we're uploading data to it) just set its data
  25. if (file.toFile().getName().equals(ZKNODE_DATA_FILE) && zkClient.exists(zkNode, true)) {
  26. zkClient.setData(zkNode, file.toFile(), true);
  27. } else {
  28. zkClient.makePath(zkNode, file.toFile(), false, true);
  29. }
  30. } catch (KeeperException | InterruptedException e) {
  31. throw new IOException("Error uploading file " + file.toString() + " to zookeeper path " + zkNode,
  32. SolrZkClient.checkInterrupted(e));
  33. }
  34. return FileVisitResult.CONTINUE;
  35. }
  36.  
  37. @Override
  38. public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
  39. if (dir.getFileName().toString().startsWith(".")) return FileVisitResult.SKIP_SUBTREE;
  40.  
  41. return FileVisitResult.CONTINUE;
  42. }
  43. });
  44. }

文件转换为byte流数据,设置到znode

  1. /**
  2. * Write file to ZooKeeper - default system encoding used.
  3. *
  4. * @param path path to upload file to e.g. /solr/conf/solrconfig.xml
  5. * @param file path to file to be uploaded
  6. */
  7. public Stat setData(String path, File file, boolean retryOnConnLoss) throws IOException,
  8. KeeperException, InterruptedException {
  9. log.debug("Write to ZooKeeper: {} to {}", file.getAbsolutePath(), path);
  10. byte[] data = FileUtils.readFileToByteArray(file);
  11. return setData(path, data, retryOnConnLoss);
  12.  
  13. /**
  14. * Returns node's state
  15. */
  16. public Stat setData(final String path, final byte data[], final int version, boolean retryOnConnLoss)
  17. throws KeeperException, InterruptedException {
  18. if (retryOnConnLoss) {
  19. return zkCmdExecutor.retryOperation(() -> keeper.setData(path, data, version));
  20. } else {
  21. return keeper.setData(path, data, version);
  22. }
  23. }

具体实现为ZooKeeper本身的客户端ZooKeeper.java

  1. /**
  2. * Set the data for the node of the given path if such a node exists and the
  3. * given version matches the version of the node (if the given version is
  4. * -1, it matches any node's versions). Return the stat of the node.
  5. * <p>
  6. * This operation, if successful, will trigger all the watches on the node
  7. * of the given path left by getData calls.
  8. * <p>
  9. * A KeeperException with error code KeeperException.NoNode will be thrown
  10. * if no node with the given path exists.
  11. * <p>
  12. * A KeeperException with error code KeeperException.BadVersion will be
  13. * thrown if the given version does not match the node's version.
  14. * <p>
  15. * The maximum allowable size of the data array is 1 MB (1,048,576 bytes).
  16. * Arrays larger than this will cause a KeeperException to be thrown.
  17. *
  18. * @param path
  19. * the path of the node
  20. * @param data
  21. * the data to set
  22. * @param version
  23. * the expected matching version
  24. * @return the state of the node
  25. * @throws InterruptedException If the server transaction is interrupted.
  26. * @throws KeeperException If the server signals an error with a non-zero error code.
  27. * @throws IllegalArgumentException if an invalid path is specified
  28. */
  29. public Stat setData(final String path, byte data[], int version)
  30. throws KeeperException, InterruptedException
  31. {
  32. final String clientPath = path;
  33. PathUtils.validatePath(clientPath);
  34.  
  35. final String serverPath = prependChroot(clientPath);
  36.  
  37. RequestHeader h = new RequestHeader();
  38. h.setType(ZooDefs.OpCode.setData);
  39. SetDataRequest request = new SetDataRequest();
  40. request.setPath(serverPath);
  41. request.setData(data);
  42. request.setVersion(version);
  43. SetDataResponse response = new SetDataResponse();
  44. ReplyHeader r = cnxn.submitRequest(h, request, response, null);
  45. if (r.getErr() != 0) {
  46. throw KeeperException.create(KeeperException.Code.get(r.getErr()),
  47. clientPath);
  48. }
  49. return response.getStat();
  50. }

3. 小结

1.solrcloud使用zookeeper实现了配置中心,入口函数为ZkCLI.java ,它使用命令模式内部封装了一系列命令,如:healthcheck,status,api,config,upconfig,downconfig,mv,cp,ls,mkroot等命令

2.最终调用的是apache zookeeper本身的api,如果为文件的话,需要先转为byte流,然后存入znode节点中。

参考文献:

【1】https://www.cnblogs.com/xiaoqi/p/configserver-compair.html

【2】https://lucene.apache.org/solr/guide/7_6/solr-tutorial.html

zookeeper配置中心实战--solrcloud zookeeper配置中心原理及源码分析的更多相关文章

  1. zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析

    1.为什么要服务发现? 服务实例的网络位置都是动态分配的.由于扩展.失败和升级,服务实例会经常动态改变,因此,客户端代码需要使用更加复杂的服务发现机制. 2.常见的服务发现开源组件 etcd—用于共享 ...

  2. 微服务之SpringCloud实战(四):SpringCloud Eureka源码分析

    Eureka源码解析: 搭建Eureka服务的时候,我们会再SpringBoot启动类加上@EnableEurekaServer的注解,这个注解做了一些什么,我们一起来看. 点进@EnableEure ...

  3. Nacos配置中心集群原理及源码分析

    Nacos作为配置中心,必然需要保证服务节点的高可用性,那么Nacos是如何实现集群的呢? 下面这个图,表示Nacos集群的部署图. Nacos集群工作原理 Nacos作为配置中心的集群结构中,是一种 ...

  4. (转)spring boot实战(第三篇)事件监听源码分析

    原文:http://blog.csdn.net/liaokailin/article/details/48194777 监听源码分析 首先是我们自定义的main方法: package com.lkl. ...

  5. 【Zookeeper】源码分析之Watcher机制(二)

    一.前言 前面已经分析了Watcher机制中的第一部分,即在org.apache.zookeeper下的相关类,接着来分析org.apache.zookeeper.server下的WatchManag ...

  6. 【Zookeeper】源码分析之Watcher机制(二)之WatchManager

    一.前言 前面已经分析了Watcher机制中的第一部分,即在org.apache.zookeeper下的相关类,接着来分析org.apache.zookeeper.server下的WatchManag ...

  7. 6.Sentinel源码分析—Sentinel是如何动态加载配置限流的?

    Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 3. Senti ...

  8. 浅谈ZooKeeper基本原理与源码分析

    最近一直有小伙伴私信我,问一些关于Zookeeper的知识,下边关于的Zookeeper的知识整理了一下,一起学习一下. 看完本文对于Zookeeper想深入全面了解的读者朋友们,小编这里整理了一份更 ...

  9. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

随机推荐

  1. function()

    avaScript中的function可以有以下两种用法:一是做“普通逻辑代码容器”,也就是我们通常意义上的函数.方法,和我们C/C++里的函数没什么大分别,只是写法稍有不同.用法更加灵活:二是做对象 ...

  2. 如何理解Unity组件化开发模式

    Unity的开发模式核心:节点和组件,组件可以加载到任何节点上,每个组件都有 gameobject 属性,可以通过这个属性获取到该节点,即游戏物体. 也就是说游戏物体由节点和组件构成,每个组件表示物体 ...

  3. Runnable和Callable 的区别

    Runnable和Callable 的区别 01.Runnable接口中只有一个run()没有返回值 没有声明异常   Callable接口中只有一个call()有返回值 有声明异常 02.Calla ...

  4. nginx报错:./configure: error: C compiler cc is not found, gcc 是已经安装了的

    源码安装nginx报错,找不到gcc,但是实际上gcc是存在的,如下: # ./configure checking for OS + Linux -.el7.x86_64 x86_64 checki ...

  5. Shell条件测试和流程控制-4

  6. C++反汇编(一)

    对象/结构体 对象的大小只包括数据成员,成员函数属于执行代码. 对象长度 = sizeof(数据成员1) + sizeof(数据成员2) + ...... + sizeof(数据成员n) 特殊情况公式 ...

  7. python 学习之路【目录】

    目录: python--常用函数

  8. Android中实现gif动画

    一.需求 Android本身没有提供直接显示gif动画的相关控件,因此需要自定义GifImageView类来实现gif的播放,主要是使用的Movie类来解决的. 二.自定义GifImageView p ...

  9. shiro与项目集成开发

    shiro与spring web项目开发 加入shiro的jar包 自定义realm /** * 自定义realm 继承授权realm * @author Administrator * */ pub ...

  10. Java对象序列化和返序列化

    public class SerializeUtil { /** * 序列化 * * @param object * @return */ public static byte[] serialize ...