<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>数据库敲门人</title>
	<atom:link href="http://www.knockatdatabase.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.knockatdatabase.com/</link>
	<description>带你敲开数据库大门</description>
	<lastBuildDate>Wed, 29 Jul 2026 23:57:55 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.5</generator>

<image>
	<url>http://www.knockatdatabase.com/wp-content/uploads/2021/03/favicon-16x16-1.png</url>
	<title>数据库敲门人</title>
	<link>http://www.knockatdatabase.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>新手解决Whitelabel Error Page NoResourceFoundException: No static resource  for request &#8216;/’报错的一则案例</title>
		<link>http://www.knockatdatabase.com/2026/07/28/whitelabel-error-page-noresource-found-exception-no-static-resource-for-request/</link>
					<comments>http://www.knockatdatabase.com/2026/07/28/whitelabel-error-page-noresource-found-exception-no-static-resource-for-request/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Tue, 28 Jul 2026 00:35:29 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=2778</guid>

					<description><![CDATA[<p>一 报错重现和故障说明 在我自己动手实践「Spring in Action sixth edition」的第2个章节的过程中，编写了一个简单的Controller，然后用IDEA启动了Spring工程之后，浏览器访问 ：http://localhost:8080/ 遇到下述错误： &#160; 我的Controller代码如下： &#160; 但是，当我把代码改写为： &#160; 或者 &#160; &#160; &#160; &#160; 程序都可以运行正常，不报错。 二 错误分析 对于新手而言，这可能需要花费一些时间。于是，把问题交给了Gemini，给出了一针见血的解释和说明： 造成问题的根源，是SpringMVC的注解解析机制，尤其是既有类级别「class-level」又有方法级别「method-level」混合使用作路由映射的场景时，容易出现一些和我们预期不一致的报错。 如果只把路由写在类上，方法上不写路由时，Spring是不会把这个方法识别为Web请求处理器的。就如同第一种写法。 1 第一种写法：只在类上写注解为啥会报错 SpringMVC的RequestMappingHandlerMapping在注册路由时，会先扫描带有@Controller的类，然后到该类中去找那些带有@RequestMapping或者@GetMapping的方法。此时，HomeController类上虽然有@Controller注解，但是该类中没有任何满足条件的方法，于是SpringMVC认为这是1个普普通通的方法，压根儿不会把它当做Web请求的接口。最终，请求的根路径/这个URL，没有绑定到任何控制器方法上。Spring认为这不是一个动态请求，而是查找一个静态资源，于是会到项目的静态路径static下去查找名为index.html或者是名为/的静态资源，结果呢，没有找到该资源，最终抛出了： &#160; 再进一步，当我创建对应的文件 src/main/resources/static/index.html 时，程序则可以继续运行： &#160; 2 第2种写法：类和方法上都写注解，为啥不报错 当我们在类和方法上同时都写有注解时，SpringMVC在解析时，会拼接URL。类注解地址+方法注解地址。而本例中，类和方法上都写成了根路径，最后会拼接成http://localhost:8080//。SpringMVC在此时，会自动去掉一个根路径/的URL。home()方法被成功识别到，并直接返回了名为home的view。 3 第3种写法：只在方法上写注解，为啥也不报错 这是Spring开发中最推荐、最简洁的写法。类级别上不设置基准路径，直接由方法级别的@GetMapping(value=”/”)来统领全局。Spring识别到该方法并且绑定到根路径。 三 SpringMVC最佳实践小结 在编写SpringMVC控制器时，通常遵循这个铁律：方法上必须有路由注解，它才会被作为一个可达的Web接口。 &#160; &#160; &#160;</p>
<p><a href="http://www.knockatdatabase.com/2026/07/28/whitelabel-error-page-noresource-found-exception-no-static-resource-for-request/">新手解决Whitelabel Error Page NoResourceFoundException: No static resource  for request &#8216;/’报错的一则案例</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">一 报错重现和故障说明</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">在我自己动手实践「Spring in Action sixth edition」的第2个章节的过程中，编写了一个简单的Controller，然后用IDEA启动了Spring工程之后，浏览器访问 ：<a href="http://localhost:8080/">http://localhost:8080/</a></p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">遇到下述错误：</p>


<pre class="wp-block-code"><code>Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Jul 21 08:37:48 CST 2026
There was an unexpected error (type=Not Found, status=404).
No static resource .
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource  for request &#039;/&#039;.
	at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:527)
	at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:50)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:892)
	...</code></pre>


<p>&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/07/image-67-1024x420.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">我的Controller代码如下：</p>


<pre class="wp-block-code"><code>package com.knockatdatabase.tacocloud;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(method = RequestMethod.GET,value = &quot;/&quot;)
public class HomeController {

    public String home() {
        return &quot;home&quot;;
    }
}</code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">但是，当我把代码改写为：</p>


<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>//写法2
package com.knockatdatabase.tacocloud;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(method = RequestMethod.GET,value = &quot;/&quot;)
public class HomeController {

    @GetMapping(value = &quot;/&quot;)
    public String home() {
        return &quot;home&quot;;
    }
}
</code></pre>


<p>&nbsp;</p>

</div>


<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-color" style="color: rgb(0, 0, 0)">或者</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>

</div>


<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>//写法3
package com.knockatdatabase.tacocloud;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping(value = &quot;/&quot;)
    public String home() {
        return &quot;home&quot;;
    }
}
</code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>

</div>

</div>


<p class="has-text-color" style="color: rgb(0, 0, 0)">程序都可以运行正常，不报错。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/07/image-68-1024x368.png" alt=""/></figure>


<h2 class="wp-block-heading">二 错误分析</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">对于新手而言，这可能需要花费一些时间。于是，把问题交给了Gemini，给出了一针见血的解释和说明：</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">造成问题的根源，是SpringMVC的注解解析机制，尤其是既有类级别「class-level」又有方法级别「method-level」混合使用作路由映射的场景时，容易出现一些和我们预期不一致的报错。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)"><span style="background-color: rgb(253, 235, 236);"><em>如果只把路由写在类上，方法上不写路由时，Spring是不会把这个方法识别为Web请求处理器的。</em></span>就如同第一种写法。</p>


<h3 class="wp-block-heading">1 第一种写法：只在类上写注解为啥会报错</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">SpringMVC的RequestMappingHandlerMapping在注册路由时，会先扫描带有@Controller的类，然后到该类中去找那些带有@RequestMapping或者@GetMapping的方法。此时，HomeController类上虽然有@Controller注解，但是该类中没有任何满足条件的方法，于是SpringMVC认为这是1个普普通通的方法，压根儿不会把它当做Web请求的接口。最终，请求的根路径/这个URL，没有绑定到任何控制器方法上。Spring认为这不是一个动态请求，而是查找一个静态资源，于是会到项目的静态路径static下去查找名为index.html或者是名为/的静态资源，结果呢，没有找到该资源，最终抛出了：</p>


<pre class="wp-block-code"><code>ue Jul 21 08:37:48 CST 2026
There was an unexpected error (type=Not Found, status=404).
No static resource .
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource  for request &#039;/&#039;.</code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">再进一步，当我创建对应的文件 src/main/resources/static/index.html 时，程序则可以继续运行：</p>


<pre class="wp-block-code"><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
我的路径在
&lt;h1&gt;欢迎来到 Taco Cloud！&lt;/h1&gt;

&lt;div style=&quot;background-color: #f0f0f0; padding: 15px; border-radius: 5px;&quot;&gt;
  &lt;p&gt;&lt;strong&gt;当前完整的 URL：&lt;/strong&gt; &lt;span id=&quot;full-url&quot;&gt;&lt;/span&gt;&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;当前访问的相对路径：&lt;/strong&gt; &lt;span id=&quot;path-name&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;script&gt;
  // 获取浏览器当前地址并渲染到页面
  document.getElementById(&#039;full-url&#039;).innerText = window.location.href;
  document.getElementById(&#039;path-name&#039;).innerText = window.location.pathname;

  // 同时也在控制台打印一份
  console.log(&quot;网页绝对 URL: &quot; + window.location.href);
  console.log(&quot;网页路径: &quot; + window.location.pathname);
&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre>


<p>&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/07/image-69-1024x269.png" alt=""/></figure>


<h3 class="wp-block-heading">2 第2种写法：类和方法上都写注解，为啥不报错</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">当我们在类和方法上同时都写有注解时，SpringMVC在解析时，会拼接URL。类注解地址+方法注解地址。而本例中，类和方法上都写成了根路径，最后会拼接成<a href="http://localhost:8080/">http://localhost:8080/</a>/。SpringMVC在此时，会自动去掉一个根路径/的URL。home()方法被成功识别到，并直接返回了名为home的view。</p>


<h3 class="wp-block-heading">3 第3种写法：只在方法上写注解，为啥也不报错</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">这是Spring开发中最推荐、最简洁的写法。类级别上不设置基准路径，直接由方法级别的@GetMapping(value=”/”)来统领全局。Spring识别到该方法并且绑定到根路径。</p>


<h2 class="wp-block-heading">三 SpringMVC最佳实践小结</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">在编写SpringMVC控制器时，通常遵循这个铁律：方法上必须有路由注解，它才会被作为一个可达的Web接口。</p>


<ul class="wp-block-list">
<li>类级别的注解@RequestMapping：通常用于定义公共前缀。例如：处理订单的控制器，可以在类上写@RequestMapping(”/orders/”)；</li>



<li>方法上的注解，如则处理具体的动作，如@GetMapping(”/detail”)，最终匹配成“/orders/detail”;</li>



<li>对于类似查看主页这样的根路径，只需要直接写在方法注解上即可，@GetMapping(”/”)，这样代码可读性好，简洁也不会引起歧义。</li>
</ul>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>

<p><a href="http://www.knockatdatabase.com/2026/07/28/whitelabel-error-page-noresource-found-exception-no-static-resource-for-request/">新手解决Whitelabel Error Page NoResourceFoundException: No static resource  for request &#8216;/’报错的一则案例</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2026/07/28/whitelabel-error-page-noresource-found-exception-no-static-resource-for-request/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>如何在信创麒麟V10 ARM64位机器上通过配置chronyd作为ntp服务器来同步系统时间</title>
		<link>http://www.knockatdatabase.com/2026/07/22/how-to-config-ntp-server-on-kylin-v10/</link>
					<comments>http://www.knockatdatabase.com/2026/07/22/how-to-config-ntp-server-on-kylin-v10/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Wed, 22 Jul 2026 00:49:47 +0000</pubDate>
				<category><![CDATA[算法和数据结构]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=2780</guid>

					<description><![CDATA[<p>一 配置场景说明 某项目采用信创麒麟V10 ARM64位操作系统，服务器分别位于2个网络区域：一部分机器位于可以连接到互联网的区域，另外一部分服务器则无法访问到互联网区服务器。云厂商提供过来的机器系统时间又不对，和北京时间差8个小时。让PM去反馈给云厂商处理无果，无奈只能自己动手处理了。 在位于互联网区的一台机器上，通过设置从互联网同步校准时间，保证自身系统时间是准确的前提下，再启动运行一个ntp服务端，让那些无法访问互联网区的服务器作为client，从这个ntp server来同步时间，进而实现系统时间同步。 技术一点儿的讲：server端，先从互联网同步时间，确保时间正确之后，启动chronyd系统服务，监听在123端口；client端通过udp协议，从 server ip:123端口请求时间同步。 服务器的操作系统和版本信息都一致，只是系统时间不同而已「我在编写整理这篇文档时的北京时间是：2026年7月22日早上7点20分左右 」，具体信息如下： &#160; &#160; 下文中，我会以192.166.20.3当做ntp服务器端，10.193.120.35作为ntp client端配置。 一 具体操作和配置步骤 1 ntp serve192.166.20.3查看chronyd服务是否启动 &#160; 服务启动正常，如果没有启动的话，则需要先启动。如果没有该服务，可以通过yum install chronyd*来执行安装。 2 ntp server端192.166.20.3修改chronyd配置文件 vi /etc/chrony.conf 在其配置文件里，加入允许客户端访问的IP地址范围限制，以及要把chronyd系统服务绑定在所有网卡上，而不能只是本机环路地址127.0.0.1。否则，ntp客户端发起同步时间请求时，无法通过ntp server 主机IP地址来请求。 修改的2个参数配置项如下： &#160; 修改之后的文件内容如下： &#160; 3 ntp server端192.166.20.3重启chronyd服务，确保123端口正常监听 &#160; 4 ntp客户端10.193.120.35修改chronyd配置文件/etc/chronyd.conf 修改前： &#160; 在配置文件/etc/chronyd.conf中，添加 server 192.166.20.3 iburst 修改后： &#160; 5 ntp客户端10.193.120.35重启chronyd服务，并确认可以同步时间源 &#160; 6 ntp客户端10.193.120.35开始手动同步时间 这一步非必须，其实只要在客户端里配置了ntp同步时间源，并且重启了chronyd服务之后，系统会自动同步时间。 &#160; 三 小结 这是一个比较简单的问题，系统因为网络问题，或者其它原因导致无法提供正确时间，势必会对运行在其上的应用系统带来一些问题。这里做一个简洁记录。 ntp服务端查查系统是否提供ntp时间服务，以及其运行的端口是否正常： &#160; ntp客户端，查看是否可以连接到ntp server并执行时间同步，此时无法通过常规的telnet ntp_server_ip 123命令来验证。 &#160; 手工通过ntpdate命令来同步时间 &#160;</p>
<p><a href="http://www.knockatdatabase.com/2026/07/22/how-to-config-ntp-server-on-kylin-v10/">如何在信创麒麟V10 ARM64位机器上通过配置chronyd作为ntp服务器来同步系统时间</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">一 配置场景说明</h2>



<p class="has-text-color" style="color:rgb(0, 0, 0)">某项目采用信创麒麟V10 ARM64位操作系统，服务器分别位于2个网络区域：一部分机器位于可以连接到互联网的区域，另外一部分服务器则无法访问到互联网区服务器。云厂商提供过来的机器系统时间又不对，和北京时间差8个小时。让PM去反馈给云厂商处理无果，无奈只能自己动手处理了。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">在位于互联网区的一台机器上，通过设置从互联网同步校准时间，保证自身系统时间是准确的前提下，再启动运行一个ntp服务端，让那些无法访问互联网区的服务器作为client，从这个ntp server来同步时间，进而实现系统时间同步。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">技术一点儿的讲：server端，先从互联网同步时间，确保时间正确之后，启动chronyd系统服务，监听在123端口；client端通过udp协议，从 server ip:123端口请求时间同步。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">服务器的操作系统和版本信息都一致，只是系统时间不同而已「我在编写整理这篇文档时的北京时间是：2026年7月22日早上7点20分左右 」，具体信息如下：</p>



<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/07/image-70.png" alt=""/></figure>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>&#91;root@gxd-hlw-3 ~]# hostname -I
192.166.20.3 172.17.0.1 
&#91;root@gxd-hlw-3 ~]# uname -rm
4.19.90-89.11.v2401.ky10.aarch64 aarch64
&#91;root@gxd-hlw-3 ~]# cat /etc/os-release 
NAME="Kylin Linux Advanced Server"
VERSION="V10 (Halberd)"
ID="kylin"
VERSION_ID="V10"
PRETTY_NAME="Kylin Linux Advanced Server V10 (Halberd)"
ANSI_COLOR="0;31"

&#91;root@gxd-hlw-3 ~]# date
Wed Jul 22 07:20:11 CST 2026
&#91;root@gxd-hlw-3 ~]# </code></pre>



<p>&nbsp;</p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>&#91;root@hqqf-35 ~]# hostname -I
10.193.120.35 172.17.0.1 
&#91;root@hqqf-35 ~]# uname -rm
4.19.90-89.11.v2401.ky10.aarch64 aarch64
&#91;root@hqqf-35 ~]# cat /etc/os-release 
NAME="Kylin Linux Advanced Server"
VERSION="V10 (Halberd)"
ID="kylin"
VERSION_ID="V10"
PRETTY_NAME="Kylin Linux Advanced Server V10 (Halberd)"
ANSI_COLOR="0;31"

&#91;root@hqqf-35 ~]# date
Tue Jul 21 23:19:59 CST 2026
&#91;root@hqqf-35 ~]#  </code></pre>



<p>&nbsp;</p>
</div>
</div>



<p class="has-text-color" style="color:rgb(0, 0, 0)">下文中，我会以192.166.20.3当做ntp服务器端，10.193.120.35作为ntp client端配置。</p>



<h2 class="wp-block-heading">一 具体操作和配置步骤</h2>



<h3 class="wp-block-heading">1 ntp serve192.166.20.3查看chronyd服务是否启动</h3>



<pre class="wp-block-code"><code>&#91;root@gxd-hlw-3 ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2026-07-09 06:50:53 CST; 1 weeks 5 days ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
 Main PID: 734 (chronyd)
    Tasks: 1
   Memory: 3.2M
   CGroup: /system.slice/chronyd.service
           └─734 /usr/sbin/chronyd

Jul 16 10:54:16 gxd-hlw-3 chronyd&#91;734]: Source 1.82.219.234 replaced with 113.141.164.39
Jul 16 13:29:03 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 113.141.164.38
Jul 16 16:38:11 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.38 replaced with 113.141.164.39
Jul 16 20:22:23 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 113.141.164.38
Jul 17 11:18:55 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.38 replaced with 113.141.164.39
Jul 17 13:54:13 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 1.82.219.234
Jul 19 02:41:29 gxd-hlw-3 chronyd&#91;734]: Source 1.82.219.234 replaced with 113.141.164.39
Jul 19 05:34:03 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 113.141.164.38
Jul 20 03:41:42 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.38 replaced with 113.141.164.39
Jul 20 08:17:36 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 1.82.219.234
&#91;root@gxd-hlw-3 ~]#</code></pre>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">服务启动正常，如果没有启动的话，则需要先启动。如果没有该服务，可以通过yum install chronyd*来执行安装。</p>



<h3 class="wp-block-heading">2 ntp server端192.166.20.3修改chronyd配置文件</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">vi /etc/chrony.conf </p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">在其配置文件里，加入允许客户端访问的IP地址范围限制，以及要把chronyd系统服务绑定在所有网卡上，而不能只是本机环路地址127.0.0.1。否则，ntp客户端发起同步时间请求时，无法通过ntp server 主机IP地址来请求。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">修改的2个参数配置项如下：</p>



<pre class="wp-block-code"><code>allow 10.193.120.0/8
bindaddress 0.0.0.0</code></pre>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">修改之后的文件内容如下：</p>



<pre class="wp-block-code"><code># Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
#pool pool.ntp.org iburst
server ntp.ntsc.ac.cn iburst
server ntp1.aliyun.com iburst
#server cn.pool.ntp.org iburst

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

# Enable hardware timestamping on all interfaces that support it.
#hwtimestamp *

# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2

# Allow NTP client access from local network.
#allow 192.168.0.0/16
allow 10.193.120.0/8
bindaddress 0.0.0.0

# Serve time even if not synchronized to a time source.
#local stratum 10

# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys

# Get TAI-UTC offset and leap seconds from the system tz database.
#leapsectz right/UTC

# Specify directory for log files.
logdir /var/log/chrony

# Select which information is logged.
#log measurements statistics tracking</code></pre>



<p>&nbsp;</p>



<h3 class="wp-block-heading">3 ntp server端192.166.20.3重启chronyd服务，确保123端口正常监听</h3>



<pre class="wp-block-code"><code>&#91;root@gxd-hlw-3 ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2026-07-09 06:50:53 CST; 1 weeks 5 days ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
 Main PID: 734 (chronyd)
    Tasks: 1
   Memory: 3.2M
   CGroup: /system.slice/chronyd.service
           └─734 /usr/sbin/chronyd

Jul 16 10:54:16 gxd-hlw-3 chronyd&#91;734]: Source 1.82.219.234 replaced with 113.141.164.39
Jul 16 13:29:03 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 113.141.164.38
Jul 16 16:38:11 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.38 replaced with 113.141.164.39
Jul 16 20:22:23 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 113.141.164.38
Jul 17 11:18:55 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.38 replaced with 113.141.164.39
Jul 17 13:54:13 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 1.82.219.234
Jul 19 02:41:29 gxd-hlw-3 chronyd&#91;734]: Source 1.82.219.234 replaced with 113.141.164.39
Jul 19 05:34:03 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 113.141.164.38
Jul 20 03:41:42 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.38 replaced with 113.141.164.39
Jul 20 08:17:36 gxd-hlw-3 chronyd&#91;734]: Source 113.141.164.39 replaced with 1.82.219.234
&#91;root@gxd-hlw-3 ~]# systemctl restart chronyd
&#91;root@gxd-hlw-3 ~]# 
&#91;root@gxd-hlw-3 ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2026-07-21 16:48:32 CST; 3s ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 1434299 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
  Process: 1434303 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
 Main PID: 1434301 (chronyd)
    Tasks: 1
   Memory: 2.1M
   CGroup: /system.slice/chronyd.service
           └─1434301 /usr/sbin/chronyd

Jul 21 16:48:32 gxd-hlw-3 systemd&#91;1]: Starting NTP client/server...
Jul 21 16:48:32 gxd-hlw-3 chronyd&#91;1434301]: chronyd version 3.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH +IPV6 +DEBUG)
Jul 21 16:48:32 gxd-hlw-3 chronyd&#91;1434301]: Frequency -12.151 +/- 0.063 ppm read from /var/lib/chrony/drift
Jul 21 16:48:32 gxd-hlw-3 systemd&#91;1]: Started NTP client/server.
&#91;root@gxd-hlw-3 ~]# 
&#91;root@gxd-hlw-3 ~]# ss -unlp | grep 123
UNCONN    0         0                  0.0.0.0:123              0.0.0.0:*        users:(("chronyd",pid=1434301,fd=8))                                           
&#91;root@gxd-hlw-3 ~]# </code></pre>



<p>&nbsp;</p>



<h3 class="wp-block-heading">4 ntp客户端10.193.120.35修改chronyd配置文件/etc/chronyd.conf</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">修改前：</p>



<pre class="wp-block-code"><code>&#91;root@hqqf-35 ~]# hostname -I
10.193.120.35 172.17.0.1 
&#91;root@hqqf-35 ~]# date
Tue Jul 21 23:37:46 CST 2026
&#91;root@hqqf-35 ~]# chronyc sources -v
210 Number of sources = 0

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
||                                                 .- xxxx &#91; yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                     |          |  zzzz = estimated error.
||                                 |    |           
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
&#91;root@hqqf-35 ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2026-06-22 09:58:13 CST; 4 weeks 1 days ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
 Main PID: 661 (chronyd)
    Tasks: 1
   Memory: 2.6M
   CGroup: /system.slice/chronyd.service
           └─661 /usr/sbin/chronyd
&#91;root@hqqf-35 ~]# </code></pre>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">在配置文件/etc/chronyd.conf中，添加 server 192.166.20.3 iburst</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">修改后：</p>



<pre class="wp-block-code"><code>&#91;root@hqqf-35 ~]# cat /etc/chrony.conf 
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
#pool pool.ntp.org iburst
server ntp.ntsc.ac.cn iburst
server ntp1.aliyun.com iburst
#server cn.pool.ntp.org iburst
#下面是新添加的配置项
server 192.166.20.3 iburst

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

# Enable hardware timestamping on all interfaces that support it.
#hwtimestamp *

# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2

# Allow NTP client access from local network.
#allow 192.168.0.0/16

# Serve time even if not synchronized to a time source.
#local stratum 10

# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys

# Get TAI-UTC offset and leap seconds from the system tz database.
#leapsectz right/UTC

# Specify directory for log files.
logdir /var/log/chrony

# Select which information is logged.
#log measurements statistics tracking
&#91;root@hqqf-35 ~]# </code></pre>



<p>&nbsp;</p>



<h3 class="wp-block-heading">5  ntp客户端10.193.120.35重启chronyd服务，并确认可以同步时间源</h3>



<pre class="wp-block-code"><code>&#91;root@hqqf-35 ~]# systemctl restart chronyd
&#91;root@hqqf-35 ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2026-07-21 23:50:05 CST; 6s ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 1621798 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
  Process: 1621802 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
 Main PID: 1621800 (chronyd)
    Tasks: 2
   Memory: 1.9M
   CGroup: /system.slice/chronyd.service
           └─1621800 /usr/sbin/chronyd

Jul 21 23:50:05 hqqf-35 systemd&#91;1]: Starting NTP client/server...
Jul 21 23:50:05 hqqf-35 chronyd&#91;1621800]: chronyd version 3.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH&gt;
Jul 21 23:50:05 hqqf-35 chronyd&#91;1621800]: Frequency -6.273 +/- 0.176 ppm read from /var/lib/chrony/drift
Jul 21 23:50:05 hqqf-35 systemd&#91;1]: Started NTP client/server.
&#91;root@hqqf-35 ~]# chronyc sources -v
210 Number of sources = 1

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
||                                                 .- xxxx &#91; yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                     |          |  zzzz = estimated error.
||                                 |    |           
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================

^* 192.166.20.3                  3   6    17     1    +19us&#91; +320us] +/-   25ms
&#91;root@hqqf-35 ~]# </code></pre>



<p>&nbsp;</p>



<h3 class="wp-block-heading">6 ntp客户端10.193.120.35开始手动同步时间</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">这一步非必须，其实只要在客户端里配置了ntp同步时间源，并且重启了chronyd服务之后，系统会自动同步时间。</p>



<pre class="wp-block-code"><code>&#91;root@hqqf-35 ~]# ntpdate 192.166.20.3
22 Jul 07:51:20 ntpdate&#91;4123508]: step time server 192.166.20.3 offset +28807.674521 sec
&#91;root@hqqf-35 ~]# date
Wed Jul 22 07:51:24 CST 2026
&#91;root@hqqf-35 ~]# </code></pre>



<p>&nbsp;</p>



<h2 class="wp-block-heading">三 小结</h2>



<p class="has-text-color" style="color:rgb(0, 0, 0)">这是一个比较简单的问题，系统因为网络问题，或者其它原因导致无法提供正确时间，势必会对运行在其上的应用系统带来一些问题。这里做一个简洁记录。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">ntp服务端查查系统是否提供ntp时间服务，以及其运行的端口是否正常：</p>



<pre class="wp-block-code"><code>systemctl status chronyd

ss -nltp|grep 123
netstat -anp|grep 123
netstat -anp|grep udp</code></pre>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">ntp客户端，查看是否可以连接到ntp server并执行时间同步，此时无法通过常规的telnet ntp_server_ip 123命令来验证。</p>



<pre class="wp-block-code"><code>chronyc resource -v
#或者
ntpdate -q NTP_server_ip</code></pre>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">手工通过ntpdate命令来同步时间</p>



<pre class="wp-block-code"><code>ntpdate NTP_server_ip</code></pre>



<p>&nbsp;</p>
<p><a href="http://www.knockatdatabase.com/2026/07/22/how-to-config-ntp-server-on-kylin-v10/">如何在信创麒麟V10 ARM64位机器上通过配置chronyd作为ntp服务器来同步系统时间</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2026/07/22/how-to-config-ntp-server-on-kylin-v10/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>如何在麒麟V10 ARM64服务器上安装配置1个FE2个BE节点的Doris环境</title>
		<link>http://www.knockatdatabase.com/2026/07/21/how-to-config-doris-fe-two-be-on-kylin-arm64-linux/</link>
					<comments>http://www.knockatdatabase.com/2026/07/21/how-to-config-doris-fe-two-be-on-kylin-arm64-linux/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Mon, 20 Jul 2026 23:58:28 +0000</pubDate>
				<category><![CDATA[doris]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=2741</guid>

					<description><![CDATA[<p>零 项目背景和环境说明 近期，某项目需要采用信创国产化服务器，需要把系统迁移部署上去。下述是服务器操作系统和内核版本信息： &#160; 项目中有用到Doris中间件，结合项目资源和服务器配置的考虑，准备部署1个FE节点2个BE节点的Doris环境，实际生产环境，建议至少3个BE节点。 IP 角色 OS内核 OS架构 Doris版本 安装目录&#124;配置路径 10.193.120.45 FE 4.19.90-89.11.v2401.ky10.aarch64 aarch64 2.1.11 /dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/ 10.193.120.45 BE 4.19.90-89.11.v2401.ky10.aarch64 aarch64 2.1.11 /dmdata/doris/apache-doris-2.1.11-bin-arm64/be 10.193.120.46 BE 4.19.90-89.11.v2401.ky10.aarch64 aarch64 2.1.11 /dmdata/doris/apache-doris-2.1.11-bin-arm64/be 一 具体配置和操作步骤 0 10.193.120.45安装配置FE 官网下载：https://doris.apache.org/download 选择对应的版本和架构。具体步骤略。 查阅Doris官方文档上关于安装配置的前置条件和设置如下，https://doris.apache.org/docs/2.1/install/preparation/cluster-planning &#160; 具体操作执行步骤如下： &#160; &#160; 修改/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/conf/fe.conf配置文件中的，priority_networks参数，其它保持不变。 &#160; 具体操作如下： &#160; 至此，Doris的FE节点已经配置并启动完成。 1 10.193.120.45安装配置BE 在启动运行BE节点之前，我们先通过访问Doris FE，把本机添加为BE：alter system add backend &#34;10.193.120.45:9050&#34;; &#160; 配置文件中，只需要修改priority_networks和JAVA_HOME这2个参数即可，其它保留默认。 /dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/start_be.sh &#38; &#160; 再查看backend状态： &#160; 至此，看到BE状态已经正常，Alive: true。我们的1个FE+1个BE节点已经配置部署完成。 2 将10.193.20.46作为新的BE添加到Doris cluster 具体需要修改和配置的项目和10.193.20.45服务器配置一样，具体执行过程省略。 &#160; 这里，我们采用和10.193.20.45服务器上保持一致的路径和版本，以及配置文件内容也保持一致：只修改priority_networks和JAVA_HOME这2个参数。 &#160; 启动BE服务之后，我们看到BE服务监听在了多个端口：8040、8060、9050、9060。 &#160; 这里看到新be已经添加成功。但是45机器上的be节点是失败的，具体原因以及分析策略，会在另外一篇进行讨论。 3 设置doris 管理用户root口令 默认情况下，Doris管理账户root的口令是空的，比较不安全，我们需要修改。这里，通过mysql命令行客户端工具，连接之后，进行修改： &#160; 二 小结 我们通过从Doris官网下载ARM64位平台的binary安装包介质文件，在2台信创麒麟V10版本的服务器上，安装配置了1个FE+2个BE的Doris cluster环境。建议在生产环境至少部署3个BE节点，本文中选择2个BE，是基于项目和资源限制，不得已而做出的选择。 &#160; 三 如何将BE和FE设置成systemd管理的系统服务 把BE和FE设置成systemd管理的系统服务，可以： 1 设置FE为systemd管理的系统服务 &#160; 2 设置BE为systemd管理的系统服务 &#160;</p>
<p><a href="http://www.knockatdatabase.com/2026/07/21/how-to-config-doris-fe-two-be-on-kylin-arm64-linux/">如何在麒麟V10 ARM64服务器上安装配置1个FE2个BE节点的Doris环境</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">零 项目背景和环境说明</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">近期，某项目需要采用信创国产化服务器，需要把系统迁移部署上去。下述是服务器操作系统和内核版本信息：</p>


<pre class="wp-block-code"><code>[root@zngg-db-primary-45 ~]# uname -rm
4.19.90-89.11.v2401.ky10.aarch64 aarch64
[root@zngg-db-primary-45 ~]# cat /etc/os-release 
NAME=&quot;Kylin Linux Advanced Server&quot;
VERSION=&quot;V10 (Halberd)&quot;
ID=&quot;kylin&quot;
VERSION_ID=&quot;V10&quot;
PRETTY_NAME=&quot;Kylin Linux Advanced Server V10 (Halberd)&quot;
ANSI_COLOR=&quot;0;31&quot;

[root@zngg-db-primary-45 ~]# </code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">项目中有用到Doris中间件，结合项目资源和服务器配置的考虑，准备部署1个FE节点2个BE节点的Doris环境，实际生产环境，建议至少3个BE节点。</p>


<figure class="wp-block-table"><table><tbody><tr><td><strong>IP</strong></td><td><strong>角色</strong></td><td><strong>OS内核</strong></td><td><strong>OS架构</strong></td><td><strong>Doris版本</strong></td><td><strong>安装目录|配置路径</strong></td></tr><tr><td>10.193.120.45</td><td>FE</td><td>4.19.90-89.11.v2401.ky10.aarch64</td><td>aarch64</td><td>2.1.11</td><td>/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/</td></tr><tr><td>10.193.120.45</td><td>BE</td><td>4.19.90-89.11.v2401.ky10.aarch64</td><td>aarch64</td><td>2.1.11</td><td>/dmdata/doris/apache-doris-2.1.11-bin-arm64/be</td></tr><tr><td>10.193.120.46</td><td>BE</td><td>4.19.90-89.11.v2401.ky10.aarch64</td><td>aarch64</td><td>2.1.11</td><td>/dmdata/doris/apache-doris-2.1.11-bin-arm64/be</td></tr></tbody></table></figure>


<h2 class="wp-block-heading">一 具体配置和操作步骤</h2>


<h3 class="wp-block-heading">0 10.193.120.45安装配置FE</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">官网下载：<a href="https://doris.apache.org/download">https://doris.apache.org/download</a> 选择对应的版本和架构。具体步骤略。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">查阅Doris官方文档上关于安装配置的前置条件和设置如下，<a href="https://doris.apache.org/docs/2.1/install/preparation/cluster-planning">https://doris.apache.org/docs/2.1/install/preparation/cluster-planning</a> </p>


<ol class="wp-block-list">
<li><strong>Disable Transparent Huge Pages</strong></li>



<li><strong>Ensure Sufficient Virtual Memory Area</strong></li>



<li><strong>Reset New Connections on Network Overflow</strong></li>



<li><strong>Increase System&#039;s Open File Descriptors Limit</strong></li>
</ol>


<pre class="wp-block-code"><code>#1 <strong>Disable Transparent Huge Pages</strong>
cat &gt;&gt; /etc/rc.d/rc.local &lt;&lt; EOF
   echo madvise &gt; /sys/kernel/mm/transparent_hugepage/enabled
   echo madvise &gt; /sys/kernel/mm/transparent_hugepage/defrag
EOF
chmod +x /etc/rc.d/rc.local

#2 <strong>Ensure Sufficient Virtual Memory Area

</strong>cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF
vm.max_map_count = 2000000
EOF

# Take effect immediately
sysctl -p

#3 <strong>Reset New Connections on Network Overflow
</strong>cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF
net.ipv4.tcp_abort_on_overflow=1
EOF
# Take effect immediately
sysctl -p

#4 <strong>Increase System&#039;s Open File Descriptors Limit
</strong>vi /etc/security/limits.conf 
root soft nofile 1000000
root hard nofile 1000000</code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">具体操作执行步骤如下：</p>


<pre class="wp-block-code"><code>[root@zngg-db-primary-45 fe]# cat &gt;&gt; /etc/rc.d/rc.local &lt;&lt; EOF
&gt;    echo madvise &gt; /sys/kernel/mm/transparent_hugepage/enabled
&gt;    echo madvise &gt; /sys/kernel/mm/transparent_hugepage/defrag
&gt; EOF
[root@zngg-db-primary-45 fe]# chmod +x /etc/rc.d/rc.local
[root@zngg-db-primary-45 fe]# 

[root@zngg-db-primary-45 fe]# cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF
&gt; vm.max_map_count = 2000000
&gt; EOF
[root@zngg-db-primary-45 fe]# 
[root@zngg-db-primary-45 fe]# # Take effect immediately
[root@zngg-db-primary-45 fe]# sysctl -p
kernel.sysrq = 0
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_syncookies = 1
kernel.dmesg_restrict = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
vm.overcommit_memory = 0
kernel.core_uses_pid = 1
kernel.core_pattern = /dmdata/corefile/core-%e-%p-%s
vm.swappiness = 1
vm.max_map_count = 2000000
[root@zngg-db-primary-45 fe]# 
[root@zngg-db-primary-45 fe]# cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF
&gt; net.ipv4.tcp_abort_on_overflow=1
&gt; EOF
[root@zngg-db-primary-45 fe]# # Take effect immediately
[root@zngg-db-primary-45 fe]# sysctl -p
kernel.sysrq = 0
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_syncookies = 1
kernel.dmesg_restrict = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
vm.overcommit_memory = 0
kernel.core_uses_pid = 1
kernel.core_pattern = /dmdata/corefile/core-%e-%p-%s
vm.swappiness = 1
vm.max_map_count = 2000000
net.ipv4.tcp_abort_on_overflow = 1
[root@zngg-db-primary-45 fe]# </code></pre>


<p>&nbsp;</p>


<pre class="wp-block-code"><code>[root@zngg-db-primary-45 ~]# mkdir -p /dmdata/doris
[root@zngg-db-primary-45 ~]# mv apache-doris-2.1.11-bin-arm64.tar.gz /dmdata/doris/
[root@zngg-db-primary-45 ~]# cd /dmdata/doris/
[root@zngg-db-primary-45 doris]# tar -zxvf apache-doris-2.1.11-bin-arm64.tar.gz 
...
apache-doris-2.1.11-bin-arm64/be/dict/idf.utf8
apache-doris-2.1.11-bin-arm64/be/dict/hmm_model.utf8
[root@zngg-db-primary-45 doris]# ll
total 2882088
drwx------ 5 root root         44 Aug 13  2025 apache-doris-2.1.11-bin-arm64
-rw-r--r-- 1 root root 2951254221 Jul 14  2026 apache-doris-2.1.11-bin-arm64.tar.gz
[root@zngg-db-primary-45 doris]# </code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">修改/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/conf/fe.conf配置文件中的，priority_networks参数，其它保持不变。</p>


<pre class="wp-block-code"><code>	priority_networks = 10.193.120.0/24</code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">具体操作如下：</p>


<pre class="wp-block-code"><code>[root@zngg-db-primary-45 conf]# pwd
/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/conf
[root@zngg-db-primary-45 conf]# ll
total 12
-rw------- 1 root root 4156 Aug 13  2025 fe.conf
-rw------- 1 root root 2627 Aug 13  2025 ldap.conf
drwx------ 2 root root    6 Aug 13  2025 ssl
[root@zngg-db-primary-45 conf]# vi fe.conf 
...
priority_networks = 10.193.120.0/24
...
[root@zngg-db-primary-45 conf]# /dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/bin/start_fe.sh &amp;
[1] 1862210
[root@zngg-db-primary-45 conf]# ps -ef|grep doris
root     1862210 1855004  0 06:35 pts/0    00:00:00 bash /dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/bin/start_fe.sh
root     1862752 1862210 25 06:35 pts/0    00:00:07 /usr/bin/java -Dfile.encoding=UTF-8 -Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xm
x8192m -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintClassHistogramA
fterFullGC -Xloggc:/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/log/fe.gc.log.20260714-063548 -Dlog4j2.formatMsgNoLookups=true -XX:-OmitStackTra
ceInFastThrow -XX:OnOutOfMemoryError=kill -9 %p org.apache.doris.DorisFE
root     1862959 1855004  0 06:36 pts/0    00:00:00 grep --color=auto doris
[root@zngg-db-primary-45 conf]# netstat -anp|grep 1862752
tcp6       0      0 10.193.120.45:9010      :::*                    LISTEN      1862752/java        
tcp6       0      0 :::9020                 :::*                    LISTEN      1862752/java        
tcp6       0      0 :::8030                 :::*                    LISTEN      1862752/java        
tcp6       0      0 :::9030                 :::*                    LISTEN      1862752/java        
unix  2      [ ]         STREAM     CONNECTED     69232423 1862752/java         
unix  2      [ ]         STREAM     CONNECTED     69232417 1862752/java         
unix  2      [ ]         STREAM     CONNECTED     69231708 1862752/java         
unix  3      [ ]         STREAM     CONNECTED     69232606 1862752/java         
unix  3      [ ]         STREAM     CONNECTED     69232607 1862752/java         
[root@zngg-db-primary-45 conf]# mysql -uroot -P 9030 -hlocalhost
ERROR 2002 (HY000): Can&#039;t connect to local MySQL server through socket &#039;/var/lib/mysql/mysql.sock&#039; (2)
[root@zngg-db-primary-45 conf]# mysql -uroot -P 9030 -h10.193.120.45
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MySQL connection id is 0
Server version: 5.7.99

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &#039;help;&#039; or &#039;h&#039; for help. Type &#039;c&#039; to clear the current input statement.

MySQL [(none)]&gt; show frontendsG;

*************************** 1. row ***************************
              Name: fe_9865a9c3_dfe5_4fe6_a4a0_9437b8459c49
              Host: 10.193.120.45
       EditLogPort: 9010
          HttpPort: 8030
         QueryPort: 9030
           RpcPort: 9020
ArrowFlightSqlPort: -1
              Role: FOLLOWER
          IsMaster: true
         ClusterId: 368228512
              Join: true
             Alive: true
 ReplayedJournalId: 33
     LastStartTime: 2026-07-14 06:37:18
     LastHeartbeat: 2026-07-14 06:39:18
          IsHelper: true
            ErrMsg: 
           Version: doris-2.1.11-rc01-97b77e6cda
  CurrentConnected: Yes
1 row in set (40.139 sec)

ERROR: No query specified

MySQL [(none)]&gt; </code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">至此，Doris的FE节点已经配置并启动完成。</p>


<h3 class="wp-block-heading">1 10.193.120.45安装配置BE</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">在启动运行BE节点之前，我们先通过访问Doris FE，把本机添加为BE：alter system add backend &quot;10.193.120.45:9050&quot;;</p>


<pre class="wp-block-code"><code>[root@zngg-db-primary-45 ~]# mysql -uroot -P 9030 -h10.193.120.45
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MySQL connection id is 1
Server version: 5.7.99
...
MySQL [(none)]&gt; show backends;
Empty set (0.007 sec)

MySQL [(none)]&gt; alter system add backend &quot;10.193.120.45:9050&quot;;
Query OK, 0 rows affected (0.046 sec)

MySQL [(none)]&gt; show backends;
+-----------+---------------+---------------+--------+----------+----------+--------------------+---------------+---------------+-------+---------
-------------+-----------+------------------+-------------------+---------------+---------------+---------+----------------+--------------------+-
-------------------------+--------+---------+-----------------------------------------------------------------------------------------------------
----------+-------------------------+----------+
| BackendId | Host          | HeartbeatPort | BePort | HttpPort | BrpcPort | ArrowFlightSqlPort | LastStartTime | LastHeartbeat | Alive | SystemDe
commissioned | TabletNum | DataUsedCapacity | TrashUsedCapacity | AvailCapacity | TotalCapacity | UsedPct | MaxDiskUsedPct | RemoteUsedCapacity | 
Tag                      | ErrMsg | Version | Status                                                                                              
          | HeartbeatFailureCounter | NodeRole |
+-----------+---------------+---------------+--------+----------+----------+--------------------+---------------+---------------+-------+---------
-------------+-----------+------------------+-------------------+---------------+---------------+---------+----------------+--------------------+-
-------------------------+--------+---------+-----------------------------------------------------------------------------------------------------
----------+-------------------------+----------+
| 10275     | 10.193.120.45 | 9050          | -1     | -1       | -1       | -1                 | NULL          | NULL          | false | false   
             | 0         | 0.000            | 0.000             | 1.000 B       | 0.000         | 0.00 %  | 0.00 %         | 0.000              | 
{&quot;location&quot; : &quot;default&quot;} |        |         | {&quot;lastSuccessReportTabletsTime&quot;:&quot;N/A&quot;,&quot;lastStreamLoadTime&quot;:-1,&quot;isQueryDisabled&quot;:false,&quot;isLoadDisable
d&quot;:false} | 0                       |          |
+-----------+---------------+---------------+--------+----------+----------+--------------------+---------------+---------------+-------+---------
-------------+-----------+------------------+-------------------+---------------+---------------+---------+----------------+--------------------+-
-------------------------+--------+---------+-----------------------------------------------------------------------------------------------------
----------+-------------------------+----------+
1 row in set (0.005 sec)

MySQL [(none)]&gt; </code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">配置文件中，只需要修改priority_networks和JAVA_HOME这2个参数即可，其它保留默认。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)"><strong>/dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/start_be.sh &amp;</strong></p>


<pre class="wp-block-code"><code>vi /dmdata/doris/apache-doris-2.1.11-bin-arm64/be/conf/be.conf
...
#2026.07.14
priority_networks = 10.193.120.0/24

<strong># since 1.2, the JAVA_HOME need to be set to run BE process.
# JAVA_HOME=/path/to/jdk/
#2026.07.14
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-0.p01.ky10.p01.aarch64/jre

...

# 启动服务
[root@zngg-db-primary-45 ~]# /dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/start_be.sh &amp;
[1] 1875005
[root@zngg-db-primary-45 ~]# </strong></code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">再查看backend状态：</p>


<pre class="wp-block-code"><code>MySQL [(none)]&gt; show backendsG;
*************************** 1. row ***************************
              BackendId: 10275
                   Host: 10.193.120.45
          HeartbeatPort: 9050
                 BePort: 9060
               HttpPort: 8040
               BrpcPort: 8060
     ArrowFlightSqlPort: -1
          LastStartTime: 2026-07-14 07:18:01
          LastHeartbeat: 2026-07-14 07:18:19
                  Alive: true
   SystemDecommissioned: false
              TabletNum: 22
       DataUsedCapacity: 0.000 
      TrashUsedCapacity: 0.000 
          AvailCapacity: 281.882 GB
          TotalCapacity: 299.850 GB
                UsedPct: 5.99 %
         MaxDiskUsedPct: 5.99 %
     RemoteUsedCapacity: 0.000 
                    Tag: {&quot;location&quot; : &quot;default&quot;}
                 ErrMsg: 
                Version: doris-2.1.11-rc01-97b77e6cda
                 Status: {&quot;lastSuccessReportTabletsTime&quot;:&quot;2026-07-14 07:18:13&quot;,&quot;lastStreamLoadTime&quot;:-1,&quot;isQueryDisabled&quot;:false,&quot;isLoadDisabled&quot;:fa
lse}
HeartbeatFailureCounter: 0
               NodeRole: mix
1 row in set (0.004 sec)

ERROR: No query specified

MySQL [(none)]&gt; </code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">至此，看到BE状态已经正常，Alive: true。我们的1个FE+1个BE节点已经配置部署完成。</p>


<h3 class="wp-block-heading">2 将10.193.20.46作为新的BE添加到Doris cluster</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">具体需要修改和配置的项目和10.193.20.45服务器配置一样，具体执行过程省略。</p>


<pre class="wp-block-code"><code>#<strong>Disable Transparent Huge Pages</strong>
cat &gt;&gt; /etc/rc.d/rc.local &lt;&lt; EOF
   echo madvise &gt; /sys/kernel/mm/transparent_hugepage/enabled
   echo madvise &gt; /sys/kernel/mm/transparent_hugepage/defrag
EOF
chmod +x /etc/rc.d/rc.local


#<strong>Ensure Sufficient Virtual Memory Area

</strong>cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF
vm.max_map_count = 2000000
EOF

# Take effect immediately
sysctl -p


#<strong>Reset New Connections on Network Overflow
</strong>cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF
net.ipv4.tcp_abort_on_overflow=1
EOF

# Take effect immediately
sysctl -p


#<strong>Increase System&#039;s Open File Descriptors Limit

</strong>vi /etc/security/limits.conf 
root soft nofile 1000000
root hard nofile 1000000</code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">这里，我们采用和10.193.20.45服务器上保持一致的路径和版本，以及配置文件内容也保持一致：只修改priority_networks和JAVA_HOME这2个参数。</p>


<pre class="wp-block-code"><code>[root@zngg-db-standby-46 ~]# mkdir -p /dmdata/doris
[root@zngg-db-standby-46 ~]# mv apache-doris-2.1.11-bin-arm64.tar.gz /dmdata/doris/
[root@zngg-db-standby-46 ~]# cd /dmdata/doris/
[root@zngg-db-standby-46 doris]# ll
total 2882088
-rw-r--r-- 1 root root 2951254221 Jul 14 11:38 apache-doris-2.1.11-bin-arm64.tar.gz
[root@zngg-db-standby-46 doris]# tar -zxvf apache-doris-2.1.11-bin-arm64.tar.gz 

...
apache-doris-2.1.11-bin-arm64/be/dict/idf.utf8
apache-doris-2.1.11-bin-arm64/be/dict/hmm_model.utf8
[root@zngg-db-standby-46 doris]# ll
total 2882088
drwx------ 5 root root         44 Aug 13  2025 apache-doris-2.1.11-bin-arm64
-rw-r--r-- 1 root root 2951254221 Jul 14 11:38 apache-doris-2.1.11-bin-arm64.tar.gz
[root@zngg-db-standby-46 doris]# cd apache-doris-2.1.11-bin-arm64/be/conf/
[root@zngg-db-standby-46 conf]# ll
total 20
-rw------- 1 root root 1320 Aug 13  2025 asan_suppr.conf
-rw------- 1 root root 4507 Aug 13  2025 be.conf
-rw------- 1 root root  900 Aug 13  2025 lsan_suppr.conf
-rw------- 1 root root 1529 Aug 13  2025 odbcinst.ini
[root@zngg-db-standby-46 conf]# vi be.conf 
...
#2026.07.14
priority_networks = 10.193.120.0/24

<strong># since 1.2, the JAVA_HOME need to be set to run BE process.
# JAVA_HOME=/path/to/jdk/
#2026.07.14
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-0.p01.ky10.p01.aarch64/jre

...

#启动BE服务
[root@zngg-db-standby-46 conf]# /dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/start_be.sh &amp;
[1] 2290735
[root@zngg-db-standby-46 conf]# ps -ef|grep doris
root     2290735 2286546  1 02:42 pts/0    00:00:00 bash /dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/start_be.sh
root     2291439 2290735 61 02:42 pts/0    00:00:04 /dmdata/doris/apache-doris-2.1.11-bin-arm64/be/lib/doris_be
root     2293179 2286546  0 02:42 pts/0    00:00:00 grep --color=auto doris
[root@zngg-db-standby-46 conf]# netstat -anp|grep 2291439
tcp        0      0 0.0.0.0:9050            0.0.0.0:*               LISTEN      2291439/doris_be    
tcp        0      0 0.0.0.0:8060            0.0.0.0:*               LISTEN      2291439/doris_be    
tcp        0      0 0.0.0.0:9060            0.0.0.0:*               LISTEN      2291439/doris_be    
tcp        0      0 0.0.0.0:8040            0.0.0.0:*               LISTEN      2291439/doris_be    
unix  3      [ ]         STREAM     CONNECTED     76147323 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147543 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76148466 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147540 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147325 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147322 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147324 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147542 2291439/doris_be     
unix  3      [ ]         STREAM     CONNECTED     76147541 2291439/doris_be     
[root@zngg-db-standby-46 conf]# </strong></code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">启动BE服务之后，我们看到BE服务监听在了多个端口：8040、8060、9050、9060。</p>


<pre class="wp-block-code"><code>mysql -uroot -P 9030 -h10.193.120.45

[root@zngg-db-primary-45 ~]# mysql -uroot -P 9030 -h10.193.120.45
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MySQL connection id is 4
Server version: 5.7.99

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &#039;help;&#039; or &#039;h&#039; for help. Type &#039;c&#039; to clear the current input statement.

MySQL [(none)]&gt; show backendsG;
*************************** 1. row ***************************
              BackendId: 10275
                   Host: 10.193.120.45
          HeartbeatPort: 9050
                 BePort: 9060
               HttpPort: 8040
               BrpcPort: 8060
     ArrowFlightSqlPort: -1
          LastStartTime: 2026-07-14 07:18:01
          LastHeartbeat: 2026-07-14 07:34:30
                  Alive: false
   SystemDecommissioned: false
              TabletNum: 22
       DataUsedCapacity: 0.000 
      TrashUsedCapacity: 0.000 
          AvailCapacity: 281.882 GB
          TotalCapacity: 299.850 GB
                UsedPct: 5.99 %
         MaxDiskUsedPct: 5.99 %
     RemoteUsedCapacity: 0.000 
                    Tag: {&quot;location&quot; : &quot;default&quot;}
                 ErrMsg: java.net.ConnectException: Connection refused (Connection refused)
                Version: doris-2.1.11-rc01-97b77e6cda
                 Status: {&quot;lastSuccessReportTabletsTime&quot;:&quot;2026-07-14 07:33:56&quot;,&quot;lastStreamLoadTime&quot;:-1,&quot;isQueryDisabled&quot;:false,&quot;isLoadDisabled&quot;:fa
lse}
HeartbeatFailureCounter: 15529
               NodeRole: 
1 row in set (0.003 sec)

ERROR: No query specified

MySQL [(none)]&gt; alter system add backend &quot;10.193.120.46:9050&quot;;
Query OK, 0 rows affected (0.007 sec)

MySQL [(none)]&gt; show backendsG;
*************************** 1. row ***************************
              BackendId: 10275
                   Host: 10.193.120.45
          HeartbeatPort: 9050
                 BePort: 9060
               HttpPort: 8040
               BrpcPort: 8060
     ArrowFlightSqlPort: -1
          LastStartTime: 2026-07-14 07:18:01
          LastHeartbeat: 2026-07-14 07:34:30
                  Alive: false
   SystemDecommissioned: false
              TabletNum: 22
       DataUsedCapacity: 0.000 
      TrashUsedCapacity: 0.000 
          AvailCapacity: 281.882 GB
          TotalCapacity: 299.850 GB
                UsedPct: 5.99 %
         MaxDiskUsedPct: 5.99 %
     RemoteUsedCapacity: 0.000 
                    Tag: {&quot;location&quot; : &quot;default&quot;}
                 ErrMsg: java.net.ConnectException: Connection refused (Connection refused)
                Version: doris-2.1.11-rc01-97b77e6cda
                 Status: {&quot;lastSuccessReportTabletsTime&quot;:&quot;2026-07-14 07:33:56&quot;,&quot;lastStreamLoadTime&quot;:-1,&quot;isQueryDisabled&quot;:false,&quot;isLoadDisabled&quot;:fa
lse}
HeartbeatFailureCounter: 15536
               NodeRole: 
*************************** 2. row ***************************
              BackendId: 14221
                   Host: 10.193.120.46
          HeartbeatPort: 9050
                 BePort: 9060
               HttpPort: 8040
               BrpcPort: 8060
     ArrowFlightSqlPort: -1
          LastStartTime: 2026-07-16 02:42:35
          LastHeartbeat: 2026-07-16 02:45:04
                  Alive: true
   SystemDecommissioned: false
              TabletNum: 0
       DataUsedCapacity: 0.000 
      TrashUsedCapacity: 0.000 
          AvailCapacity: 281.900 GB
          TotalCapacity: 299.850 GB
                UsedPct: 5.99 %
         MaxDiskUsedPct: 5.99 %
     RemoteUsedCapacity: 0.000 
                    Tag: {&quot;location&quot; : &quot;default&quot;}
                 ErrMsg: 
                Version: doris-2.1.11-rc01-97b77e6cda
                 Status: {&quot;lastSuccessReportTabletsTime&quot;:&quot;2026-07-16 02:44:55&quot;,&quot;lastStreamLoadTime&quot;:-1,&quot;isQueryDisabled&quot;:false,&quot;isLoadDisabled&quot;:fa
lse}
HeartbeatFailureCounter: 0
               NodeRole: mix
2 rows in set (0.003 sec)

ERROR: No query specified

MySQL [(none)]&gt;  </code></pre>


<p>&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">这里看到新be已经添加成功。但是45机器上的be节点是失败的，具体原因以及分析策略，会在另外一篇进行讨论。</p>


<h3 class="wp-block-heading">3 设置doris 管理用户root口令</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">默认情况下，Doris管理账户root的口令是空的，比较不安全，我们需要修改。这里，通过mysql命令行客户端工具，连接之后，进行修改：</p>


<pre class="wp-block-code"><code>#修改Doris <strong>Change Doris Cluster Password
 
</strong>SET PASSWORD = PASSWORD(&#039;Doris5Xa99@2)4&#039;);

MySQL [(none)]&gt; SET PASSWORD = PASSWORD(&#039;Doris5Xa99@2)4&#039;);</code></pre>


<p>&nbsp;</p>


<h2 class="wp-block-heading">二 小结</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">我们通过从Doris官网下载ARM64位平台的binary安装包介质文件，在2台信创麒麟V10版本的服务器上，安装配置了1个FE+2个BE的Doris cluster环境。建议在生产环境至少部署3个BE节点，本文中选择2个BE，是基于项目和资源限制，不得已而做出的选择。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h2 class="wp-block-heading">三 如何将BE和FE设置成systemd管理的系统服务</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">把BE和FE设置成systemd管理的系统服务，可以：</p>


<ol class="wp-block-list">
<li>通过systemctl start|stop|enable|disable doris-fe|doris-be的命令来快速启动、关闭、服务；</li>



<li>可以保证操作系统如果发生重启的话，服务可以随着系统的重启而自动启动。</li>
</ol>


<h3 class="wp-block-heading">1 设置FE为systemd管理的系统服务</h3>


<pre class="wp-block-code"><code>#编辑配置文件
vi /etc/systemd/system/doris-fe.service 
#写入下述内容
[Unit]
Description=Apache Doris FE
After=network-online.target
Wants=network-online.target

[Service]
Type=forking

User=root
Group=root

# &#x2b50; 资源限制
LimitNOFILE=200000
LimitNPROC=65535
LimitCORE=infinity

# &#x2b50; 环境变量（关键！）

# &#x2b50; 启动/停止
ExecStart=/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/bin/start_fe.sh --daemon
ExecStop=/dmdata/doris/apache-doris-2.1.11-bin-arm64/fe/bin/stop_fe.sh

# &#x2b50; 重启策略
Restart=on-failure
RestartSec=20
StartLimitInterval=120
StartLimitBurst=3

KillMode=none
TimeoutStopSec=300

[Install]
WantedBy=multi-user.target

# 执行systemctl daemon-reload

#systemctl start|stop|enable|disable doris-fe
systemctl enable doris-fe
systemctl start doris-fe
systemctl status doris-fe</code></pre>


<p>&nbsp;</p>


<h3 class="wp-block-heading">2 设置BE为systemd管理的系统服务</h3>


<pre class="wp-block-code"><code>#编辑配置文件
vi /etc/systemd/system/doris-be.service 
[Unit]
Description=Apache Doris BE
#在有FE的节点上，要写上After doris-fe.service.单独的BE节点上，不需要After doris-fe.service
After=network-online.target doris-fe.service       
Wants=network-online.target

[Service]
Type=forking

User=root
Group=root

# &#x2b50; 资源限制（BE更高）
LimitNOFILE=200000
LimitNPROC=65535
LimitCORE=infinity


# &#x2b50; 启动/停止
ExecStart=/dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/start_be.sh --daemon
ExecStop=/dmdata/doris/apache-doris-2.1.11-bin-arm64/be/bin/stop_be.sh

# &#x2b50; 重启策略
Restart=on-failure
RestartSec=20
StartLimitInterval=120
StartLimitBurst=3

KillMode=none
TimeoutStopSec=300

[Install]
WantedBy=multi-user.target


# 执行systemctl daemon-reload

#systemctl start|stop|enable|disable doris-be
systemctl enable doris-be
systemctl start doris-be
systemctl status doris-be</code></pre>


<p>&nbsp;</p>

<p><a href="http://www.knockatdatabase.com/2026/07/21/how-to-config-doris-fe-two-be-on-kylin-arm64-linux/">如何在麒麟V10 ARM64服务器上安装配置1个FE2个BE节点的Doris环境</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2026/07/21/how-to-config-doris-fe-two-be-on-kylin-arm64-linux/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>我是如何开通德国N26虚拟银行失败的</title>
		<link>http://www.knockatdatabase.com/2026/02/02/why-i-failed-to-open-germany-n26-bank-account/</link>
					<comments>http://www.knockatdatabase.com/2026/02/02/why-i-failed-to-open-germany-n26-bank-account/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Mon, 02 Feb 2026 07:45:46 +0000</pubDate>
				<category><![CDATA[投资]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1572</guid>

					<description><![CDATA[<p>我是如何开通德国N26虚拟银行失败的</p>
<p><a href="http://www.knockatdatabase.com/2026/02/02/why-i-failed-to-open-germany-n26-bank-account/">我是如何开通德国N26虚拟银行失败的</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">零 开通失败了也许对你们才有参考和借鉴意义</h2>


<p class="has-text-color" style="color: rgb(0, 0, 0)">是的，在网络上看了一些网友、博主的文章和视频都是说正常开通成功的。但是，我的开通失败经历，也许可以帮助到你——我的读者、我的朋友——帮助你们如何避免开通n26失败。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h2 class="wp-block-heading">一 复盘猜测我开通失败的原因</h2>


<ol class="wp-block-list">
<li>申请开户过程中切换了网络环境，从WiFi切换到无线流量；开户过程中，尽量不要切换网络环境，如果有开通全局VPN代理的话，一旦切换，就会发生IP显著变化</li>



<li>过程中，拍摄护照期间花了太多时间；由于我的旧护照已经到期，这本是刚刚是新换的，可能反光比较严重，加上新版本护照的激光防伪条码在某些拍照角度下要么太不明显，要么就太明显；</li>



<li>人脸识别和自拍过程中花了太多时间；</li>



<li>n26账户类型时，<span style="color: rgba(203, 145, 47, 1);"><s>我选择了business purpose</s></span>；可能personal会更好一些</li>



<li>n26账户主要用于接收哪个国家|地区的付款：<span style="color: rgba(203, 145, 47, 1);">我选择了香港</span>，可能选择一个欧盟<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1ea-1f1fa.png" alt="🇪🇺" class="wp-smiley" style="height: 1em; max-height: 1em;" />国家会更好一些</li>



<li>开通n26账户主要目的；<span style="color: rgba(203, 145, 47, 1);"><s>我选择了接收薪资</s></span>；可能选择在线购物或其它会好一些；</li>
</ol>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h2 class="wp-block-heading">二 准备工作</h2>


<ol class="wp-block-list">
<li>非大陆手机号，用于接收短信验证码；</li>



<li>有效期正常的护照；</li>



<li>全局VPN代理；</li>



<li>奥地利虚拟地址；
<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8870-472x1024.png" alt=""/></figure>
</li>



<li>手机上下载并安装n26 app</li>
</ol>


<h2 class="wp-block-heading">三 第一次开通过程</h2>


<h3 class="wp-block-heading">1 开启WiFi，全局VPN代理：</h3>


<h3 class="wp-block-heading">2 打开n26,注册新账号</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8871_copy_2-472x1024.jpg" alt=""/></figure>


<h3 class="wp-block-heading">3居住地区，选择奥地利</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8872-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">此时，有个提示报错，原因是我的iPhone 15的操作系统版本太低了。根据提示，重新升级iOS，继续开始。</p>


<h3 class="wp-block-heading">4 重新开始申请</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">此时，升级系统加上其它杂事弄一弄，时间来到了下午16：28。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8873-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">5居住地区，选择Austria奥地利</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8874-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">6又提示系统需要升级</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8875-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">7 退出，重新继续开始</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8876-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">8 再开始</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8877-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">9填写地区奥地利</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8878-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">10提示隐私信息如何保护和使用</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8879-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">选择accept all并继续</p>


<h3 class="wp-block-heading">11 根据提示填写email</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8880-1-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">12 提示是否打开n26 app通知</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8881-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">这里，先选择跳过。</p>


<h3 class="wp-block-heading">13 填写姓名、出生日期，firstname填写名字，lastname填姓</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8882-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">14选择性别</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8883-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">15国籍填写China</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8884-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">16 填写出生城市、和邀请码(如果有，)</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8886-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8887-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">17 设置登录密码</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8888-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">18 邮件确认</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8889-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">19 打开邮件，点击链接确认完毕</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8890-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">20 重新open the N26 app</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8891-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">21 输入非大陆手机号接受短信验证码</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8892-1-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8894-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">22 输入家庭地址</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">这里输入之前通过<a href="https://www.fakeaddressgenerator.com/">https://www.fakeaddressgenerator.com/</a> 随机生成的Austria的地址，实际地址可能有略微不同，在N26 app上，可以根据城市大概搜索并定位一个地址。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8895-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8896-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8897-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8898-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">23选择账号类型</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">我注册时，阴差阳错的选择了business purpose；</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8899-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">24 开始进入Know Your Customer环节回答问题</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8900-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">25雇佣状态，建议选受雇</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8901-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">26工作所属行业类别</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8902-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">27 主要收入来源</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8903-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">28税后平均月薪</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8904-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">29主要接收哪个国家|地区的付款</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">这里阴差阳错的选择了香港，因为我用香港手机号接收的短信，以为填这个会比较容易过。也许这是一个错误的选择。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8905-1-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">30 申请开通n26账户的主要用途</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8906-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">31 kyc完成之后。开始校验身份信息</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8907-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">32 校验身份信息的使用你的个人信息的申明和授权</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8908-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">33 选择护照签发国家China<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f1e8-1f1f3.png" alt="🇨🇳" class="wp-smiley" style="height: 1em; max-height: 1em;" /></h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8909-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">34 选择证件类型，passport</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8910-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">35 准备护照</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8911-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">36 根据提示进行拍照</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">此时第一次会调用摄像头拍摄你护照的第一页，就是包含你的照片的那页。这个时候，拍摄的时候，有些小的tips：</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">光线充足，避免反光，否则的话，接下来N26的OCR无法通过图片读取你的个人信息，</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">护照首页的4个角都包含进去拍摄；</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">第一次拍摄之后，系统会担心一张照片无法准确读取你的个人信息，还会要求你再拍摄一张护照首页的图片。不过，这一次，需要手机摄像头稍微倾斜一点儿，进行拍摄并上传。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">如果2张照片都拍摄完成的话，系统会通过OCR读取到你的个人身份信息，并且会弹出一个页面，让你去确认OCR读取到的信息，是否和你的真实护照信息一致？这个是我后面重复注册时，看到有弹出OCR读取到信息并回显之后，才知道的。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">我当时，尝试多次之后，依然没有成功拍摄到满足系统要求的我的护照首页信息，每次都是弹出一个页面，让我手工填写我的个人信息。但凡是需要手工输入个人信息时，多半就是你拍摄的护照首页信息，无法被N26系统的OCR识别，进而会导致你一直卡在这个环节。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">注意，我这里的截图是当时系统弹出，让我手工输入我的证件号，证件到期时间，以及我的出生日期的。并不是我们希望OCR识别并自动读取个人信息的页面。哭死在这儿了……</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8913-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">37 上传信息</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">正常情况下，护照拍摄没问题，OCR识别也没问题的话，这个上传你的个人信息页面会非常快。<span style="color: rgba(212, 76, 71, 1);">如果一直在这个环节转圈圈，多半儿是护照信息拍摄识别不过关</span>。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8914-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">果然，提示报错了：</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8915-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">继续在拍摄护照环节折腾，时间来到了17:16分。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8916-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">38 继续折腾，页面有提示报错了</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">时间来到了17:41分，注意看，此时我有点儿不耐心了，以为是WiFi的问题，因为我的护照迟迟没法拍成系统OCR可以识别到的标准，以为是客厅开了主厅大吊灯太亮太反光，我就去房间拍摄，房间WiFi信号不太好，就切换到数据流量网络了。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">也许这个切换网络是一个导致申请开户失败的原因。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8917-1-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">39 系统OCR终于识别了护照信息</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">能识别到护照信息，是不知道踩到了哪一坨狗屎，拍摄的2张照片，正好符合他们OCR的标准。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8918-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">识别出我的国籍和出生地，和护照上的实际信息也是一致的</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8919-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">正确识别出姓名和性别</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8920-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">40  开始上传信息</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8921-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">41 系统要求获取我的定位，可以提供实际地址</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8922-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">42 开始签名</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8923-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">43 review 证件信息</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8924-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">44再次接收短信验证码</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8925-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">45 快要结束了</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8926-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">46 有点儿激动</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/IMG_8927-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">47 快好了</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_8928-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_8929-472x1024.png" alt=""/></figure>


<h3 class="wp-block-heading">48 去等着能否开户成功的邮件吧</h3>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_8930-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">49等来了个开户不成功</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">因为迟迟没有收到官方的开户邮件通知，转天，我就在App上登录账号，结果是个开户失败了。</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_8934-472x1024.png" alt=""/></figure>


<h2 class="wp-block-heading">四 第二次继续尝试</h2>


<h3 class="wp-block-heading">50 后续</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">因为我的旧护照被收起来了，申领换发新护照之后，要继续交给单位代管。我没有太多时间继续等待了。于是，我用另外一个邮件尝试了重新申请。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">时间来到了2026年1月26日15：00，我重新申请时，提示个这：</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_8939-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">继续折腾，</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_8952-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">依然错误，没法继续折腾了。得去搬砖坐一会儿牛马了。</p>


<h3 class="wp-block-heading">51 2026年1月27日上午继续</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">改用<span style="color: rgba(212, 76, 71, 1);">我的163邮箱，和改一个用户名试试看能否注册成功</span>：</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">吸取前面注册的教训：主要收款国家或地区，<span style="color: rgba(212, 76, 71, 1);">选择德国，账户类型选择个人使用，用途选择在线购物</span>。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9063-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9064-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9065-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9066-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9067-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9068-1-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9069-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9070-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9071-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9072-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9073-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9074-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">剩下的不再继续贴图了，，，，</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/E7BD91E69893E982AEE7AEB1E7A7BBE58AA8E98082E9858DE78988-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/E7BD91E69893E982AEE7AEB1E7A7BBE58AA8E98082E9858DE78988_2-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">等着开户的结果邮件：</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9090-472x1024.png" alt=""/></figure>


<h2 class="wp-block-heading">五 最后的死心</h2>


<h3 class="wp-block-heading">52 再继续，发邮件联系客服</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">2026年1月27日，刷到Twitter上，有网友说，可以通过给n26客服发邮件请求删除个人开户信息，并重新开户。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">于是，我用3dian14@gmail.com给客服发了邮件，此时发现用我第一次的邮件登录时，直接报错邮件地址和密码不匹配。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">并在邮件里，把报错截图给他们。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9098-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9099-1-472x1024.png" alt=""/></figure>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9100-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<h3 class="wp-block-heading">53 彻底死心</h3>


<p class="has-text-color" style="color: rgb(0, 0, 0)">最后，收到了他们的德语回复的邮件:</p>


<figure class="wp-block-image size-large"><img decoding="async" src="http://www.knockatdatabase.com/wp-content/uploads/2026/02/IMG_9101-472x1024.png" alt=""/></figure>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">大意是说，经过他们的审核，无法开户。</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>


<p class="has-text-color" style="color: rgb(0, 0, 0)">&nbsp;</p>

<p><a href="http://www.knockatdatabase.com/2026/02/02/why-i-failed-to-open-germany-n26-bank-account/">我是如何开通德国N26虚拟银行失败的</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2026/02/02/why-i-failed-to-open-germany-n26-bank-account/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>关于Java中的final关键字小结</title>
		<link>http://www.knockatdatabase.com/2026/01/06/java-final-field-method-class/</link>
					<comments>http://www.knockatdatabase.com/2026/01/06/java-final-field-method-class/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 08:42:18 +0000</pubDate>
				<category><![CDATA[算法和数据结构]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1329</guid>

					<description><![CDATA[<p>一 final可以修饰的范围 💡 二 final修饰的字段 1 final修饰字段的限制和注意事项 当字段被指定为final时，如果该类的对象被实例化之后，则该字段值不可再次被修改。也就是说如果某个类里有个字段是final的，new一个该类的对象之后，则该对象的该字段值不允许再次被修改了。 同时，在IDEA里进行代码测试验证时，发现某个类里定义了一个final字段时，IDEA会主动提示，我们是否通过构造函数来初始化该字段，或者提示在定义该字段时就对其进行初始化，或者通过无参构造方法来初始化该字段，再或者把该字段定义为非final修饰。 此外，当字段被定义为final时，通过IDEA帮我们生成getter()和setter()时，会发现，IDEA自动识别了，无需或者说不可以为该字段创建setter()方法，只能生成getter()方法。 2 测试验证代码和执行结果 运行结果： 三 final修饰方法 1 为啥需要通过final来修饰方法 如果类中的某些特定方法，不希望被子类重写override，则可以在父类上把该方法指定为final。 比如Calendar类中的getTime()和setTime()方法，就被定义为final： 如果某个类被定义为final，则该类中的所有方法自动变为final，而字段却不会自动变成final。 四 final修饰类 1 为啥需要final修饰类 如果不希望某个类被继承，则可以把该类设计为final。 2 final修饰的类有哪些特征 如果类被定义为final，则该类的所有方法自动变成final，但是字段却不是默认变为final。 3 常见的哪些类被定义为final LocalData，LocalTime，MinguoDate，String 比较有意思的是，可以看到Java里还单独为台湾定义了一个民国日期，专门用于处理台湾习惯把1912年当做民国元年来处理的习惯。但是JDK文档里说明的好像有点儿政治味儿了。 4 为什么String被定义为final String被设计为 final，主要是出于安全性、性能和线程安全这三个核心维度的考量 4.1. 核心安全性 (Security) String 在 Java 中被广泛用于参数传递，例如网络连接的 URL、文件路径、数据库连接地址等。 4.2. 线程安全性 (Thread Safety) 由于 final 类的对象通常设计为不可变 (Immutable)： 4.3. 性能优化与常量池 (Optimization) 这是 String 设计为 final 最直观的原因： 5 补充说明解决 Calendar 的“历史遗留”痛点 早期的 java.util.Date 和 Calendar 是可变的 (Mutable)，这被认为是 Java 设计史上最大的失误之一：</p>
<p><a href="http://www.knockatdatabase.com/2026/01/06/java-final-field-method-class/">关于Java中的final关键字小结</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">一 final可以修饰的范围</h1>



<p> <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<ul class="wp-block-list">
<li>字段</li>



<li>方法</li>



<li>类 </li>
</ul>



<h1 class="wp-block-heading">二 final修饰的字段</h1>



<h2 class="wp-block-heading">1 final修饰字段的限制和注意事项</h2>



<p>当字段被指定为final时，如果该类的对象被实例化之后，则该字段值不可再次被修改。也就是说如果某个类里有个字段是final的，new一个该类的对象之后，则该对象的该字段值不允许再次被修改了。</p>



<p>同时，在IDEA里进行代码测试验证时，发现某个类里定义了一个final字段时，IDEA会主动提示，我们是否通过构造函数来初始化该字段，或者提示在定义该字段时就对其进行初始化，或者通过无参构造方法来初始化该字段，再或者把该字段定义为非final修饰。</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="789" height="411" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/image.png" alt="" class="wp-image-1331" srcset="http://www.knockatdatabase.com/wp-content/uploads/2026/01/image.png 789w, http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-300x156.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-768x400.png 768w" sizes="(max-width: 789px) 100vw, 789px" /></figure>



<p>此外，当字段被定义为final时，通过IDEA帮我们生成getter()和setter()时，会发现，IDEA自动识别了，无需或者说不可以为该字段创建setter()方法，只能生成getter()方法。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="819" height="545" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-1.png" alt="" class="wp-image-1333" srcset="http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-1.png 819w, http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-1-300x200.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-1-768x511.png 768w" sizes="(max-width: 819px) 100vw, 819px" /></figure>



<h2 class="wp-block-heading">2 测试验证代码和执行结果</h2>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">package com.knockatdatabase;

import java.time.LocalDate;
import java.util.Calendar;

/**
 * Hello world!
 *
 */
public class App 
{
    private final String name;

    public App(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public static void main(String[] args )
    {
        App app = new App(&quot;KnockatDatabase&quot;);
        System.out.println(app.getName());
        App app2 = new App(&quot;KnockatDatabase~~~~~~~~~~~~~~~~~~~~&quot;);
        System.out.println(app2.getName());

        System.out.println( &quot;Hello World!&quot; );
        Calendar.getInstance().getTime();
        LocalDate today = LocalDate.now();
    }
}

</pre></div>



<p>运行结果：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">/Users/huangwei/Software/jdk-24.0.2.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:60649,suspend=y,server=n -agentpath:/private/var/folders/8t/v80nxtp52454n5b1zs20w0y80000gn/T/idea_libasyncProfiler_dylib_temp_folder/libasyncProfiler.dylib=version,jfr,event=wall,interval=10ms,cstack=no,file=/Users/huangwei/IdeaSnapshots/App_2026_01_06_112556.jfr,log=/private/var/folders/8t/v80nxtp52454n5b1zs20w0y80000gn/T/App_2026_01_06_112556.jfr.log.txt,logLevel=DEBUG -javaagent:/Users/huangwei/Library/Caches/JetBrains/IntelliJIdea2024.3/captureAgent/debugger-agent.jar -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Ddebugger.agent.enable.coroutines=true -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /Users/huangwei/IdeaProjects/java_core_11th_edition/chap05/target/classes:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar com.knockatdatabase.App
Connected to the target VM, address: '127.0.0.1:60649', transport: 'socket'
KnockatDatabase
KnockatDatabase~~~~~~~~~~~~~~~~~~~~
Hello World!
Disconnected from the target VM, address: '127.0.0.1:60649', transport: 'socket'

Process finished with exit code 0
</pre></div>



<h1 class="wp-block-heading">三 final修饰方法</h1>



<h2 class="wp-block-heading">1 为啥需要通过final来修饰方法</h2>



<p>如果类中的某些特定方法，不希望被子类重写override，则可以在父类上把该方法指定为final。</p>



<p>比如Calendar类中的getTime()和setTime()方法，就被定义为final：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">    /**
     * Returns a {@code Date} object representing this
     * {@code Calendar}'s time value (millisecond offset from the &lt;a
     * href=&quot;#Epoch&quot;&gt;Epoch&lt;/a&gt;&quot;).
     *
     * @return a {@code Date} representing the time value.
     * @see #setTime(Date)
     * @see #getTimeInMillis()
     */
    public final Date getTime() {
        return new Date(getTimeInMillis());
    }

    /**
     * Sets this Calendar's time with the given {@code Date}.
     * &lt;p&gt;
     * Note: Calling {@code setTime()} with
     * {@code Date(Long.MAX_VALUE)} or {@code Date(Long.MIN_VALUE)}
     * may yield incorrect field values from {@code get()}.
     *
     * @param date the given Date.
     * @see #getTime()
     * @see #setTimeInMillis(long)
     * @throws NullPointerException if {@code date} is {@code null}
     */
    public final void setTime(Date date) {
        Objects.requireNonNull(date, &quot;date must not be null&quot;);
        setTimeInMillis(date.getTime());
    }
</pre></div>



<p>如果某个类被定义为final，则该类中的所有方法自动变为final，而字段却不会自动变成final。</p>



<h1 class="wp-block-heading">四 final修饰类</h1>



<h2 class="wp-block-heading">1 为啥需要final修饰类</h2>



<p>如果不希望某个类被继承，则可以把该类设计为final。</p>



<h2 class="wp-block-heading">2 final修饰的类有哪些特征</h2>



<p>如果类被定义为final，则该类的所有方法自动变成final，但是字段却不是默认变为final。</p>



<h2 class="wp-block-heading">3 常见的哪些类被定义为final</h2>



<p>LocalData，LocalTime，MinguoDate，String</p>



<p>比较有意思的是，可以看到Java里还单独为台湾定义了一个民国日期，专门用于处理台湾习惯把1912年当做民国元年来处理的习惯。但是JDK文档里说明的好像有点儿政治味儿了。</p>



<figure class="wp-block-image size-full"><img decoding="async" width="904" height="685" src="http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-2.png" alt="" class="wp-image-1334" srcset="http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-2.png 904w, http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-2-300x227.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2026/01/image-2-768x582.png 768w" sizes="(max-width: 904px) 100vw, 904px" /></figure>



<h2 class="wp-block-heading">4 为什么String被定义为final</h2>



<p>String被设计为 <strong>final</strong>，主要是出于<strong>安全性、性能</strong>和<strong>线程安全</strong>这三个核心维度的考量</p>



<h3 class="wp-block-heading">4.1. 核心安全性 (Security)</h3>



<p><code>String</code> 在 Java 中被广泛用于参数传递，例如网络连接的 URL、文件路径、数据库连接地址等。</p>



<ul class="wp-block-list">
<li><strong>防止恶意劫持：</strong> 如果 <code>String</code> 不是 final 的，开发者可以继承它并重写方法。假设一个系统方法预期接收一个路径，但你传入了一个虚假的子类，在校验通过后，子类通过重写逻辑返回了另一个危险路径，这会导致严重的系统安全漏洞。</li>



<li><strong>类加载机制：</strong> String 常用于类加载器的参数。如果 String 可变，加载过程中的类名可能被修改，从而导致加载错误的类。</li>
</ul>



<h3 class="wp-block-heading">4.2. 线程安全性 (Thread Safety)</h3>



<p>由于 <code>final</code> 类的对象通常设计为<strong>不可变 (Immutable)</strong>：</p>



<ul class="wp-block-list">
<li><strong>无锁并发：</strong> 不可变对象可以在多个线程之间自由共享，而不需要任何同步机制（Synchronization）。这极大地提升了并发性能。</li>



<li><strong>消除副作用：</strong> 你不用担心一个方法在处理字符串或日期时，另一个线程悄悄修改了它的值。</li>
</ul>



<h3 class="wp-block-heading">4.3. 性能优化与常量池 (Optimization)</h3>



<p>这是 <code>String</code> 设计为 final 最直观的原因：</p>



<ul class="wp-block-list">
<li><strong>字符串常量池 (String Pool)：</strong> 只有当 String 不可变时，常量池才有意义。如果多个变量指向内存中同一个 &#8220;abc&#8221;，而其中一个变量修改了它，其他变量都会受到影响。通过设计成 final，Java 可以实现字符串的复用，节省大量堆内存。</li>



<li><strong>Hash 缓存：</strong> 由于 String 是不可变的，它的 <code>hashCode</code> 只需要在创建时计算一次并缓存起来。这使得 String 作为 <code>HashMap</code> 的 key 时效率极高。</li>
</ul>



<h2 class="wp-block-heading">5 补充说明解决 Calendar 的“历史遗留”痛点</h2>



<p>早期的 <code>java.util.Date</code> 和 <code>Calendar</code> 是<strong>可变的 (Mutable)</strong>，这被认为是 Java 设计史上最大的失误之一：</p>



<ul class="wp-block-list">
<li><strong>易错性：</strong> 在旧代码中，如果你把一个 Calendar 对象传给两个方法，方法 A 修改了月份，方法 B 的逻辑就会莫名其妙地出错。</li>



<li><strong>Java 8 的改进：</strong> 正是因为 <code>Calendar</code> 的设计缺陷（非 final 且可变），Java 8 引入了全新的 <code>java.time</code> 包。
<ul class="wp-block-list">
<li><code>LocalDate</code>、<code>ZonedDateTime</code> 、<code>LocalTime、MinguoDate</code>等全都是 <strong>final</strong> 的。</li>



<li>它们是<strong>不可变对象</strong>，任何修改操作都会返回一个新的实例，而不是修改原对象。</li>
</ul>
</li>
</ul>
<p><a href="http://www.knockatdatabase.com/2026/01/06/java-final-field-method-class/">关于Java中的final关键字小结</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2026/01/06/java-final-field-method-class/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>The little book of common sense investing读后感</title>
		<link>http://www.knockatdatabase.com/2025/12/24/the-little-book-of-common-sense-investing/</link>
					<comments>http://www.knockatdatabase.com/2025/12/24/the-little-book-of-common-sense-investing/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Wed, 24 Dec 2025 03:48:22 +0000</pubDate>
				<category><![CDATA[投资]]></category>
		<category><![CDATA[读书点亮生活]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1325</guid>

					<description><![CDATA[<p>先说读这本书的缘由，国庆期间，逛YouTube的时候，在其中一期我认为还不错的节目里，youtuber推荐了这两本书：《The little book of common sense investing》十周年纪念版和《Millionaire Teacher》第二版。本着对youtuber和视频节目质量的认可和好感，顺手找来电子档翻了翻，就去忙我的那期关于期权的视频节目录制的事情了。节后，把这两本书的电子档还有一本名为《spring in action》第六版打包丢给之前我一直从他们家打印电子文档的淘宝店主了，收到打印的纸质书之后，就借着上下班在地铁通勤的过程中开始读。哦，那本spring的书还停留在在Mac上翻看到前3章的进度。 再来说说读后感，整体来讲，这是一本比较有投资指导意义的书，尤其是对于retail investor而言。作者出身正统的金融学院派系，讲事实摆道理，画图表作对比，告诉普通投资者：The only way to guarantee your fair share of stock market returns，无他，就是去买低费率的S&#38;P 500 ETF。 全书算是一本阅读小册子，章节组织的比较细，一共167页，却分了20章。本书作者，John Bogle上世纪40年代毕业于普林斯顿，70年代创立了第一支指数基金，他也是先锋集团Vanguard group的创始人。Vanguard令人称赞的多数是其低费率高回报的ETF，在全球几大EFT机构里绝对算是叫得上号的，论资排辈的话，必须得安排到主桌，还得是比较重要的座位上。由于John Bogle的学院派风格，整本书读起来却不是那么通畅，尤其是刚上手时。随着阅读的逐步推进，慢慢习惯作者的表达方式和遣词造句之后，阅读卡顿的症状会略微好转。比如，作者在第98页写到： If you can avoid jumping on the bandwagon . . . And if professional investment consultants are wise enough—or lucky enough —to keep their clients from jumping on the latest and hottest bandwagon (for example, the tech-stock craze of the late 1990s, reflected in the mania for funds investing in “new economy” stocks), their clients may earn returns that easily surpass the disappointing returns achieved by fund investors as a group. “如果专业投资顾问足够聪明或者足够幸运的话，避免把他们的客户指向当前最新最热的旅游花车上（比如，上世纪90年代的热门科技股，相当于是基金投资比较疯狂的“新经济”股票上），他们客户的投资回报或许能轻松超越那些投资回报令人失望的基金的投资者。 作者在这里用了2个看似简单，其实不太好懂的词：bandwagon和mania。我都需要借助字典工具，才能搞懂它们。尤其是那个mania，明明作者在前面已经用过了craze，后面用了一个同义词mania。可见，读John Bogle的这本书，需要花一点点时间和精力，会多辛苦一点。但，这不正是读书过程中比较有趣的部分吗？ 另外，作者喜欢时不时的引经据典，给自己贴金，把别人对他的正向反馈和评价称赞，引用起来，并散落到全书里： &#8220;Rather than listen to the siren songs from investment managers, investors-large and smallshould instead read Jack Bogle&#8217;s The Little Book of Common Sense Investing.&#8221; -WARREN BUFFETT 书皮儿封面就有传奇人物的背书。 虽说作者John bogle算得上投资界比较有影响力的人物不假，可在全书后半部分，作者拿自己和美国开国元勋之一的本杰明富兰克林，在个人品行道德诸如勤奋节俭以及对财富的理解做了一番对比。 On the markets: Franklin: One man may be more cunning than another, but not more cunning than everybody else. Bogle: Don’t think that you know...</p>
<p><a href="http://www.knockatdatabase.com/2025/12/24/the-little-book-of-common-sense-investing/">The little book of common sense investing读后感</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<p>先说读这本书的缘由，国庆期间，逛YouTube的时候，在其中一期我认为还不错的节目里，youtuber推荐了这两本书：《The little book of common sense investing》十周年纪念版和《Millionaire Teacher》第二版。本着对youtuber和视频节目质量的认可和好感，顺手找来电子档翻了翻，就去忙我的那期关于期权的视频节目录制的事情了。节后，把这两本书的电子档还有一本名为《spring in action》第六版打包丢给之前我一直从他们家打印电子文档的淘宝店主了，收到打印的纸质书之后，就借着上下班在地铁通勤的过程中开始读。哦，那本spring的书还停留在在Mac上翻看到前3章的进度。</p>



<p>再来说说读后感，整体来讲，这是一本比较有投资指导意义的书，尤其是对于retail investor而言。作者出身正统的金融学院派系，讲事实摆道理，画图表作对比，告诉普通投资者：The only way to guarantee your fair share of stock market returns，无他，就是去买低费率的S&amp;P 500 ETF。</p>



<p>全书算是一本阅读小册子，章节组织的比较细，一共167页，却分了20章。本书作者，John Bogle上世纪40年代毕业于普林斯顿，70年代创立了第一支指数基金，他也是先锋集团Vanguard group的创始人。Vanguard令人称赞的多数是其低费率高回报的ETF，在全球几大EFT机构里绝对算是叫得上号的，论资排辈的话，必须得安排到主桌，还得是比较重要的座位上。由于John Bogle的学院派风格，整本书读起来却不是那么通畅，尤其是刚上手时。随着阅读的逐步推进，慢慢习惯作者的表达方式和遣词造句之后，阅读卡顿的症状会略微好转。比如，作者在第98页写到：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>If you can avoid jumping on the bandwagon . . .</strong></p>



<p>And if professional investment consultants are wise enough—or lucky enough —to keep their clients from jumping on the latest and hottest bandwagon (for example, the tech-stock craze of the late 1990s, reflected in the mania for funds investing in “new economy” stocks), their clients may earn returns that easily surpass the disappointing returns achieved by fund investors as a group.</p>
</blockquote>



<p>“如果专业投资顾问足够聪明或者足够幸运的话，避免把他们的客户指向当前最新最热的旅游花车上（比如，上世纪90年代的热门科技股，相当于是基金投资比较疯狂的“新经济”股票上），他们客户的投资回报或许能轻松超越那些投资回报令人失望的基金的投资者。</p>



<p>作者在这里用了2个看似简单，其实不太好懂的词：bandwagon和mania。我都需要借助字典工具，才能搞懂它们。尤其是那个mania，明明作者在前面已经用过了craze，后面用了一个同义词mania。可见，读John Bogle的这本书，需要花一点点时间和精力，会多辛苦一点。但，这不正是读书过程中比较有趣的部分吗？</p>



<p>另外，作者喜欢时不时的引经据典，给自己贴金，把别人对他的正向反馈和评价称赞，引用起来，并散落到全书里：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>&#8220;Rather than listen to the siren songs from investment managers, investors-large and smallshould instead read Jack Bogle&#8217;s The Little Book of Common Sense Investing.&#8221;</p>



<p>-WARREN BUFFETT</p>
</blockquote>



<p>书皮儿封面就有传奇人物的背书。</p>



<p>虽说作者John bogle算得上投资界比较有影响力的人物不假，可在全书后半部分，作者拿自己和美国开国元勋之一的本杰明富兰克林，在个人品行道德诸如勤奋节俭以及对财富的理解做了一番对比。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>On the markets:</strong></p>



<p><strong>Franklin</strong>: One man may be more cunning than another, but not more cunning than everybody else.</p>



<p><strong>Bogle</strong>: Don’t think that you know more than the market; no one does. And don’t act on insights that you think are your own but are usually shared by millions of others.</p>



<p><strong>On steadfastness:</strong></p>



<p><strong>Franklin</strong>: Industry, Perseverance, and Frugality make Fortune yield.</p>



<p><strong>Bogle</strong>: No matter what happens, stick to your program. Think long term. Patience and consistency are the most valuable assets for the intelligent investor. “Stay the course.”</p>
</blockquote>



<p>最后摘抄一句：We know that investing entices risk,but we also know that not investing dooms us financial failure.</p>



<p></p>
<p><a href="http://www.knockatdatabase.com/2025/12/24/the-little-book-of-common-sense-investing/">The little book of common sense investing读后感</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2025/12/24/the-little-book-of-common-sense-investing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>如何在Mac mini M4上安装配置并灵活切换Oracle jdk</title>
		<link>http://www.knockatdatabase.com/2025/09/26/how-to-config-and-switch-oracle-jdk-on-mac-mini-m4/</link>
					<comments>http://www.knockatdatabase.com/2025/09/26/how-to-config-and-switch-oracle-jdk-on-mac-mini-m4/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Fri, 26 Sep 2025 09:44:57 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[JDK]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1321</guid>

					<description><![CDATA[<p>一 背景 本文档用于记录如何在Mac mini M4机器上安装配置Oracle官方提供的jdk。由于我的机器上之前已经安装并且配置过多个版本的Oracle jdk，这里手工一步一步安装配置Oracle最新发布的jdk 25版本，用于文档记录。 二 下载Oracle jdk 到Oracle官网下载最新版本的jdk，选择对应操作系统平台的CPU型号，由于我的是Mac mini M4，所以，我下载的是ARM64 Compressed Archive，其下载地址为： https://download.oracle.com/java/25/latest/jdk-25_macos-aarch64_bin.tar.gz 下载之后： 三 安装配置 我这里，把jdk安装配置在/Users/huangwei/Software路径下，便于管理。 命令行执行解压安装： 确认解压安装结果： 看到，在/Users/huangwei/Software 路径下，生成了jdk-25.jdk，该路径下的其它版本的jdk是之前安装配置的。 四 验证jdk安装成功可用 通过绝对路径可以使用最新版本的jdk。 五 配置环境可以灵活切换jdk版本 由于Mac mini M4默认的shell是zsh，我这里创建一个配置文件~/.zsh_rc，用于配置Oracle jdk不同版本灵活切换，配置之后的文件如下： 如何灵活切换jdk版本：</p>
<p><a href="http://www.knockatdatabase.com/2025/09/26/how-to-config-and-switch-oracle-jdk-on-mac-mini-m4/">如何在Mac mini M4上安装配置并灵活切换Oracle jdk</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">一 背景</h3>



<p>本文档用于记录如何在Mac mini M4机器上安装配置Oracle官方提供的jdk。由于我的机器上之前已经安装并且配置过多个版本的Oracle jdk，这里手工一步一步安装配置Oracle最新发布的jdk 25版本，用于文档记录。</p>



<h3 class="wp-block-heading">二 下载Oracle jdk</h3>



<p>到<a href="https://www.oracle.com/java/technologies/downloads/#jdk25-mac">Oracle官网</a>下载最新版本的jdk，选择对应操作系统平台的CPU型号，由于我的是Mac mini M4，所以，我下载的是ARM64 Compressed Archive，其下载地址为：</p>



<p><a href="https://download.oracle.com/java/25/latest/jdk-25_macos-aarch64_bin.tar.gz">https://download.oracle.com/java/25/latest/jdk-25_macos-aarch64_bin.tar.gz</a></p>



<p>下载之后：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">huangwei@huangweis-Mac-mini Downloads % ls -lrt jdk-25_macos-aarch64_bin.tar.gz 
-rw-r--r--@ 1 huangwei  staff  207923647 Sep 26 12:58 jdk-25_macos-aarch64_bin.tar.gz
huangwei@huangweis-Mac-mini Downloads % pwd
/Users/huangwei/Downloads
huangwei@huangweis-Mac-mini Downloads % ls -lrt jdk-25_macos-aarch64_bin.tar.gz
-rw-r--r--@ 1 huangwei  staff  207923647 Sep 26 12:58 jdk-25_macos-aarch64_bin.tar.gz
huangwei@huangweis-Mac-mini Downloads % </pre></div>



<h3 class="wp-block-heading">三 安装配置</h3>



<p>我这里，把jdk安装配置在/Users/huangwei/Software路径下，便于管理。</p>



<p>命令行执行解压安装：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">huangwei@huangweis-Mac-mini Downloads % tar -xzvf jdk-25_macos-aarch64_bin.tar.gz -C /Users/huangwei/Software 
x ./
x ./jdk-25.jdk/
x ./jdk-25.jdk/Contents/
x ./jdk-25.jdk/Contents/CodeResources
x ./jdk-25.jdk/Contents/_CodeSignature/
x ./jdk-25.jdk/Contents/Home/
x ./jdk-25.jdk/Contents/MacOS/
...
x ./jdk-25.jdk/Contents/Home/man/man1/jarsigner.1
x ./jdk-25.jdk/Contents/_CodeSignature/CodeResources
huangwei@huangweis-Mac-mini Downloads % </pre></div>



<p>确认解压安装结果：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">huangwei@huangweis-Mac-mini Downloads % ll /Users/huangwei/Software 
total 16
drwxr-xr-x   9 huangwei  staff   288 Sep 26 17:25 .
drwxr-x---+ 59 huangwei  staff  1888 Sep 26 12:45 ..
-rw-r--r--@  1 huangwei  staff  6148 Sep 25 17:30 .DS_Store
drwxr-xr-x@  9 huangwei  staff   288 Aug 14  2024 apache-maven-3.9.9
drwxr-xr-x@  3 huangwei  staff    96 Dec  3  2024 jdk-17.0.14.jdk
drwxr-xr-x@  3 huangwei  staff    96 Nov 29  2024 jdk-23.0.2.jdk
drwxr-xr-x   3 huangwei  staff    96 Aug 15 07:07 jdk-25.jdk
drwxr-xr-x@  4 huangwei  staff   128 Feb 10  2025 jdk1.8.0_441.jdk
drwxrwxr-x@ 28 huangwei  staff   896 Aug 29 10:41 nvm-0.40.3
huangwei@huangweis-Mac-mini Downloads % </pre></div>



<p>看到，在/Users/huangwei/Software 路径下，生成了jdk-25.jdk，该路径下的其它版本的jdk是之前安装配置的。</p>



<h3 class="wp-block-heading">四 验证jdk安装成功可用</h3>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">huangwei@huangweis-Mac-mini Downloads % /Users/huangwei/Software/jdk-25.jdk/Contents/Home/bin/java -version
java version &quot;25&quot; 2025-09-16 LTS
Java(TM) SE Runtime Environment (build 25+37-LTS-3491)
Java HotSpot(TM) 64-Bit Server VM (build 25+37-LTS-3491, mixed mode, sharing)
huangwei@huangweis-Mac-mini Downloads % </pre></div>



<p>通过绝对路径可以使用最新版本的jdk。</p>



<h3 class="wp-block-heading">五 配置环境可以灵活切换jdk版本</h3>



<p>由于Mac mini M4默认的shell是zsh，我这里创建一个配置文件~/.zsh_rc，用于配置Oracle jdk不同版本灵活切换，配置之后的文件如下：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">huangwei@huangweis-Mac-mini Downloads % cat ~/.zsh_rc
export JAVA_8_HOME=/Users/huangwei/Software/jdk1.8.0_441.jdk/Contents/Home
export JAVA_17_HOME=/Users/huangwei/Software/jdk-17.0.14.jdk/Contents/Home
export JAVA_23_HOME=/Users/huangwei/Software/jdk-23.0.2.jdk/Contents/Home
export JAVA_25_HOME=/Users/huangwei/Software/jdk-25.jdk/Contents/Home
export M2_HOME=/Users/huangwei/Software/apache-maven-3.9.9
​
#修改jdk版本为17的命令：source ~/.zsh_rc; jdk17;
​
# 默认 JDK 版本
export JAVA_HOME=$JAVA_8_HOME
export PATH=$JAVA_HOME/bin:$M2_HOME/bin:$PATH
​
# 切换 JDK 版本的函数
jdk8() {
    export JAVA_HOME=$JAVA_8_HOME
    export PATH=$JAVA_HOME/bin:$PATH
    echo &quot;Switched to JDK 8&quot;
}
​
jdk17() {
    export JAVA_HOME=$JAVA_17_HOME
    export PATH=$JAVA_HOME/bin:$PATH
    echo &quot;Switched to JDK 17&quot;
}
jdk23() {
    export JAVA_HOME=$JAVA_23_HOME
    export PATH=$JAVA_HOME/bin:$PATH
    echo &quot;Switched to JDK 23&quot;
}
​
jdk25() {
    export JAVA_HOME=$JAVA_25_HOME
    export PATH=$JAVA_HOME/bin:$PATH
    echo &quot;Switched to JDK 25&quot;
}
​
#2025.02.27
alias ll='ls -al'
​
​
#source ~/.bash_profile
huangwei@huangweis-Mac-mini Downloads % </pre></div>



<p>如何灵活切换jdk版本：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">huangwei@huangweis-Mac-mini Downloads % source ~/.zsh_rc 
huangwei@huangweis-Mac-mini Downloads % java -version
java version &quot;1.8.0_441&quot;
Java(TM) SE Runtime Environment (build 1.8.0_441-b07)
Java HotSpot(TM) 64-Bit Server VM (build 25.441-b07, mixed mode)
huangwei@huangweis-Mac-mini Downloads % which java
/Users/huangwei/Software/jdk1.8.0_441.jdk/Contents/Home/bin/java
huangwei@huangweis-Mac-mini Downloads % jdk17
Switched to JDK 17
huangwei@huangweis-Mac-mini Downloads % java -version
java version &quot;17.0.14&quot; 2025-01-21 LTS
Java(TM) SE Runtime Environment (build 17.0.14+8-LTS-191)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.14+8-LTS-191, mixed mode, sharing)
huangwei@huangweis-Mac-mini Downloads % jdk23
Switched to JDK 23
huangwei@huangweis-Mac-mini Downloads % java -version
java version &quot;23.0.2&quot; 2025-01-21
Java(TM) SE Runtime Environment (build 23.0.2+7-58)
Java HotSpot(TM) 64-Bit Server VM (build 23.0.2+7-58, mixed mode, sharing)
huangwei@huangweis-Mac-mini Downloads % jdk25
Switched to JDK 25
huangwei@huangweis-Mac-mini Downloads % java -version
java version &quot;25&quot; 2025-09-16 LTS
Java(TM) SE Runtime Environment (build 25+37-LTS-3491)
Java HotSpot(TM) 64-Bit Server VM (build 25+37-LTS-3491, mixed mode, sharing)
huangwei@huangweis-Mac-mini Downloads % which java
/Users/huangwei/Software/jdk-25.jdk/Contents/Home/bin/java
huangwei@huangweis-Mac-mini Downloads % </pre></div>



<p></p>
<p><a href="http://www.knockatdatabase.com/2025/09/26/how-to-config-and-switch-oracle-jdk-on-mac-mini-m4/">如何在Mac mini M4上安装配置并灵活切换Oracle jdk</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2025/09/26/how-to-config-and-switch-oracle-jdk-on-mac-mini-m4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>流量耗费1TB云成本千元的一则性能优化案例</title>
		<link>http://www.knockatdatabase.com/2025/08/29/how-to-optimize-js-by-example/</link>
					<comments>http://www.knockatdatabase.com/2025/08/29/how-to-optimize-js-by-example/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Fri, 29 Aug 2025 10:19:41 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[NGINX]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1311</guid>

					<description><![CDATA[<p>一 项目背景 近期查看华为云账单消费时，发现有些异常的带宽流浪费用： 从费用上看，发现是上行流量，觉得奇怪。补充项目信息，应用部署在华为云，数据流向图：Client&#8211;&#62;DNS&#8211;&#62;华为云WAF&#8211;&#62;华为云ELB&#8211;&#62;转发至后端ECS&#8211;&#62;返回给ELB&#8211;&#62;返回给WAF&#8211;&#62;Client。 二分析思路和原因 1 通过资源ID定位到流量消耗在ELB 登录华为云控制台，进入EIP弹性公网管理界面，通过带宽ID：8f248608-90a2-4175-b07e-70006da2b93b定位到对应的ELB。 2 通过ELB查看后端服务器组 进入ELB界面，查看后端服务器组，定位到后端服务器有5台，分别是几个不同的项目。 3 控制台查看机器流量 逐一对每台机器流量进行排查，的确发现有一台ECS机器流量异常。 4 查看NGINX日志 通过goaccess工具分析应用系统的NGINX请求日志，发现有对一个js文件的流量请求达到惊人的1.1TB。 5 统计NGINX访问最多的前10个URL地址 进一步分析，查看NGINX请求，发现访问比较多的URL资源： 6 查看这个js文件究竟是啥 Chrome浏览器，控制台，查看js，发现压缩之后1.8Mb，原始文件更是有7Mb多。加载耗时2.66秒。 7 寻求开发同事介入支持 寻求开发同事支持，查看该js文件里有大量的json文件，查看源代码，原来是全国各市区县的地图json文件，一共有300多个，平均每个文件几十个kb，全部打包到该js文件里了，不大才怪呢。经过分析，访问该站点时，只需要加载该项目所在市区的地图就行，根本不需要把全国各市区县的地图json文件全部打包到该js文件里。 三 解决问题 1 优化代码 优化之后，上测试环境，测试同事验证没问题，发布到生产环境。 可以看到，生产环境该js文件压缩之后，原文件大小从7777kb降低到只有115kb，&#8221;瘦身&#8221;了7777/115=67倍多。压缩之后，也从1804kb降低到只有43kb，“瘦身”了1804/43=41.953 倍。 四 复盘总结 一个小小的js文件，造成流量请求1.1TB，成本千元。 系统性能优化都在细节里，代码里装的都是细节。 感谢身边几位同事的协助分析支持。周末愉快。今天2025年8月29日，农历七月初七，牛郎织女将在今晚跨越那条银河。想起儿时暑假的夜空，长辈们讲述这个美好爱情故事的场景&#8230;&#8230;</p>
<p><a href="http://www.knockatdatabase.com/2025/08/29/how-to-optimize-js-by-example/">流量耗费1TB云成本千元的一则性能优化案例</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">一 项目背景</h3>



<p>近期查看华为云账单消费时，发现有些异常的带宽流浪费用：</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="276" src="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165-1024x276.png" alt="" class="wp-image-1314" srcset="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165-1024x276.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165-300x81.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165-768x207.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165-1536x415.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165-1140x308.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829170852165.png 1649w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>从费用上看，发现是上行流量，觉得奇怪。补充项目信息，应用部署在华为云，数据流向图：Client&#8211;&gt;DNS&#8211;&gt;华为云WAF&#8211;&gt;华为云ELB&#8211;&gt;转发至后端ECS&#8211;&gt;返回给ELB&#8211;&gt;返回给WAF&#8211;&gt;Client。</p>



<h3 class="wp-block-heading">二分析思路和原因</h3>



<h4 class="wp-block-heading">1 通过资源ID定位到流量消耗在ELB</h4>



<p>登录华为云控制台，进入EIP弹性公网管理界面，通过带宽ID：8f248608-90a2-4175-b07e-70006da2b93b定位到对应的ELB。</p>



<h4 class="wp-block-heading">2 通过ELB查看后端服务器组</h4>



<p>进入ELB界面，查看后端服务器组，定位到后端服务器有5台，分别是几个不同的项目。</p>



<h4 class="wp-block-heading">3 控制台查看机器流量</h4>



<p>逐一对每台机器流量进行排查，的确发现有一台ECS机器流量异常。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="432" src="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1-1024x432.png" alt="" class="wp-image-1315" srcset="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1-1024x432.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1-300x127.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1-768x324.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1-1536x648.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1-1140x481.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174558789-1.png 1807w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">4 查看NGINX日志</h4>



<p>通过goaccess工具分析应用系统的NGINX请求日志，发现有对一个js文件的流量请求达到惊人的1.1TB。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="899" height="420" src="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174746586.png" alt="" class="wp-image-1316" srcset="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174746586.png 899w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174746586-300x140.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829174746586-768x359.png 768w" sizes="auto, (max-width: 899px) 100vw, 899px" /></figure>



<h4 class="wp-block-heading">5 统计NGINX访问最多的前10个URL地址</h4>



<p>进一步分析，查看NGINX请求，发现访问比较多的URL资源：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">awk '{print $7}' qyxyd.log | sort|uniq -c| sort -rn| head -10 | more
root@xmxyd-17xx:/etc/nginx/logs# awk '{print $7}' qyxyd.log | sort|uniq -c| sort -rn| head -10 | more
 674633 /
 672633 /home
 652434 /_nuxt/js/vendors/app.1751528723734.js
 652386 /_nuxt/js/pages/home/index.1751528723734.js
 652230 /_nuxt/js/pages/credit_institution/index/pages/financial_institution/index/pages/financial_shop/index/pages/ho/245b0134.1751528723734.js
 652225 /_nuxt/js/app.1751528723734.js
 652124 /_nuxt/img/left_arrow.0c6667f.png
 652083 /_nuxt/img/newYear1.fc48a87.jpeg
 652054 /_nuxt/js/runtime.1751528723734.js
 652029 /_nuxt/img/bar-sort.0c296c8.png
root@xmxyd-17xx:/etc/nginx/logs# </pre></div>



<h4 class="wp-block-heading">6 查看这个js文件究竟是啥</h4>



<p>Chrome浏览器，控制台，查看js，发现压缩之后1.8Mb，原始文件更是有7Mb多。加载耗时2.66秒。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="587" src="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175303784-1024x587.png" alt="" class="wp-image-1317" srcset="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175303784-1024x587.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175303784-300x172.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175303784-768x440.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175303784-1140x654.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175303784.png 1240w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">7 寻求开发同事介入支持</h4>



<p>寻求开发同事支持，查看该js文件里有大量的json文件，查看源代码，原来是全国各市区县的地图json文件，一共有300多个，平均每个文件几十个kb，全部打包到该js文件里了，不大才怪呢。经过分析，访问该站点时，只需要加载该项目所在市区的地图就行，根本不需要把全国各市区县的地图json文件全部打包到该js文件里。</p>



<h3 class="wp-block-heading">三 解决问题</h3>



<h4 class="wp-block-heading">1 优化代码</h4>



<p>优化之后，上测试环境，测试同事验证没问题，发布到生产环境。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="653" src="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175908306-1024x653.png" alt="" class="wp-image-1318" srcset="http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175908306-1024x653.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175908306-300x191.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175908306-768x490.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175908306-1140x727.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2025/08/image-20250829175908306.png 1241w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>可以看到，生产环境该js文件压缩之后，原文件大小从7777kb降低到只有115kb，&#8221;瘦身&#8221;了7777/115=67倍多。压缩之后，也从1804kb降低到只有43kb，“瘦身”了1804/43=41.953 倍。</p>



<h3 class="wp-block-heading">四 复盘总结</h3>



<p>一个小小的js文件，造成流量请求1.1TB，成本千元。</p>



<p>系统性能优化都在细节里，代码里装的都是细节。</p>



<p>感谢身边几位同事的协助分析支持。周末愉快。今天2025年8月29日，农历七月初七，牛郎织女将在今晚跨越那条银河。想起儿时暑假的夜空，长辈们讲述这个美好爱情故事的场景&#8230;&#8230;</p>



<p></p>
<p><a href="http://www.knockatdatabase.com/2025/08/29/how-to-optimize-js-by-example/">流量耗费1TB云成本千元的一则性能优化案例</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2025/08/29/how-to-optimize-js-by-example/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>如何实现MySQL实时同步到PostgreSQL数据库</title>
		<link>http://www.knockatdatabase.com/2024/10/14/how-to-sync-mysql-to-postgesql/</link>
					<comments>http://www.knockatdatabase.com/2024/10/14/how-to-sync-mysql-to-postgesql/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Mon, 14 Oct 2024 09:01:38 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1300</guid>

					<description><![CDATA[<p>0 项目背景说明 公司有一项目，采用MySQL 5.7.39作为业务数据库。项目主管部门有一套数据汇总系统，要求我们把部分业务表数据实时推送到汇总系统。他们提供一套前置的瀚高PostgreSQL数据库出来，让我们把MySQL中的对应业务表推送到该数据库中。同时，要求我们把数据推送到目标PostgreSQL数据库之后，如果源端的MySQL数据库有插入操作，则需要在目标PostgreSQL数据库表中通过添加4个字段记录下来：I_ID 自增，I_STATE = 1，I_FLAG = I，I_TIME 表示记录插入时间。 经过分析调研测试验证，在网上找到有网友在Kubernetes里通过Debezium and KafkaConnect来说实现过，这个场景对我们来说不太贴合，大概了解一下原理，就略过了。链接：Sync MySQL to PostgreSQL Using Debezium and KafkaConnect 同时，看到有网友通过轻量级 CDC debezium-server-databend 构建实时数据同步，简单测试了下，该网友实现了把MySQL同步到databend数据库里，没有直接落库到PostgreSQL数据库。有开发同事，对该项目进行了简单的二开，有实现了部分需求。暂时没有足够的时间和精力继续二开，就地搁置。https://zhuanlan.zhihu.com/p/647470177?utm_id=0 网上有Tapdata工具可以实现该场景，但是需要联系厂家申请试用，他们的人有联系我。但是，我隐隐约约感觉到对方可能会收费。https://bbs.huaweicloud.com/blogs/320806 最后，找到一款go-mysql-postgres的开源工具，经过测试验证，以及在目标端的PostgreSQL数据库表上创建触发器，可以初步实现该功能。 核心操作流程：直接在源端的MySQL数据库服务器上执行操作：安装配置go-mysql-postgres工具，用于读取本地的MySQL数据库的binlog，然后把数据写入到目标端的PostgreSQL数据库。 而go-mysql-postgres工具的主要思路是，源端的MySQL数据库开启binlog，且格式要求是row，源端MySQL和目标端PostgreSQL中的表必须都得有主键。通过mysqldump工具把MySQL中要同步的表备份出来，记录下binlog position，用于后面从哪儿开始读取binlog进行同步。把备份的建表语句改成兼容PostgreSQL的SQL，在PostgreSQL中执行建表，并且把数据执行插入到PostgreSQL数据库里。准备就绪之后，开启go-mysql-postgres程序来从记录下的binlog position位置处开始执行同步。 本文档用于记录如何采用go-mysql-postgres和触发器来实现MySQL数据实时同步到PostgreSQL，并且在目标库表上增加4个标记位字段的操作步骤和详细流程。 1 安装PostgreSQL 15.0 在源端MySQL数据库服务器上执行安装，目的是通过该PostgreSQL安装的psql客户端工具可以连接到目标端的PostgreSQL数据库。 2 下载安装go-mysql-postgres 同样在源端MySQL数据库服务器上执行安装，将来直接在数据库服务器上启动该程序，读取MySQL的binlog，并把数据推送到目标端的PostgreSQL数据库中去。 3 下载mysql2pgsql工具脚本 该工具脚本的主要作用是可以把mysqldump导出的含有建表语句的SQL和插入SQL转换成兼容PostgreSQL的SQL。其中，会自动把MySQL的自增主键id转换为PostgreSQL的serial序列自增类型字段。缺点是，在建表语句里没有把MySQL建表语句中的USING BTREE关键字去掉，这个需要手工处理一下。 https://github.com/ahammond/mysql2pgsql/blob/master/mysql2pgsql.pl 4 导出MySQL表结构和表数据 5 转换为PostgreSQL的表结构和数据 6 导入PostgreSQL数据库： 7 修改go-mysql-postgres配置文件 该文件放在/root/go-mysql-postgres路径下，名为river.toml，可以参考/root/go-mysql-postgres/etc/river.toml实例文件进行配置。核心配置内容如下： 新建/root/go-mysql-postgres/var/master.info文件，该路径和文件默认不存在，需要手工创建出来，其内容如下：bin_name执行MyS...</p>
<p><a href="http://www.knockatdatabase.com/2024/10/14/how-to-sync-mysql-to-postgesql/">如何实现MySQL实时同步到PostgreSQL数据库</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<p></p>



<h4 class="wp-block-heading">0 项目背景说明</h4>



<p>公司有一项目，采用MySQL 5.7.39作为业务数据库。项目主管部门有一套数据汇总系统，要求我们把部分业务表数据实时推送到汇总系统。他们提供一套前置的瀚高PostgreSQL数据库出来，让我们把MySQL中的对应业务表推送到该数据库中。同时，要求我们把数据推送到目标PostgreSQL数据库之后，如果源端的MySQL数据库有插入操作，则需要在目标PostgreSQL数据库表中通过添加4个字段记录下来：I_ID 自增，I_STATE = 1，I_FLAG = I，I_TIME 表示记录插入时间。</p>



<p>经过分析调研测试验证，在网上找到有网友在Kubernetes里通过Debezium and KafkaConnect来说实现过，这个场景对我们来说不太贴合，大概了解一下原理，就略过了。链接：<a href="https://medium.com/swlh/sync-mysql-to-postgresql-using-debezium-and-kafkaconnect-d6612489fd64">Sync MySQL to PostgreSQL Using Debezium and KafkaConnect</a></p>



<p>同时，看到有网友通过轻量级 CDC debezium-server-databend 构建实时数据同步，简单测试了下，该网友实现了把MySQL同步到databend数据库里，没有直接落库到PostgreSQL数据库。有开发同事，对该项目进行了简单的二开，有实现了部分需求。暂时没有足够的时间和精力继续二开，就地搁置。<a href="https://zhuanlan.zhihu.com/p/647470177?utm_id=0">https://zhuanlan.zhihu.com/p/647470177?utm_id=0</a></p>



<p>网上有Tapdata工具可以实现该场景，但是需要联系厂家申请试用，他们的人有联系我。但是，我隐隐约约感觉到对方可能会收费。<a href="https://bbs.huaweicloud.com/blogs/320806">https://bbs.huaweicloud.com/blogs/320806</a></p>



<p>最后，找到一款go-mysql-postgres的开源工具，经过测试验证，以及在目标端的PostgreSQL数据库表上创建触发器，可以初步实现该功能。</p>



<p>核心操作流程：直接在源端的MySQL数据库服务器上执行操作：安装配置go-mysql-postgres工具，用于读取本地的MySQL数据库的binlog，然后把数据写入到目标端的PostgreSQL数据库。</p>



<p>而go-mysql-postgres工具的主要思路是，源端的MySQL数据库开启binlog，且格式要求是row，源端MySQL和目标端PostgreSQL中的表必须都得有主键。通过mysqldump工具把MySQL中要同步的表备份出来，记录下binlog position，用于后面从哪儿开始读取binlog进行同步。把备份的建表语句改成兼容PostgreSQL的SQL，在PostgreSQL中执行建表，并且把数据执行插入到PostgreSQL数据库里。准备就绪之后，开启go-mysql-postgres程序来从记录下的binlog position位置处开始执行同步。</p>



<p>本文档用于记录如何采用go-mysql-postgres和触发器来实现MySQL数据实时同步到PostgreSQL，并且在目标库表上增加4个标记位字段的操作步骤和详细流程。</p>



<h4 class="wp-block-heading">1 安装PostgreSQL 15.0</h4>



<p>在源端MySQL数据库服务器上执行安装，目的是通过该PostgreSQL安装的psql客户端工具可以连接到目标端的PostgreSQL数据库。</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">groupadd -g 1688 postgres
useradd -g postgres -u 1688 postgres
echo 'D1ng0D1888!'|passwd --stdin docker
mkdir -p /data/postgres/15.0/
chown -R postgres:postgres /data/postgres/
cp postgresql-15.0.tar.gz  /home/postgres/
​
##解压，编译安装
su - postgres
tar -zxvf postgresql-15.0.tar.gz
​
cd postgresql-15.0/
​
./configure --prefix=/data/postgres/15.0
​
gmake world &amp;&amp; gmake install-world
​
​
###修改~/.bashrc
[postgres@dbserver ~]$ cat .bashrc 
# Source default setting
[ -f /etc/bashrc ] &amp;&amp; . /etc/bashrc
​
# User environment PATH
PATH=&quot;$HOME/.local/bin:$HOME/bin:$PATH:/data/postgres/15.0/bin/&quot;
export PATH
​
export PGPASSWORD=123456Aa*
[postgres@dbserver ~]$     
​
##使之生效
source ~/.bashrc
​
#连接目标端瀚高数据库，这里隐去对应的数据库IP，端口，账户名和密码等信息
[postgres@dbserver ~]$ psql -h pg_ip -p port -U user_name -d db_name
NOTICE:  
-------------------------------------------
Login User: user_name 
Login time: 2024-10-14 16:01:21.042908+08 
Login Address: pg_ip 
Last Login Status: SUCCESS 
Login Failures: 0 
Valied Until: infinity 
-------------------------------------------
​
psql (15.0, server 12.7)
Type &quot;help&quot; for help.
​
db_name=&gt; </pre></div>



<h4 class="wp-block-heading">2 下载安装go-mysql-postgres</h4>



<p>同样在源端MySQL数据库服务器上执行安装，将来直接在数据库服务器上启动该程序，读取MySQL的binlog，并把数据推送到目标端的PostgreSQL数据库中去。</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">#下载安装golang,因为go-mysql-postges是用golang写的，所以需要先安装配置golang环境，才可以编译go-mysql-postgres程序
wget https://dl.google.com/go/go1.21.3.linux-amd64.tar.gz
# 解压到/usr/local路径下
tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz
​
vi /etc/profile
#添加下述配置项
​
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=$HOME/Documents/go
​
#读取golang配置，使之生效
source /etc/profile
​
​
#下载编译go-mysql-postgres
git clone https://gitee.com/tangjunhu/go-mysql-postgres.git
cd go-mysql-postgres/
make
[root@dbserver ~]# go version
go version go1.21.3 linux/amd64
[root@dbserver ~]# cd go-mysql-postgres/
[root@dbserver go-mysql-postgres]# ll
total 60
-rw-r--r-- 1 root root  199 Oct 11 10:45 build.sh
-rw-r--r-- 1 root root  425 Oct 11 10:45 clear_vendor.sh
drwxr-xr-x 3 root root 4096 Oct 11 10:45 cmd
-rw-r--r-- 1 root root  455 Oct 11 10:45 Dockerfile
drwxr-xr-x 2 root root 4096 Oct 11 10:45 elastic
drwxr-xr-x 2 root root 4096 Oct 11 10:45 etc
-rw-r--r-- 1 root root 1046 Oct 11 10:45 go.mod
-rw-r--r-- 1 root root 5088 Oct 11 10:45 go.sum
-rw-r--r-- 1 root root 1076 Oct 11 10:45 LICENSE
-rw-r--r-- 1 root root  255 Oct 11 10:45 Makefile
-rw-r--r-- 1 root root 3399 Oct 11 10:45 README.md
drwxr-xr-x 2 root root 4096 Oct 11 10:45 river
drwxr-xr-x 2 root root 4096 Oct 11 10:45 util
drwxr-xr-x 3 root root 4096 Oct 11 10:45 vendor
[root@dbserver go-mysql-postgres]# make
GO111MODULE=on go build -o bin/go-mysql-postgresql-mw ./cmd/go-mysql-elasticsearch
cat build.sh &gt;build 
chmod a+x build
[root@dbserver go-mysql-postgres]#</pre></div>



<h4 class="wp-block-heading">3 下载mysql2pgsql工具脚本</h4>



<p>该工具脚本的主要作用是可以把mysqldump导出的含有建表语句的SQL和插入SQL转换成兼容PostgreSQL的SQL。其中，会自动把MySQL的自增主键id转换为PostgreSQL的serial序列自增类型字段。缺点是，在建表语句里没有把MySQL建表语句中的USING BTREE关键字去掉，这个需要手工处理一下。</p>



<p><a href="https://github.com/ahammond/mysql2pgsql/blob/master/mysql2pgsql.pl">https://github.com/ahammond/mysql2pgsql/blob/master/mysql2pgsql.pl</a></p>



<h4 class="wp-block-heading">4 导出MySQL表结构和表数据</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">mkdir -p /tmp/mysql2pg/
cd /tmp/mysql2pg/
​
mysqldump -h 127.0.0.1 -P端口 -uroot -proot密码 数据库名  --master-data=2  t_policies &gt; t_policies.mysql</pre></div>



<h4 class="wp-block-heading">5 转换为PostgreSQL的表结构和数据</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">cd /tmp/mysql2pg/
/root/mysql2pgsql.pl t_policies.mysql t_policies.pg
​
#去掉建表语句中的USING BTREE
sed -i 's/USING BTREE/ /' /tmp/mysql2pg/t_policies.pg</pre></div>



<h4 class="wp-block-heading">6 导入PostgreSQL数据库：</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;sql&quot;,&quot;mime&quot;:&quot;text/x-sql&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;SQL&quot;,&quot;modeName&quot;:&quot;sql&quot;}">su - postgres
psql -h -xxxx #连接到目标PostgreSQL数据库，执行SQL建表语句和插入数据 
yth_ta_qlk=&gt; \i /tmp/mysql2pg/t_policies.pg 
psql:/tmp/mysql2pg/t_policies.pg:40: ERROR:  table &quot;t_policies&quot; does not exist
CREATE TABLE
INSERT 0 53
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
COMMENT
yth_ta_qlk=&gt;</pre></div>



<h4 class="wp-block-heading">7 修改go-mysql-postgres配置文件</h4>



<p>该文件放在/root/go-mysql-postgres路径下，名为river.toml，可以参考/root/go-mysql-postgres/etc/river.toml实例文件进行配置。核心配置内容如下：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;toml&quot;,&quot;mime&quot;:&quot;text/x-toml&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;TOML&quot;,&quot;modeName&quot;:&quot;toml&quot;}"># MySQL data source
[[source]]
schema = &quot;mysql_db_name&quot;    #MySQL源库数据库名
tables = [&quot;t_news&quot;,&quot;t_policies&quot;] #待同步的MySQL表名，如果有多个表的话，以逗号分隔，列出多个要同步的表名即可
​
# 目标PG的连接配置
[[target]]
pg_name = &quot;159.xxx_yth_ta_qlk&quot;      #指定一个目标PostgreSQL数据库的连接标识符
pg_host = &quot;pg_ip&quot;            #目标PostgreSQL数据库的IP
pg_port = pg_port                    #目标PostgreSQL数据库的端口
pg_user = &quot;pg_useranme&quot;  #目标PostgreSQL数据库的用户名
pg_pass = &quot;pg_password&quot;               #目标PostgreSQL数据库的密码
pg_dbname = &quot;pg_dbname&quot;            #目标PostgreSQL数据库的数据库名
​
# MySQL 数据到 PG 后的分发规则
[[rule]]
#mysql 库表的配置
schema = &quot;mysql_db_name&quot;               #源端MySQL数据库名，
table = &quot;t_news&quot;                   #源端待同步的表名
# pg 库表的配置
pg_schema = &quot;tas_fgw_zxqyrzzhxyfwpt&quot;  #目标端pg schema
pg_table = &quot;t_news&quot;                   #目标端表名
​
[[rule]]
#mysql 库表的配置
schema = &quot;mysql_db_name&quot;              #源端MySQL数据库名，
table = &quot;t_policies&quot;              #源端MySQL数据库名，
# pg 库表的配置
pg_schema = &quot;tas_fgw_zxqyrzzhxyfwpt&quot;  #目标端pg schema
pg_table = &quot;t_policies&quot;               #目标端表名</pre></div>



<p>新建/root/go-mysql-postgres/var/master.info文件，该路径和文件默认不存在，需要手工创建出来，其内容如下：bin_name执行MySQL数据库当前的binary log日志文件名，bin_pos指向当前的binary log position位置处。</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@dbserver go-mysql-postgres]# cat var/master.info 
bin_name = &quot;binlog.000001&quot;
bin_pos = 17466296
[root@dbserver go-mysql-postgres]#</pre></div>



<p>可以通过在MySQL命令行里执行show master status或者show binary logs来获取：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;sql&quot;,&quot;mime&quot;:&quot;text/x-sql&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;SQL&quot;,&quot;modeName&quot;:&quot;sql&quot;}">mysql&gt; show master status;
+---------------+----------+--------------+------------------+-------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000001 | 17466296 |              |                  |                   |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
​
mysql&gt; show binary logs;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000001 |  17466296 |
+---------------+-----------+
1 row in set (0.00 sec)
​
mysql&gt;   </pre></div>



<p>这里的bin_pos至少要从第一次dump MySQL表时的位置处开始，在第4步骤的导出命令里加了&#8211;master-data=2选项，可以从导出文件中获取该信息。一旦同步开启之后，go-mysql-postgres会自动更新该文件信息。</p>



<h4 class="wp-block-heading">8 启动go-mysql-postgres</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">cd /root/go-mysql-postgres
​
nohup ./bin/go-mysql-postgresql-mw  -config=river.toml &gt; /root/go-mysql-postgres/reps.log 2 &gt;&amp;1 &amp;
​
tail -f reps.log
[root@dbserver go-mysql-postgres]# tail -f reps.log
[2024/10/14 16:54:53] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:54:54] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:54:55] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:54:56] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:54:57] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:54:58] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:54:59] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:55:00] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:55:01] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:55:02] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:55:03] [info] master.go:110 save position [binlog.000001,17434752]
[2024/10/14 16:55:04] [info] master.go:110 save position [binlog.000001,17434752]
....
​
#查看帮助
[root@dbserver go-mysql-postgres]# ./bin/go-mysql-postgresql-mw -h
Usage of ./bin/go-mysql-postgresql-mw:
  -config string
        go-mysql-postgres config file (default &quot;./etc/river.toml&quot;)
  -data_dir string
        path for go-mysql-elasticsearch to save data
  -es_addr string
        Elasticsearch addr
  -exec string
        mysqldump execution path
  -flavor string
        flavor: mysql or mariadb
  -log_level string
        log level (default &quot;info&quot;)
  -max_procs int
        GOMAXPROCS
  -my_addr string
        MySQL addr
  -my_pass string
        MySQL password
  -my_user string
        MySQL user
  -server_id int
        MySQL server id, as a pseudo slave
[root@dbserver go-mysql-postgres]# </pre></div>



<h4 class="wp-block-heading">9 PostgreSQL表添加字段和触发器</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;sql&quot;,&quot;mime&quot;:&quot;text/x-sql&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;SQL&quot;,&quot;modeName&quot;:&quot;sql&quot;}">alter table t_policies add column i_state varchar(2);
alter table t_policies add column i_flag varchar(2);
alter table t_policies add column i_time timestamp;
alter table t_policies add column i_id serial;
comment on table t_policies is '政策法规信息';
​
--insert
create or replace function t_policies_insert_state_flag_time() returns trigger as
$$
begin
    new.i_state = 1;
    new.i_flag ='I';
    new.i_time = current_timestamp;
    return new;
end
$$
language plpgsql;
​
create trigger t_policies_auto_insert_state_flag_time
  before insert on t_policies 
  for each row execute procedure t_policies_insert_state_flag_time();</pre></div>



<h4 class="wp-block-heading">10 测试验证</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;sql&quot;,&quot;mime&quot;:&quot;text/x-sql&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;SQL&quot;,&quot;modeName&quot;:&quot;sql&quot;}">--MySQL插入数据
insert into t_policies(id,title,sort) values(9999,'测试',9999);
​
--pg查看数据
select id,title,sort,i_id,i_state,i_flag,i_time from t_policies;
​
--看到插入数据
 9999 | 测试                                                                                                                                                                             | 9999 |   54 | 1       | I      | 2024-10-12 11:25:23.947781
 
--MySQL删除测试数据
delete from t_policies where id=9999;</pre></div>



<h4 class="wp-block-heading">11 参考链接：</h4>



<p><a href="https://blog.csdn.net/Maslii/article/details/104762949">https://blog.csdn.net/Maslii/article/details/104762949</a></p>



<p><a href="https://blog.csdn.net/qq_26373925/article/details/110506835">https://blog.csdn.net/qq_26373925/article/details/110506835</a></p>



<p><a href="https://gitee.com/tangjunhu/go-mysql-postgres">https://gitee.com/tangjunhu/go-mysql-postgres</a></p>



<p><a href="https://github.com/ahammond/mysql2pgsql/blob/master/mysql2pgsql.pl">https://github.com/ahammond/mysql2pgsql/blob/master/mysql2pgsql.pl</a></p>



<p><a href="https://cloud.tencent.com/developer/article/1506974">https://cloud.tencent.com/developer/article/1506974</a></p>



<p><a href="https://cloud.tencent.com/developer/article/1506977?from_column=20421&amp;from=20421">https://cloud.tencent.com/developer/article/1506977?from_column=20421&amp;from=20421</a></p>



<p><a href="https://timothyzhang.medium.com/real-time-cdc-replications-between-mysql-and-postgresql-using-debezium-connectors-24aa33d58f1e">https://timothyzhang.medium.com/real-time-cdc-replications-between-mysql-and-postgresql-using-debezium-connectors-24aa33d58f1e</a></p>
<p><a href="http://www.knockatdatabase.com/2024/10/14/how-to-sync-mysql-to-postgesql/">如何实现MySQL实时同步到PostgreSQL数据库</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2024/10/14/how-to-sync-mysql-to-postgesql/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>多个gitlab如何迁移合并配置，以及如何把已有用户体系的gitlab再接入ldap认证</title>
		<link>http://www.knockatdatabase.com/2024/09/11/how-to-merge-gitlab-and-enable-ldap/</link>
					<comments>http://www.knockatdatabase.com/2024/09/11/how-to-merge-gitlab-and-enable-ldap/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Wed, 11 Sep 2024 03:11:53 +0000</pubDate>
				<category><![CDATA[Gitlab]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1282</guid>

					<description><![CDATA[<p>一 背景说明 因为一些莫名其妙的原因，公司内部有2个gitlab实例：10.0.9.25和10.0.9.163，且都有项目代码。其中，IP尾数是163的gitlab接入了ldap认证的用户系统，托管的项目比较少30多个。25这个gitlab上的用户是手工创建的，没有接入ldap，且托管了400多个项目的代码。现在的需求是，把163上的项目全部迁移至25服务器上，且25服务器上接入ldap认证。接入ldap的好处就是，在ldap上统一维护一套用户体系，其它系统接入ldap之后，就不再需要另外维护用户了。且，公司内部其它子应用诸如wiki，jira，Jenkins，grafana等，都可以接入ldap。对于，团队里人员变动，只需要在ldap里设置用户状态，其它系统里用户状态就会自动跟着变。 二 如何获取每个gitlab下所有的项目 可以通过gitlab提供的API来实现。首先，以管理员登录web页面，生成可以通过API访问的token，然后通过curl来进行API访问，获取所有项目信息。 1 生成access token http://10.0.9.163/profile/personal_access_tokens 输入用户名，选择token类型为API，然后生成： 2 通过access token经由gitlab api获取所有projects curl命令行工具，带上token，以及gitlab服务器的信息，默认情况下API访问地址应该类似于“http://10.0.9.163/api/v4/projects”。但是，该情形下，只能获取1页，且至多只有20个项目的信息。如果项目超过20个，则需要分页，所以带有per_page和page参数来获取多页，以便可以获取所有项目信息。 如下，由于25gitlab服务器上有400多个项目，所以，在通过API访问服务器，获取项目时，使用了分页的方式：通过per_page和page选项，来获取所有projects。默认情况下，每页只展示20个项目。 3 JSON文件转为Excel 通过JSON转Excel在线工具，将163.json文件转成Excel。https://uutool.cn/json2excel/ 4 参考地址： https://archives.docs.gitlab.com/15.10/ee/api/rest https://worktile.com/kb/ask/259761.html http://kw.dataea.cn/2017/06/20/gitlab-api/ 三 如何将项目从一个gitlab迁移合并到另一个gitlab 这里，把163上所有的项目，迁移合并到25服务器上。步骤比较简单，现在163上把项目export出来，然后在25服务器上执行import即可。 1 导出项目 以管理员身份登录10.0.9.163机器的Gitlab:http://10.0.9.163/admin 选择项目，点击edit： 点击Advanced选项： 在Export project下，选择导出项目，我这里已经导出过，所以，可以看到Download export选项。 选择导出项目之后，页面上会有个提示：Project export started. A download link will be sent by email. 如果有在gitlab里配置邮箱的话，可以收到邮件提醒。没有配置的话，需要重新刷新页面，然后点击Advanced，可以看到上面说的download export选项，进行下载。 2 导入项目 以管理员身份登录10.0.9.25 gitlab的web界面，https://10.0.9.25:89/admin 依次选择新建项目，导入项目， 填入对应的项目名称，选择对应的namespace，选择导出的项目gz压缩包文件，点击导入项目即可。 3 注意事项 目标gitlab上导入时，项目名称保持和源gitlab一致，namespace也和源gitlab的namespace一致。 四 现有的gitlab已经有用户，如何启用ldap 10.0.9.25 gitlab已经有用户，如何接入ldap呢？ 1 修改gitlab配置文件 在/etc/gitlab/gitlab.rb配置文件中，添加下述配置信息： 2 执行gitlab-ctl reconfigure使之生效 3 验证gitlab是否可以读取openldap的用户体系 从上，看到gitlab可以顺利读取ldap用户体系。 4 验证gitlab服务和状态 执行gitlab-ctl status和gitlab-ctl service-list命令来验证： 5 通过ldap来访问gitlab 6 报错处理 Could not a...</p>
<p><a href="http://www.knockatdatabase.com/2024/09/11/how-to-merge-gitlab-and-enable-ldap/">多个gitlab如何迁移合并配置，以及如何把已有用户体系的gitlab再接入ldap认证</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">一 背景说明</h3>



<p>因为一些莫名其妙的原因，公司内部有2个gitlab实例：10.0.9.25和10.0.9.163，且都有项目代码。其中，IP尾数是163的gitlab接入了ldap认证的用户系统，托管的项目比较少30多个。25这个gitlab上的用户是手工创建的，没有接入ldap，且托管了400多个项目的代码。现在的需求是，把163上的项目全部迁移至25服务器上，且25服务器上接入ldap认证。接入ldap的好处就是，在ldap上统一维护一套用户体系，其它系统接入ldap之后，就不再需要另外维护用户了。且，公司内部其它子应用诸如wiki，jira，Jenkins，grafana等，都可以接入ldap。对于，团队里人员变动，只需要在ldap里设置用户状态，其它系统里用户状态就会自动跟着变。</p>



<h3 class="wp-block-heading">二 如何获取每个gitlab下所有的项目</h3>



<p>可以通过gitlab提供的API来实现。首先，以管理员登录web页面，生成可以通过API访问的token，然后通过curl来进行API访问，获取所有项目信息。</p>



<h4 class="wp-block-heading">1 生成access token</h4>



<p><a href="http://10.0.9.163/profile/personal_access_tokens">http://10.0.9.163/profile/personal_access_tokens</a></p>



<p>输入用户名，选择token类型为API，然后生成：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">ai3LypuDHeQ5c64xdTcQ</pre></div>



<h4 class="wp-block-heading">2 通过access token经由gitlab api获取所有projects</h4>



<p>curl命令行工具，带上token，以及gitlab服务器的信息，默认情况下API访问地址应该类似于“<a href="http://10.0.9.163/api/v4/projects">http://10.0.9.163/api/v4/projects</a>”。但是，该情形下，只能获取1页，且至多只有20个项目的信息。如果项目超过20个，则需要分页，所以带有per_page和page参数来获取多页，以便可以获取所有项目信息。</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@jenkins76 tmp]# curl  --header &quot;PRIVATE-TOKEN:ai3LypuDHeQ5c64xdTcQ&quot;   &quot;http://10.0.9.163/api/v4/projects?per_page=200&amp;page=1&quot; &gt;163.json
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 84653  100 84653    0     0   9605      0  0:00:08  0:00:08 --:--:-- 23469
[root@jenkins76 tmp]# ll
total 1120
-rw-r--r--  1 root root  84653 Sep  4 14:13 163.json</pre></div>



<p>如下，由于25gitlab服务器上有400多个项目，所以，在通过API访问服务器，获取项目时，使用了分页的方式：通过per_page和page选项，来获取所有projects。默认情况下，每页只展示20个项目。</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@jenkins76 tmp]# curl  --header &quot;PRIVATE-TOKEN:4gu4WFfzteX2gsYdWx1k&quot;  -k &quot;https://10.0.9.25:89/api/v4/projects?per_page=200&amp;page=1&quot; &gt;p1.json
...
...

[root@jenkins76 tmp]# curl  --header &quot;PRIVATE-TOKEN:4gu4WFfzteX2gsYdWx1k&quot;  -k &quot;https://10.0.9.25:89/api/v4/projects?per_page=200&amp;page=6&quot; &gt;p6.json</pre></div>



<h4 class="wp-block-heading">3 JSON文件转为Excel</h4>



<p>通过JSON转Excel在线工具，将163.json文件转成Excel。<a href="https://uutool.cn/json2excel/">https://uutool.cn/json2excel/</a></p>



<h4 class="wp-block-heading">4 参考地址：</h4>



<p><a href="https://archives.docs.gitlab.com/15.10/ee/api/rest">https://archives.docs.gitlab.com/15.10/ee/api/rest</a></p>



<p><a href="https://worktile.com/kb/ask/259761.html">https://worktile.com/kb/ask/259761.html</a></p>



<p><a href="http://kw.dataea.cn/2017/06/20/gitlab-api/">http://kw.dataea.cn/2017/06/20/gitlab-api/</a></p>



<h3 class="wp-block-heading">三 如何将项目从一个gitlab迁移合并到另一个gitlab</h3>



<p>这里，把163上所有的项目，迁移合并到25服务器上。步骤比较简单，现在163上把项目export出来，然后在25服务器上执行import即可。</p>



<h4 class="wp-block-heading">1 导出项目</h4>



<p>以管理员身份登录10.0.9.163机器的Gitlab:<a href="http://10.0.9.163/admin">http://10.0.9.163/admin</a></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="541" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620-1024x541.png" alt="" class="wp-image-1287" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620-1024x541.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620-300x159.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620-768x406.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620-1536x812.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620-1140x603.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103356620.png 1909w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>选择项目，点击edit：</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="442" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061-1024x442.png" alt="" class="wp-image-1288" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061-1024x442.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061-300x130.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061-768x332.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061-1536x664.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061-1140x493.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103457061.png 1898w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>点击Advanced选项：</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="520" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430-1024x520.png" alt="" class="wp-image-1289" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430-1024x520.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430-300x152.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430-768x390.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430-1536x780.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430-1140x579.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103616430.png 1911w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>在Export project下，选择导出项目，我这里已经导出过，所以，可以看到<mark>Download export</mark>选项。</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="541" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041-1024x541.png" alt="" class="wp-image-1290" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041-1024x541.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041-300x159.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041-768x406.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041-1536x812.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041-1140x603.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910103837041.png 1882w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>选择导出项目之后，页面上会有个提示：Project export started. A download link will be sent by email.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="347" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738-1024x347.png" alt="" class="wp-image-1296" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738-1024x347.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738-300x102.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738-768x260.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738-1536x521.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738-1140x387.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113409738.png 1896w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>如果有在gitlab里配置邮箱的话，可以收到邮件提醒。没有配置的话，需要重新刷新页面，然后点击Advanced，可以看到上面说的download export选项，进行下载。</p>



<h4 class="wp-block-heading">2 导入项目</h4>



<p>以管理员身份登录10.0.9.25 gitlab的web界面，<a href="https://10.0.9.25:89/admin">https://10.0.9.25:89/admin</a> 依次选择新建项目，导入项目，</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="490" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339-1024x490.png" alt="" class="wp-image-1295" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339-1024x490.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339-300x144.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339-768x368.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339-1536x736.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339-1140x546.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113902339.png 1871w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="457" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341-1024x457.png" alt="" class="wp-image-1294" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341-1024x457.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341-300x134.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341-768x343.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341-1536x685.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341-1140x508.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113930341.png 1760w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="288" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719-1024x288.png" alt="" class="wp-image-1293" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719-1024x288.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719-300x84.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719-768x216.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719-1536x431.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719-1140x320.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910113959719.png 1908w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="357" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931-1024x357.png" alt="" class="wp-image-1292" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931-1024x357.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931-300x105.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931-768x268.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931-1536x536.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931-1140x398.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910114136931.png 1892w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>填入对应的项目名称，选择对应的namespace，选择导出的项目gz压缩包文件，点击导入项目即可。</p>



<h4 class="wp-block-heading">3 注意事项</h4>



<p>目标gitlab上导入时，项目名称保持和源gitlab一致，namespace也和源gitlab的namespace一致。</p>



<h3 class="wp-block-heading">四 现有的gitlab已经有用户，如何启用ldap</h3>



<p>10.0.9.25 gitlab已经有用户，如何接入ldap呢？</p>



<h4 class="wp-block-heading">1 修改gitlab配置文件</h4>



<p>在/etc/gitlab/gitlab.rb配置文件中，添加下述配置信息：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">...
gitlab_rails['ldap_enabled'] = true
...
# EOS
gitlab_rails['ldap_servers'] = YAML.load &lt;&lt;-'EOS'
  main:
    label: 'Celoan'
    host: '10.0.9.163' //openldap的服务器IP
    port: 389
    uid: 'uid'
    bind_dn: 'cn=admin,dc=celoan,dc=cn'
    password: '密码'
    encryption: 'plain'
    active_directory: true
    allow_username_or_email_login: false
    block_auto_created_users: false
    base: 'ou=users,dc=celoan,dc=cn'
    user_filter: ''
    attributes:
      username: 'uid'
      email:    'mail'
      name:      'cn'
      first_name: 'givenName'
      last_name:  'sn'
EOS
...</pre></div>



<h4 class="wp-block-heading">2 执行gitlab-ctl reconfigure使之生效</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@dbserver gitlab]# gitlab-ctl reconfigure
Starting Chef Client, version 14.13.11
....
Running handlers:
Running handlers complete
Chef Client finished, 3/696 resources updated in 40 seconds
gitlab Reconfigured!
[root@dbserver gitlab]# gitlab-rake gitlab:ldap:check</pre></div>



<h4 class="wp-block-heading">3 验证gitlab是否可以读取openldap的用户体系</h4>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@dbserver gitlab]# gitlab-rake gitlab:ldap:check
Checking LDAP ...

LDAP: ... Server: ldapmain
LDAP authentication... Success
LDAP users with access to your GitLab server (only showing the first 100 results)
        DN: uid=bo.liu,ou=users,dc=celoan,dc=cn  uid: bo.liu
        DN: uid=test01,ou=users,dc=celoan,dc=cn  uid: test01
        DN: uid=test02,ou=users,dc=celoan,dc=cn  uid: test02
        DN: uid=test03,ou=users,dc=celoan,dc=cn  uid: test03
        ....
        DN: uid=shuichang.jiang,ou=users,dc=celoan,dc=cn         uid: shuichang.jiang

Checking LDAP ... Finished

[root@dbserver gitlab]# </pre></div>



<p>从上，看到gitlab可以顺利读取ldap用户体系。</p>



<h4 class="wp-block-heading">4 验证gitlab服务和状态</h4>



<p>执行gitlab-ctl status和gitlab-ctl service-list命令来验证：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@dbserver gitlab]# gitlab-ctl status
run: alertmanager: (pid 1854) 67685s; run: log: (pid 1850) 67685s
run: gitaly: (pid 1831) 67685s; run: log: (pid 1830) 67685s
run: gitlab-exporter: (pid 1852) 67685s; run: log: (pid 1851) 67685s
run: gitlab-workhorse: (pid 1841) 67685s; run: log: (pid 1840) 67685s
run: grafana: (pid 8515) 67301s; run: log: (pid 1861) 67685s
run: logrotate: (pid 16774) 3086s; run: log: (pid 1865) 67685s
run: nginx: (pid 8506) 67302s; run: log: (pid 1834) 67685s
run: node-exporter: (pid 1853) 67685s; run: log: (pid 1849) 67685s
run: postgres-exporter: (pid 1863) 67685s; run: log: (pid 1862) 67685s
run: postgresql: (pid 1845) 67685s; run: log: (pid 1842) 67685s
down: prometheus: 0s, normally up, want up; run: log: (pid 1847) 67685s
run: redis: (pid 1859) 67685s; run: log: (pid 1858) 67685s
run: redis-exporter: (pid 1848) 67685s; run: log: (pid 1846) 67685s
run: sidekiq: (pid 8255) 67320s; run: log: (pid 1864) 67685s
run: unicorn: (pid 8791) 67285s; run: log: (pid 1832) 67685s
[root@dbserver gitlab]# gitlab-ctl service-list
alertmanager*
gitaly*
gitlab-exporter*
gitlab-workhorse*
grafana*
logrotate*
nginx*
node-exporter*
postgres-exporter*
postgresql*
prometheus*
redis*
redis-exporter*
sidekiq*
unicorn*
[root@dbserver gitlab]# </pre></div>



<h4 class="wp-block-heading">5 通过ldap来访问gitlab</h4>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="352" src="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478-1024x352.png" alt="" class="wp-image-1291" srcset="http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478-1024x352.png 1024w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478-300x103.png 300w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478-768x264.png 768w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478-1536x528.png 1536w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478-1140x392.png 1140w, http://www.knockatdatabase.com/wp-content/uploads/2024/09/image-20240910115235478.png 1887w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h4 class="wp-block-heading">6 报错处理</h4>



<p>Could not authenticate you from Ldapmain because &#8220;Undefined method `provider&#8217; for nil:nilclass&#8221;.</p>



<p>通过ldap登录gitlab，如果遇到类似错误，多半原因是原来在gitlab里创建的用户的邮箱，和该用户在ldap里设置的邮箱不一致导致。解决办法，修改gitlab底层使用的数据库users表里的email字段：</p>



<div class="wp-block-codemirror-blocks-code-block code-block"><pre class="CodeMirror" data-setting="{&quot;mode&quot;:&quot;shell&quot;,&quot;mime&quot;:&quot;text/x-sh&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;language&quot;:&quot;Shell&quot;,&quot;modeName&quot;:&quot;shell&quot;}">[root@dbserver gitlab]# gitlab-psql 
psql (10.9)
Type &quot;help&quot; for help.

gitlabhq_production=# \c
You are now connected to database &quot;gitlabhq_production&quot; as user &quot;gitlab-psql&quot;.
gitlabhq_production=# update users set email='huangw@xmjyjt.com' where id=76;
UPDATE 1
gitlabhq_production=# </pre></div>



<p>然后，重新登录即可。</p>



<h3 class="wp-block-heading">五 参考链接</h3>



<p><a href="https://blog.csdn.net/mshxuyi/article/details/126699098">https://blog.csdn.net/mshxuyi/article/details/126699098</a></p>



<p><a href="https://blog.csdn.net/Michaelwubo/article/details/126868151">https://blog.csdn.net/Michaelwubo/article/details/126868151</a></p>



<p><a href="https://blog.csdn.net/aixiaoyang168/article/details/80254375">https://blog.csdn.net/aixiaoyang168/article/details/80254375</a></p>



<p><a href="https://lisz.me/tech/webmaster/ldap-gitlab.html">https://lisz.me/tech/webmaster/ldap-gitlab.html</a></p>



<figure class="wp-block-embed is-type-wp-embed is-provider-pingcode wp-block-embed-pingcode"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="xeVO4mSH4b"><a href="https://docs.pingcode.com/ask/ask-ask/86399.html">GitLab如何进行项目迁移</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="《GitLab如何进行项目迁移》—PingCode" src="https://docs.pingcode.com/ask/ask-ask/86399.html/embed#?secret=zRk5c7JvYH#?secret=xeVO4mSH4b" data-secret="xeVO4mSH4b" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>
<p><a href="http://www.knockatdatabase.com/2024/09/11/how-to-merge-gitlab-and-enable-ldap/">多个gitlab如何迁移合并配置，以及如何把已有用户体系的gitlab再接入ldap认证</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2024/09/11/how-to-merge-gitlab-and-enable-ldap/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
