<?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>Fri, 17 Apr 2026 08:05:42 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</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>国产麒麟系统Kylin V10升级OpenSSH漏洞记录</title>
		<link>http://www.knockatdatabase.com/2026/04/17/how-to-upgrade-openssh-to-10-3p1-on-kylin-v10/</link>
					<comments>http://www.knockatdatabase.com/2026/04/17/how-to-upgrade-openssh-to-10-3p1-on-kylin-v10/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 03:44:38 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[中标麒麟]]></category>
		<category><![CDATA[OpenSSH]]></category>
		<category><![CDATA[OpenSSL]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1663</guid>

					<description><![CDATA[<p>如何在国产麒麟kylin-v10系统上升级OpenSSH到10.3P1版本</p>
<p><a href="http://www.knockatdatabase.com/2026/04/17/how-to-upgrade-openssh-to-10-3p1-on-kylin-v10/">国产麒麟系统Kylin V10升级OpenSSH漏洞记录</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<p class="has-text-color" style="color:rgb(0, 0, 0)">&nbsp;</p>



<h2 class="wp-block-heading">零 问题现象</h2>



<p class="has-text-color" style="color:rgb(0, 0, 0)">某业务系统运行在国产麒麟系统Kylin V10上，业主方委托安全机构非凡进行漏洞扫描。拿到报告之后，大部分和OpenSSH漏洞相关。</p>



<figure class="wp-block-table"><table><tbody><tr><td><strong>序号</strong></td><td><strong>漏洞名称</strong></td><td><strong>风险等级</strong></td><td><strong>加固建议</strong></td><td><strong>影响资产</strong></td></tr><tr><td>1</td><td>OpenSSH 输入验证错误漏洞(CVE-2020-12062)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>省略服务器IP</td></tr><tr><td>2</td><td>OpenSSH 代码问题漏洞(CVE-2023-38408)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr><tr><td>3</td><td>OpenSSH 操作系统命令注入漏洞(CVE-2020-15778)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr><tr><td>4</td><td>OpenSSH 安全漏洞(CVE-2023-51385)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr><tr><td>5</td><td>OpenSSH 资源管理错误漏洞(CVE-2021-28041)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr><tr><td>6</td><td>OpenSSH 安全漏洞(CVE-2021-41617)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr><tr><td>7</td><td>OpenSSH 安全漏洞(CVE-2023-51767)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr><tr><td>8</td><td>OpenSSH 远程代码执行漏洞(CVE-2024-6387)</td><td>高风险</td><td>若您不需要使用该应用或服务，请关闭该应用或服务即可。
目前厂商已经发布了升级补丁以修复这个安全问题，建议升级到当前最新版本（OpenSSH 10.2或以上）。
Linux系统请在以下页面进行下载：
http://www.openssh.com/portable.html

其他版本系统请到厂商主页下载最新版本：
http://www.openssh.com/</td><td>xx</td></tr></tbody></table></figure>



<p class="has-text-color" style="color:rgb(0, 0, 0)">登录到服务器上检查主机和OpenSSH版本相关信息：</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@ywtg-wjcc-23 ~]# cat /etc/os-release 
NAME=&quot;Kylin Linux Advanced Server&quot;
VERSION=&quot;V10 (Lance)&quot;
ID=&quot;kylin&quot;
VERSION_ID=&quot;V10&quot;
PRETTY_NAME=&quot;Kylin Linux Advanced Server V10 (Lance)&quot;
ANSI_COLOR=&quot;0;31&quot;

[root@ywtg-wjcc-23 ~]# ssh -V
OpenSSH_8.2p1, OpenSSL 1.1.1f  31 Mar 2020
[root@ywtg-wjcc-23 ~]#</pre></div>



<p>&nbsp;</p>



<h2 class="wp-block-heading">一  解决方案：升级SSH到最新版本openssh-10.3p1</h2>



<p class="has-text-color" style="color:rgb(0, 0, 0)">根据提示需要对OpenSSH进行升级。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">方式一：通过内网/官方仓库进行在线升级；</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">方式二：对OpenSSH源码编译升级；</p>



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



<h2 class="wp-block-heading">二 如何通过官方仓库进行升级</h2>



<p class="has-text-color" style="color:rgb(0, 0, 0)">由于这台服务器是直接可以访问互联网的，就直接通过麒麟官方的yum源来升级：yum update openssh</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@ywtg-wjcc-23 ~]# ping www.163.com
PING opencdn126music.jomodns.com (111.132.36.35) 56(84) bytes of data.
64 bytes from 111.132.36.35 (111.132.36.35): icmp_seq=1 ttl=51 time=50.0 ms
64 bytes from 111.132.36.35 (111.132.36.35): icmp_seq=2 ttl=51 time=48.5 ms

^C
--- opencdn126music.jomodns.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 48.549/49.273/49.998/0.724 ms
[root@ywtg-wjcc-23 ~]# rpm -q --changelog openssh | grep CVE-2023-38408
[root@ywtg-wjcc-23 ~]# yum update openssh
Kylin Linux Advanced Server 10 - Os                                                                                                                                                                      4.5 MB/s |  14 MB     00:03    
Kylin Linux Advanced Server 10 - Updates                                                                                                                                                                 7.8 MB/s |  42 MB     00:05    
Last metadata expiration check: 0:00:06 ago on Wed 15 Apr 2026 03:02:47 PM CST.
Dependencies resolved.
=========================================================================================================================================================================================================================================
 Package                                                   Architecture                                     Version                                                     Repository                                                  Size
=========================================================================================================================================================================================================================================
Upgrading:
 openssh                                                   x86_64                                           8.2p1-16.p23.ky10                                           ks10-adv-updates                                           255 k
 openssh-clients                                           x86_64                                           8.2p1-16.p23.ky10                                           ks10-adv-updates                                           538 k
 openssh-server                                            x86_64                                           8.2p1-16.p23.ky10                                           ks10-adv-updates                                           340 k

Transaction Summary
=========================================================================================================================================================================================================================================
Upgrade  3 Packages

Total download size: 1.1 M
Is this ok [y/N]: y
Downloading Packages:
(1/3): openssh-server-8.2p1-16.p23.ky10.x86_64.rpm                                                                                                                                                       554 kB/s | 340 kB     00:00    
(2/3): openssh-8.2p1-16.p23.ky10.x86_64.rpm                                                                                                                                                              410 kB/s | 255 kB     00:00    
(3/3): openssh-clients-8.2p1-16.p23.ky10.x86_64.rpm                                                                                                                                                      457 kB/s | 538 kB     00:01    
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                                                                    954 kB/s | 1.1 MB     00:01     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                                                                                                 1/1 
  Running scriptlet: openssh-server-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                         1/1 
  Running scriptlet: openssh-server-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                         1/6 
  Upgrading        : openssh-server-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                         1/6 
warning: /etc/ssh/sshd_config created as /etc/ssh/sshd_config.rpmnew

  Running scriptlet: openssh-server-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                         1/6 
  Running scriptlet: openssh-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                                2/6 
  Upgrading        : openssh-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                                2/6 
  Upgrading        : openssh-clients-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                        3/6 
  Cleanup          : openssh-clients-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                        4/6 
  Cleanup          : openssh-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                                5/6 
  Running scriptlet: openssh-server-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                         6/6 
  Cleanup          : openssh-server-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                         6/6 
  Running scriptlet: openssh-server-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                         6/6 
Warning: The unit file, source configuration file or drop-ins of sshd.service changed on disk. Run 'systemctl daemon-reload' to reload units.

  Verifying        : openssh-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                                1/6 
  Verifying        : openssh-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                                2/6 
  Verifying        : openssh-clients-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                        3/6 
  Verifying        : openssh-clients-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                        4/6 
  Verifying        : openssh-server-8.2p1-16.p23.ky10.x86_64                                                                                                                                                                         5/6 
  Verifying        : openssh-server-8.2p1-16.p07.ky10.x86_64                                                                                                                                                                         6/6 

Upgraded:
  openssh-8.2p1-16.p23.ky10.x86_64                                        openssh-clients-8.2p1-16.p23.ky10.x86_64                                        openssh-server-8.2p1-16.p23.ky10.x86_64                                       

Complete!
[root@ywtg-wjcc-23 ~]# ssh -V
OpenSSH_8.2p1, OpenSSL 1.1.1f  31 Mar 2020
[root@ywtg-wjcc-23 ~]# rpm -q --changelog openssh | grep CVE-2023-38408
- ID: CVE-2023-38408
- DESC: fix CVE-2023-38408
[root@ywtg-wjcc-23 ~]# rpm -q --changelog openssh | grep -i &quot;CVE-2023-38408&quot;
- ID: CVE-2023-38408
- DESC: fix CVE-2023-38408
[root@ywtg-wjcc-23 ~]# rpm -qa|grep ssh
openssh-help-8.2p1-16.p07.ky10.noarch
openssh-8.2p1-16.p23.ky10.x86_64
libssh-0.9.4-5.ky10.x86_64
openssh-server-8.2p1-16.p23.ky10.x86_64
openssh-clients-8.2p1-16.p23.ky10.x86_64
[root@ywtg-wjcc-23 ~]# 
[root@ywtg-wjcc-23 ~]# rpm -q --changelog openssh | grep -i &quot;CVE-&quot;          
- ID: CVE-2025-61985
- DESC: fix CVE-2025-61985
- ID: CVE-2025-61984
- DESC: fix CVE-2025-61984
- ID: CVE-2025-32728
- DESC: fix CVE-2025-32728
- ID: CVE-2025-26465
- DESC: fix CVE-2025-26465
- ID: CVE-2023-48795
- DESC: fix CVE-2023-48795
- DESC: fix CVE-2023-51385
        add backport-CVE-2023-51385-upstream-ban-user-hostnames-with-most-shell-metachar.patch
- ID: CVE-2023-38408
- DESC: fix CVE-2023-38408
[root@ywtg-wjcc-23 ~]#  </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">升级说明：麒麟操作系统（基于 CentOS/Debian 混合血统）通常会有经过兼容性测试的补丁包。国产系统厂商有时会通过“反向移植（Backporting）”修复漏洞，即版本号看起来没变，但补丁已打入。你可以通过 <code>rpm -q --changelog openssh | grep CVE-2023-38408</code> 确认。可以看到，升级之后，ssh -V看到的版本的确没有变化，但是看到的确有打了补丁了。这就有点儿类似Oracle数据库打PSU/CPU补丁一样。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">然后再执行：</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@ywtg-wjcc-23 ~]# systemctl daemon-reload
[root@ywtg-wjcc-23 ~]# systemctl restart sshd
[root@ywtg-wjcc-23 ~]# systemctl status sshd 
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2026-04-15 15:08:49 CST; 10s ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 2924984 (sshd)
    Tasks: 1
   Memory: 936.0K
   CGroup: /system.slice/sshd.service
           └─2924984 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

Apr 15 15:08:49 ywtg-wjcc-23 systemd[1]: Starting OpenSSH server daemon...
Apr 15 15:08:49 ywtg-wjcc-23 sshd[2924984]: /etc/ssh/sshd_config line 147: Deprecated option RSAAuthentication
Apr 15 15:08:49 ywtg-wjcc-23 sshd[2924984]: /etc/ssh/sshd_config line 149: Deprecated option RhostsRSAAuthentication
Apr 15 15:08:49 ywtg-wjcc-23 sshd[2924984]: Server listening on 0.0.0.0 port 22.
Apr 15 15:08:49 ywtg-wjcc-23 sshd[2924984]: Server listening on :: port 22.
Apr 15 15:08:49 ywtg-wjcc-23 systemd[1]: Started OpenSSH server daemon.
[root@ywtg-wjcc-23 ~]# ssh -V
OpenSSH_8.2p1, OpenSSL 1.1.1f  31 Mar 2020
[root@ywtg-wjcc-23 ~]# </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">这就完成了在线升级。</p>



<h2 class="wp-block-heading">三 如何通过编译OpenSSH源码进行升级</h2>



<p class="has-text-color" style="color:rgb(0, 0, 0)">如果服务器没有配置内网yum源，也没有互联网的yum仓库，我们就得通过手工下载OpenSSH源码，然后进行编译安装升级。</p>



<h3 class="wp-block-heading">0 首先安装源码编译依赖的工具和环境</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;}">yum install -y gcc make zlib-devel openssl-devel pam-devel


[root@ywtg-app-13 openssh-10.3p1]# yum install -y pam-devel                                         
Last metadata expiration check: 0:02:44 ago on Wed 15 Apr 2026 05:20:53 PM CST.
Dependencies resolved.
=========================================================================================================================================================================================================================================
 Package                                             Architecture                                     Version                                                           Repository                                                  Size
=========================================================================================================================================================================================================================================
Installing:
 pam-devel                                           x86_64                                           1.4.0-8.p10.se.06.ky10                                            ks10-adv-updates                                            24 k
Upgrading:
 libchkuid                                           x86_64                                           1.0-3.se.08.ky10                                                  ks10-adv-updates                                            15 k
 pam                                                 x86_64                                           1.4.0-8.p10.se.06.ky10                                            ks10-adv-updates                                           456 k

Transaction Summary
=========================================================================================================================================================================================================================================
Install  1 Package
Upgrade  2 Packages

Total download size: 495 k
Downloading Packages:
(1/3): libchkuid-1.0-3.se.08.ky10.x86_64.rpm                                                                                                                                                             112 kB/s |  15 kB     00:00    
(2/3): pam-1.4.0-8.p10.se.06.ky10.x86_64.rpm                                                                                                                                                             1.7 MB/s | 456 kB     00:00    
(3/3): pam-devel-1.4.0-8.p10.se.06.ky10.x86_64.rpm                                                                                                                                                        74 kB/s |  24 kB     00:00    
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                                                                    1.5 MB/s | 495 kB     00:00     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                                                                                                 1/1 
  Running scriptlet: libchkuid-1.0-3.se.08.ky10.x86_64                                                                                                                                                                               1/1 
  Upgrading        : libchkuid-1.0-3.se.08.ky10.x86_64                                                                                                                                                                               1/5 
  Running scriptlet: libchkuid-1.0-3.se.08.ky10.x86_64                                                                                                                                                                               1/5 
  Upgrading        : pam-1.4.0-8.p10.se.06.ky10.x86_64                                                                                                                                                                               2/5 
  Running scriptlet: pam-1.4.0-8.p10.se.06.ky10.x86_64                                                                                                                                                                               2/5 
  Installing       : pam-devel-1.4.0-8.p10.se.06.ky10.x86_64                                                                                                                                                                         3/5 
  Cleanup          : pam-1.4.0-8.p03.se.02.ky10.x86_64                                                                                                                                                                               4/5 
  Running scriptlet: pam-1.4.0-8.p03.se.02.ky10.x86_64                                                                                                                                                                               4/5 
  Cleanup          : libchkuid-1.0-3.se.06.ky10.x86_64                                                                                                                                                                               5/5 
  Running scriptlet: libchkuid-1.0-3.se.06.ky10.x86_64                                                                                                                                                                               5/5 
  Verifying        : pam-devel-1.4.0-8.p10.se.06.ky10.x86_64                                                                                                                                                                         1/5 
  Verifying        : libchkuid-1.0-3.se.08.ky10.x86_64                                                                                                                                                                               2/5 
  Verifying        : libchkuid-1.0-3.se.06.ky10.x86_64                                                                                                                                                                               3/5 
  Verifying        : pam-1.4.0-8.p10.se.06.ky10.x86_64                                                                                                                                                                               4/5 
  Verifying        : pam-1.4.0-8.p03.se.02.ky10.x86_64                                                                                                                                                                               5/5 

Upgraded:
  libchkuid-1.0-3.se.08.ky10.x86_64                                                                                   pam-1.4.0-8.p10.se.06.ky10.x86_64                                                                                  

Installed:
  pam-devel-1.4.0-8.p10.se.06.ky10.x86_64                                                                                                                                                                                                

Complete!
[root@ywtg-app-13 openssh-10.3p1]# </pre></div>



<p>&nbsp;</p>



<h3 class="wp-block-heading">1 下载openssh-10.3p1源码</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">访问<a href="https://www.openssh.org/portable.html">https://www.openssh.org/portable.html</a>  找到最新版本的<a href="https://ftp2.eu.openbsd.org/pub/OpenBSD/OpenSSH/portable/">https://ftp2.eu.openbsd.org/pub/OpenBSD/OpenSSH/portable/</a>  10.3p1版本。该版本发布于2026年4月2号，属于非常新的版本。</p>



<h3 class="wp-block-heading">2 解压编译安装</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;}">tar -zxvf openssh-10.3p1.tar.gz 
cd openssh-10.3p1
./configure --prefix=/usr --sysconfdir=/etc/ssh --with-md5-passwords --with-pam



[root@ywtg-app-13 ~]# pwd
/root
[root@ywtg-app-13 ~]# ll
total 84096
drwxrwxr-x 2 1000  1000     4096 Mar 25  2025 docker
-rw-r--r-- 1 root root  78805317 Sep 17  2025 docker-28.0.4.tgz
drwxr-xr-x 9  502 games     4096 Feb  2 17:18 nginx-1.28.0
-rw-r--r-- 1 root root   1280111 Feb  2 17:15 nginx-1.28.0.tar.gz
dr-x------ 2 root root      4096 Apr 29  2025 obsutil_linux_amd64_5.7.3
-rw-r--r-- 1 root root   3992450 Apr 29  2025 obsutil_linux_amd64.tar.gz
-rw-r--r-- 1 root root   2007369 Apr 15 15:15 openssh-10.3p1.tar.gz
-rw-r--r-- 1 root root       210 Feb  6 09:39 openssl.cnf
drwxr-xr-x 2 root root      4096 Mar 30 10:42 ssl
[root@ywtg-app-13 ~]# tar -zxvf openssh-10.3p1.tar.gz 
...
openssh-10.3p1/xmalloc.c
openssh-10.3p1/xmalloc.h
[root@ywtg-app-13 ~]# cd openssh-10.3p1
[root@ywtg-app-13 openssh-10.3p1]# ll
total 7752
-rw-r--r-- 1 1000 1000    694 Apr  2 16:09 aclocal.m4
-rw-r--r-- 1 1000 1000  10336 Apr  2 16:09 addr.c
...
[root@ywtg-app-13 openssh-10.3p1]# ./configure --prefix=/usr --sysconfdir=/etc/ssh --with-md5-passwords --with-pam
...

config.status: creating openbsd-compat/regress/Makefile
config.status: creating survey.sh
config.status: creating config.h
configure: WARNING: unrecognized options: --with-md5-passwords

OpenSSH has been configured with the following options:
                     User binaries: /usr/bin
                   System binaries: /usr/sbin
               Configuration files: /etc/ssh
                   Askpass program: /usr/libexec/ssh-askpass
                      Manual pages: /usr/share/man/manX
                          PID file: /var/run
  Privilege separation chroot path: /var/empty
            sshd default user PATH: /usr/bin:/bin:/usr/sbin:/sbin
                    Manpage format: doc
                       PAM support: yes
                   OSF SIA support: no
                 KerberosV support: no
                   SELinux support: no
                   libedit support: no
                   libldns support: no
  Solaris process contract support: no
           Solaris project support: no
         Solaris privilege support: no
       IP address in $DISPLAY hack: no
           Translate v4 in v6 hack: yes
                  BSD Auth support: no
              Random number source: OpenSSL internal ONLY
             Privsep sandbox style: seccomp_filter
                   PKCS#11 support: yes
                  U2F/FIDO support: yes

              Host: x86_64-pc-linux-gnu
          Compiler: cc
    Compiler flags: -g -O2 -pipe -Wno-error=format-truncation -Wall -Wextra -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wsizeof-pointer-memaccess -Wno-pointer-sign -Wno-unused-parameter -Wno-unused-result -Wimplicit-fallthrough -Wmisleading-indentation -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -ftrapv -fno-builtin-memset -fstack-protector-strong -fPIE  
Preprocessor flags:  -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_GNU_SOURCE
      Linker flags:  -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -fstack-protector-strong -pie 
         Libraries: -ldl -lutil  -lresolv
     +for channels: -lcrypto  -lz
         +for sshd: -lcrypt  -lpam

PAM is enabled. You may need to install a PAM control file 
for sshd, otherwise password authentication may fail. 
Example PAM control files can be found in the contrib/ 
subdirectory

[root@ywtg-app-13 openssh-10.3p1]# 
</pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)"><code>configure</code> 成功跑完，这说明你已经解决了所有“编译依赖”问题，系统环境已经准备就绪。</p>



<p class="has-background" style="background-color:rgb(241, 241, 239)"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<ol class="wp-block-list">
<li>警告提示：<code>-with-md5-passwords</code> 被忽略</li>
</ol>



<p>日志显示：<code>WARNING: unrecognized options: --with-md5-passwords</code>。</p>



<ul class="wp-block-list">
<li><strong>原因</strong>：在 OpenSSH 10.x 版本中，MD5 密码哈希已经因为安全原因被彻底废弃或默认不再需要该显式参数。</li>



<li><strong>对策</strong>：你可以忽略它。现在的 Linux 系统（包括你的麒麟 V10）默认使用更安全的 SHA-512。</li>
</ul>



<ol class="wp-block-list">
<li>关键点：PAM 配置文件提示</li>



<li>日志最后那段加粗的提示非常关键： <code>PAM is enabled. You may need to install a PAM control file for sshd</code></li>
</ol>



<ul class="wp-block-list">
<li><strong>解释</strong>：你开启了 PAM 支持（<code>-with-pam</code>），但新安装的 OpenSSH 可能不会自动覆盖你 <code>/etc/pam.d/sshd</code> 的配置。</li>



<li><strong>风险</strong>：如果你直接 <code>make install</code> 并重启，<strong>可能会导致现有的密码验证失效</strong>，让你无法登录。</li>



<li><strong>DBA建议</strong>：保留你现有的 <code>/etc/pam.d/sshd</code> 文件，它通常是通用的。</li>
</ul>
</blockquote>



<h3 class="wp-block-heading">3 编译</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;}">(使用 nproc 自动获取 CPU 核心数，全力加速编译过程。)

make -j$(nproc)



[root@ywtg-app-13 openssh-10.3p1]# make -j$(nproc)
...
...
cc -o ssh-sk-helper ssh-sk-helper.o ssh-sk.o sk-usbhid.o ssherr-nolibcrypto.o -L. -Lopenbsd-compat/  -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -fstack-protector-strong -pie  -lssh -lopenbsd-compat -lssh -lopenbsd-compat -ldl -lutil  -lresolv  -lcrypto  -lz
cc -o sftp sftp.o sftp-usergroup.o progressmeter.o sftp-common.o sftp-client.o sftp-glob.o ssherr-nolibcrypto.o -L. -Lopenbsd-compat/  -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -fstack-protector-strong -pie  -lssh -lopenbsd-compat -ldl -lutil  -lresolv 
[root@ywtg-app-13 openssh-10.3p1]# </pre></div>



<p>&nbsp;</p>



<h3 class="wp-block-heading">4 备份旧配置文件</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;}">cp /usr/sbin/sshd /usr/sbin/sshd.bak
cp /usr/bin/ssh /usr/bin/ssh.bak
cp -r /etc/ssh /etc/ssh.bak


[root@ywtg-app-13 openssh-10.3p1]# cp /usr/sbin/sshd /usr/sbin/sshd.bak
[root@ywtg-app-13 openssh-10.3p1]# cp /usr/bin/ssh /usr/bin/ssh.bak
[root@ywtg-app-13 openssh-10.3p1]# cp -r /etc/ssh /etc/ssh.bak
[root@ywtg-app-13 openssh-10.3p1]# </pre></div>



<p>&nbsp;</p>



<h3 class="wp-block-heading">5 安装</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;}">make install
[root@ywtg-app-13 openssh-10.3p1]# make install
Makefile:730: warning: ignoring prerequisites on suffix rule definition
(cd openbsd-compat &amp;&amp; make)
make[1]: Entering directory '/root/openssh-10.3p1/openbsd-compat'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/root/openssh-10.3p1/openbsd-compat'
/usr/bin/mkdir -p /usr/bin
/usr/bin/mkdir -p /usr/sbin
/usr/bin/mkdir -p /usr/share/man/man1
/usr/bin/mkdir -p /usr/share/man/man5
/usr/bin/mkdir -p /usr/share/man/man8
/usr/bin/mkdir -p /usr/libexec
/usr/bin/mkdir -p -m 0755 /var/empty
/usr/bin/install -c -m 0755 -s ssh /usr/bin/ssh
/usr/bin/install -c -m 0755 -s scp /usr/bin/scp
/usr/bin/install -c -m 0755 -s ssh-add /usr/bin/ssh-add
/usr/bin/install -c -m 0755 -s ssh-agent /usr/bin/ssh-agent
/usr/bin/install -c -m 0755 -s ssh-keygen /usr/bin/ssh-keygen
/usr/bin/install -c -m 0755 -s ssh-keyscan /usr/bin/ssh-keyscan
/usr/bin/install -c -m 0755 -s sshd /usr/sbin/sshd
/usr/bin/install -c -m 0755 -s sshd-session /usr/libexec/sshd-session
/usr/bin/install -c -m 0755 -s sshd-auth /usr/libexec/sshd-auth
/usr/bin/install -c -m 4711 -s ssh-keysign /usr/libexec/ssh-keysign
/usr/bin/install -c -m 0755 -s ssh-pkcs11-helper /usr/libexec/ssh-pkcs11-helper
/usr/bin/install -c -m 0755 -s ssh-sk-helper /usr/libexec/ssh-sk-helper
/usr/bin/install -c -m 0755 -s sftp /usr/bin/sftp
/usr/bin/install -c -m 0755 -s sftp-server /usr/libexec/sftp-server
/usr/bin/install -c -m 644 ssh.1.out /usr/share/man/man1/ssh.1
/usr/bin/install -c -m 644 scp.1.out /usr/share/man/man1/scp.1
/usr/bin/install -c -m 644 ssh-add.1.out /usr/share/man/man1/ssh-add.1
/usr/bin/install -c -m 644 ssh-agent.1.out /usr/share/man/man1/ssh-agent.1
/usr/bin/install -c -m 644 ssh-keygen.1.out /usr/share/man/man1/ssh-keygen.1
/usr/bin/install -c -m 644 ssh-keyscan.1.out /usr/share/man/man1/ssh-keyscan.1
/usr/bin/install -c -m 644 moduli.5.out /usr/share/man/man5/moduli.5
/usr/bin/install -c -m 644 sshd_config.5.out /usr/share/man/man5/sshd_config.5
/usr/bin/install -c -m 644 ssh_config.5.out /usr/share/man/man5/ssh_config.5
/usr/bin/install -c -m 644 sshd.8.out /usr/share/man/man8/sshd.8
/usr/bin/install -c -m 644 sftp.1.out /usr/share/man/man1/sftp.1
/usr/bin/install -c -m 644 sftp-server.8.out /usr/share/man/man8/sftp-server.8
/usr/bin/install -c -m 644 ssh-keysign.8.out /usr/share/man/man8/ssh-keysign.8
/usr/bin/install -c -m 644 ssh-pkcs11-helper.8.out /usr/share/man/man8/ssh-pkcs11-helper.8
/usr/bin/install -c -m 644 ssh-sk-helper.8.out /usr/share/man/man8/ssh-sk-helper.8
/usr/bin/mkdir -p /etc/ssh
/etc/ssh/ssh_config already exists, install will not overwrite
/etc/ssh/sshd_config already exists, install will not overwrite
/etc/ssh/moduli already exists, install will not overwrite
/usr/sbin/sshd -t -f /etc/ssh/sshd_config
/etc/ssh/sshd_config line 80: Unsupported option GSSAPIAuthentication
/etc/ssh/sshd_config line 81: Unsupported option GSSAPICleanupCredentials
/etc/ssh/sshd_config line 147: Deprecated option RSAAuthentication
/etc/ssh/sshd_config line 149: Deprecated option RhostsRSAAuthentication
[root@ywtg-app-13 openssh-10.3p1]# </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">可以看到安装的结果有提示不支持的和已经废弃的算法。</p>



<h3 class="wp-block-heading">6 检查与修复配置</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;}">/usr/sbin/sshd -t

[root@ywtg-app-13 openssh-10.3p1]# /usr/sbin/sshd -t
/etc/ssh/sshd_config line 80: Unsupported option GSSAPIAuthentication
/etc/ssh/sshd_config line 81: Unsupported option GSSAPICleanupCredentials
/etc/ssh/sshd_config line 147: Deprecated option RSAAuthentication
/etc/ssh/sshd_config line 149: Deprecated option RhostsRSAAuthentication
[root@ywtg-app-13 openssh-10.3p1]# </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">检查结果和安装之后执行检查的校验结果一致。我们手工把这些废弃的不支持的算法注释掉，就可以了。</p>



<h3 class="wp-block-heading">7 修改配置文件，注释废弃或不支持的旧版本的算法</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>步骤 A：注释掉不支持的 GSSAPI 选项</strong></p>



<p>在 10.3p1 编译时你可能没有开启 Kerberos/GSSAPI 支持，或者新版处理方式变了。</p>



<ul class="wp-block-list">
<li><strong>第 80 行</strong>：<code>GSSAPIAuthentication</code></li>



<li><strong>第 81 行</strong>：<code>GSSAPICleanupCredentials</code><strong>操作</strong>：在行首添加 <code>#</code> 注释掉。</li>
</ul>



<p><strong>步骤 B：注释掉弃用的 RSA 验证选项</strong></p>



<p>这些是极老版本的残留，新版已经默认禁用且不再识别这些指令。</p>



<ul class="wp-block-list">
<li><strong>第 147 行</strong>：<code>RSAAuthentication</code></li>



<li><strong>第 149 行</strong>：<code>RhostsRSAAuthentication</code><strong>操作</strong>：在行首添加 <code>#</code> 注释掉。</li>
</ul>
</blockquote>



<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;}"># 备份配置文件
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak2

# 注释掉报错行
sed -i 's/^GSSAPIAuthentication/#&amp;/' /etc/ssh/sshd_config
sed -i 's/^GSSAPICleanupCredentials/#&amp;/' /etc/ssh/sshd_config
sed -i 's/^RSAAuthentication/#&amp;/' /etc/ssh/sshd_config
sed -i 's/^RhostsRSAAuthentication/#&amp;/' /etc/ssh/sshd_config


[root@ywtg-app-13 openssh-10.3p1]# # 备份配置文件
[root@ywtg-app-13 openssh-10.3p1]# cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak2
[root@ywtg-app-13 openssh-10.3p1]# 
[root@ywtg-app-13 openssh-10.3p1]# # 注释掉报错行
[root@ywtg-app-13 openssh-10.3p1]# sed -i 's/^GSSAPIAuthentication/#&amp;/' /etc/ssh/sshd_config
[root@ywtg-app-13 openssh-10.3p1]# sed -i 's/^GSSAPICleanupCredentials/#&amp;/' /etc/ssh/sshd_config
[root@ywtg-app-13 openssh-10.3p1]# sed -i 's/^RSAAuthentication/#&amp;/' /etc/ssh/sshd_config
[root@ywtg-app-13 openssh-10.3p1]# sed -i 's/^RhostsRSAAuthentication/#&amp;/' /etc/ssh/sshd_config
[root@ywtg-app-13 openssh-10.3p1]# 
</pre></div>



<p>&nbsp;</p>



<h3 class="wp-block-heading">8 再次检查确认</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;}">[root@ywtg-app-13 openssh-10.3p1]# /usr/sbin/sshd -t
[root@ywtg-app-13 openssh-10.3p1]# </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">此时，不再有告警。</p>



<h3 class="wp-block-heading">9 启动新版本OpenSSH服务</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;}"># 告知 systemd 配置已变
systemctl daemon-reload

# 重启 SSH 服务
systemctl restart sshd


[root@ywtg-app-13 ~]# # 告知 systemd 配置已变
[root@ywtg-app-13 ~]# systemctl daemon-reload

# 重启 SSH 服务
systemctl restart sshd[root@ywtg-app-13 ~]# 
[root@ywtg-app-13 ~]# # 重启 SSH 服务
[root@ywtg-app-13 ~]# systemctl restart sshd
[root@ywtg-app-13 ~]# 
[root@ywtg-app-13 ~]# systemctl status sshd 
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2026-04-15 17:48:47 CST; 8s ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 3028515 (sshd)
    Tasks: 1
   Memory: 572.0K
   CGroup: /system.slice/sshd.service
           └─3028515 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

Apr 15 17:48:47 ywtg-app-13 systemd[1]: Starting OpenSSH server daemon...
Apr 15 17:48:47 ywtg-app-13 sshd[3028515]: Server listening on 0.0.0.0 port 22.
Apr 15 17:48:47 ywtg-app-13 sshd[3028515]: Server listening on :: port 22.
Apr 15 17:48:47 ywtg-app-13 systemd[1]: Started OpenSSH server daemon.
[root@ywtg-app-13 ~]# ssh -V
OpenSSH_10.3p1, OpenSSL 1.1.1f  31 Mar 2020
[root@ywtg-app-13 ~]# 
</pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">至此，OpenSSH通过编译源码的方式，安装升级到最新的10.3p1版本了。保险起见，我们断开和服务器的SSH连接，并重新执行一次SSH连接，验证是否没问题？</p>



<h2 class="wp-block-heading">四 小结和补充说明</h2>



<h3 class="wp-block-heading">1 OpenSSH是什么？</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">OpenSSH其全称是Open Secure Shell。说白了，就是原始的通过Telnet方式远程访问服务器不够安全，通过网络传输的数据都是明文。于是，OpenBSD项目下的一帮人站起来了，要管这事儿，他们决定开发一个OpenSSH套件，用于解决远程连接访问服务器的安全协议。我们可以从其<a href="https://www.openssh.org/">官网</a>上看到，</p>



<blockquote class="wp-block-quote has-text-color is-layout-flow wp-block-quote-is-layout-flow" style="color:rgb(0, 0, 0)">
<p>OpenSSH is the premier connectivity tool for remote login with the SSH protocol. It encrypts all traffic to eliminate eavesdropping, connection hijacking, and other attacks. In addition, OpenSSH provides a large suite of secure tunneling capabilities, several authentication methods, and sophisticated configuration options.<br>The OpenSSH suite consists of the following tools:<br>Remote operations are done using <a href="https://man.openbsd.org/ssh.1">ssh</a>, <a href="https://man.openbsd.org/scp.1">scp</a>, and <a href="https://man.openbsd.org/sftp.1">sftp</a>.<br>Key management with <a href="https://man.openbsd.org/ssh-add.1">ssh-add</a>, <a href="https://man.openbsd.org/ssh-keysign.8">ssh-keysign</a>, <a href="https://man.openbsd.org/ssh-keyscan.1">ssh-keyscan</a>, and <a href="https://man.openbsd.org/ssh-keygen.1">ssh-keygen</a>.<br>The service side consists of <a href="https://man.openbsd.org/sshd.8">sshd</a>, <a href="https://man.openbsd.org/sftp-server.8">sftp-server</a>, and <a href="https://man.openbsd.org/ssh-agent.1">ssh-agent</a>.<br>OpenSSH is developed by a few developers of the <a href="https://www.openbsd.org/">OpenBSD Project</a> and made available under a BSD-style license.<br>OpenSSH is incorporated into many commercial products, but very few of those companies assist OpenSSH with funding.<br>Contributions towards OpenSSH can be sent to the <a href="https://www.openbsd.org/donations.html">OpenBSD Foundation</a>. </p>
</blockquote>



<p class="has-text-color" style="color:rgb(0, 0, 0)">OpenSSH套件包括我们常用的ssh远程连接，scp加密传输拷贝文件，sftp加密文件传输等。OpenSSH相当于是服务器的一套高级「智能安全门禁系统」。</p>



<h3 class="wp-block-heading">2 为什么要升级OpenSSH?</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">从上文我们知道了 OpenSSH 是什么，以及它的作用和功能。既然它对于远程连接、管理、访问、运维服务器非常重要，那么就需要保证这套“门禁系统”的安全和可靠。升级 OpenSSH，其实就相当于升级这套门禁系统的锁芯。长期不升级，可能会出现服务器沦为肉鸡、被恶意利用或被植入木马等风险。</p>



<h3 class="wp-block-heading">3 升级过程中有哪些注意事项？</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">务必开启多个 SSH 会话窗口，最好另外单独开启一个 Telnet 窗口，避免升级过程中出现错误或失败，导致与服务器失去远程连接。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">升级过程中务必备份升级前与 OpenSSH 相关的配置文件。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">软件升级后重启 sshd 服务之前，务必使用新版本 sshd 进行测试和验证，避免重启后服务启动失败。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">通过源码编译安装升级之前，确保服务器已安装并配置 gcc、zlib、openssl 和 pam 的开发库。</p>



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



<h3 class="wp-block-heading">4 pam是什么？pam有什么作用？升级过程中为啥加上 &#8211;with-pam 选项？它和OpenSSH啥关系？</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">Pluggable Authentication Module，顾名思义，可插拔式的认证模块。它的出现具有一定的历史，最早可以追溯到1995年，由Sun公司最早提出，为了解决Solaris操作系统中认证逻辑过于死板、僵化的问题而提出的。因为在早期的Linux系统中，每一个需要登录认证的系统服务，比如ftp服务、Telnet各个模块需要自己写一套独立的用户认证登录系统，并且硬编码了认证登录逻辑。这样的设计有一个缺陷：比如，如果我们想修改操作系统用户密码的加密算法，从DES改为MD5，那么我们就得修改所有需要登录程序(如ftp/Telnet等)的源代码，并且需要重新编译发布。如果下次，再更换或者引入一种新的认证机制的话，这套流程又得再走一遍。如今看来，这就非常非常不方便了。于是，一波儿Sun工程师提出了PAM的雏形，让操作系统的认证模块变得像U盘一样可以实现热插拔，系统管理员只需要修改/etc/pam.d/* 配置文件，就可以实现在不重启、不修改程序的情况下，改变整个系统的安全策略。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">PAM除了提供热插拔的认证模块之外，它还提供了可以限制用户使用系统资源的限制机制、可以设定哪些用户只能在什么时间段访问系统、从哪些IP段来访问系统等机制。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">展开一点儿，如果你曾经在Unix/Linux系统上安装配置过Oracle数据库的话，那么你一定对于/etc/security/limits.conf文件的配置并不陌生。比如，我手上一台Oracle Linux 9.6的机器上部署了一套单实例的Oracle数据库：</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@oel-r9u6-11 ~]# cat /etc/oracle-release 
Oracle Linux Server release 9.6
[root@oel-r9u6-11 ~]# head /etc/security/limits.conf 
# /etc/security/limits.conf
#
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.
#
#Also note that configuration files in /etc/security/limits.d directory,
#which are read in alphabetical order, override the settings in this
#file in case the domain is the same or more specific.
#That means, for example, that setting a limit for wildcard domain here
#can be overridden with a wildcard setting in a config file in the
[root@oel-r9u6-11 ~]# </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">从该配置文件中，我们可以看到，该文件用于限制那些通过PAM登录服务器的用户对于系统资源使用的限制，此外，/etc/security/limits.d 路径下的所有配置文件，会以字母先后顺序读取生效，那些配置文件里的配置项，也会覆盖掉本文件（/etc/security/limits.conf）里的限制和设置。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">顺便给出/etc/security/limits.d/ 路径下的配置文件的配置信息，一看便知：</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@oel-r9u6-11 ~]# ll /etc/security/limits.d/
total 8
-rw-r--r--. 1 root root  514 Apr 10  2024 25-pw-rlimits.conf
-rw-r--r--. 1 root root 1245 Oct 24 08:53 oracle-ai-database-preinstall-26ai.conf
[root@oel-r9u6-11 ~]# cat /etc/security/limits.d/25-pw-rlimits.conf 
# This file was installed by PipeWire project for its libpipewire-module-rt.so

# It is up to the distribution/user to create the @pipewire group and to add the
# relevant users to the group.
#
# PipeWire will fall back to the RTKit DBus service when the user is not able to
# acquire RT priorities with rlimits.
#
# If the group is not automatically created, the match rule will never be true
# and this file will have no effect.
#
@pipewire   - rtprio  95
@pipewire   - nice    -19
@pipewire   - memlock 4194304
[root@oel-r9u6-11 ~]# cat /etc/security/limits.d/oracle-ai-database-preinstall-26ai.conf 

# oracle-ai-database-preinstall-26ai setting for nofile soft limit is 1024
oracle   soft   nofile    1024

# oracle-ai-database-preinstall-26ai setting for nofile hard limit is 65536
oracle   hard   nofile    65536

# oracle-ai-database-preinstall-26ai setting for nproc soft limit is 16384
# refer orabug15971421 for more info.
oracle   soft   nproc    16384

# oracle-ai-database-preinstall-26ai setting for nproc hard limit is 16384
oracle   hard   nproc    16384

# oracle-ai-database-preinstall-26ai setting for stack soft limit is 10240KB
oracle   soft   stack    10240

# oracle-ai-database-preinstall-26ai setting for stack hard limit is 32768KB
oracle   hard   stack    32768

# oracle-ai-database-preinstall-26ai setting for memlock hard limit is maximum of 128GB on x86_64 or 3GB on x86 OR 90 % of RAM
oracle   hard   memlock    134217728

# oracle-ai-database-preinstall-26ai setting for memlock soft limit is maximum of 128GB on x86_64 or 3GB on x86 OR 90% of RAM
oracle   soft   memlock    134217728

# oracle-ai-database-preinstall-26ai setting for data soft limit is 'unlimited'
oracle   soft   data    unlimited

# oracle-ai-database-preinstall-26ai setting for data hard limit is 'unlimited'
oracle   hard   data    unlimited
[root@oel-r9u6-11 ~]# </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">话题再转回来，如果我们通过源码编译安装配置 OpenSSH 时不带上 &#8211;with-pam 选项，会有什么后果呢？这意味着以后通过 SSH 连接这台服务器时，无法使用 PAM 的热插拔认证模块进行口令校验以及对用户资源使用的限制等认证与控制。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">至于说PAM和OpenSSH的关系，好比方用户通过SSH连接到远端的服务器之后，SSH自身不对该用户的用户名、密码进行校验，转而调用PAM进行验证，通过之后，再根据PAM的设置，对用户可以使用的系统资源进行限制。</p>



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



<h3 class="wp-block-heading">5 补充：OpenSSH和OpenSSL有啥关系？</h3>



<p class="has-text-color" style="color:rgb(0, 0, 0)">OpenSSH可以理解为一种远程连接请求的协议和应用层的工具集，而OpenSSL却是底层的一种加解密的密码学库。OpenSSH依赖于OpenSSL，像上述我们在编译安装OpenSSH之前，需要确保系统上已经有安装openssl-devel的库文件原因就在于此。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">场景举例说明：用户通过执行 <code>ssh username@server_ip</code> 发起连接请求前，就约定了要使用 AES-256 对通信进行加密。OpenSSH 调用 OpenSSL 的 AES-256 算法对请求进行加密。加密后的数据到达服务端之后，再用同样的算法进行解密。确认加解密一切正常，才算连接成功。大致过程可能类似这样，这是我的理解，实际过程可能更复杂。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">OpenSSH场景下使用的命令有：ssh,scp,ssh-keygen等；</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">OpenSSL场景下使用的常见命令：openssl x509创建或者查看证书等；例如，在某些场景下，需要对NGINX执行自签名的证书，进行HTTPS访问时，就会用到类似下述命令：</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;}">openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt
</pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">同时，OpenSSL也常见用于对Web网站的签名证书生成。配置站点的HTTPS证书时，经常会用到.crt和.key的文件，这些就是有OpenSSL生成的证书。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">而常见的id_rsa和id_rsa.pub文件，却是由ssh-keygen命令生成的秘钥对文件。不过，ssh-keygen生成秘钥对儿文件时，底层依然是调用了OpenSSL提供的随机数生成器和数学模型来实现的。</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">升级系统的OpenSSL要比OpenSSH危险系数更高，务必注意。</p>



<h3 class="wp-block-heading">6 手工编译安装OpenSSH源码的代码清单</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;}">yum install -y gcc make zlib-devel openssl-devel pam-devel

tar -zxvf openssh-10.3p1.tar.gz 
cd openssh-10.3p1
./configure --prefix=/usr --sysconfdir=/etc/ssh --with-md5-passwords --with-pam


make -j$(nproc)


cp /usr/sbin/sshd /usr/sbin/sshd.bak
cp /usr/bin/ssh /usr/bin/ssh.bak
cp -r /etc/ssh /etc/ssh.bak

make install


# 备份配置文件
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak2

# 注释掉报错行
sed -i 's/^GSSAPIAuthentication/#&amp;/' /etc/ssh/sshd_config
sed -i 's/^GSSAPICleanupCredentials/#&amp;/' /etc/ssh/sshd_config
sed -i 's/^RSAAuthentication/#&amp;/' /etc/ssh/sshd_config
sed -i 's/^RhostsRSAAuthentication/#&amp;/' /etc/ssh/sshd_config


/usr/sbin/sshd -t


# 告知 systemd 配置已变
systemctl daemon-reload

# 重启 SSH 服务
systemctl restart sshd

systemctl status sshd

ssh -V </pre></div>



<p>&nbsp;</p>



<p class="has-text-color" style="color:rgb(0, 0, 0)">&nbsp;</p>
<p><a href="http://www.knockatdatabase.com/2026/04/17/how-to-upgrade-openssh-to-10-3p1-on-kylin-v10/">国产麒麟系统Kylin V10升级OpenSSH漏洞记录</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2026/04/17/how-to-upgrade-openssh-to-10-3p1-on-kylin-v10/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>
		<item>
		<title>解决eslint-plugin-vue构建报错</title>
		<link>http://www.knockatdatabase.com/2024/07/19/how-to-resolve-eslint-plugin-vue-error/</link>
					<comments>http://www.knockatdatabase.com/2024/07/19/how-to-resolve-eslint-plugin-vue-error/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Fri, 19 Jul 2024 07:25:08 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Vue]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1278</guid>

					<description><![CDATA[<p>一项目背景 在构建前端Vue工程时，遇到下述错误： 二 解决错误 从报错日志，看应该是eslint-plugin-vue依赖的版本不对。参考GitHub上有网友提出的issue，以及解决办法，把该依赖的版本改为7.20.0。 将package.json中的&#8221;eslint-plugin-vue&#8221;: &#8220;^8.0.3&#8243;,修改为&#8221;eslint-plugin-vue&#8221;: &#8220;^7.20.0&#8243;。下述是修改后的文件。 { &#160;"name": "gxd-backend-multi-ui", &#160;"version": "0.1.0", &#160;"private": true, &#160;"scripts": { &#160; &#160;"serve": "vue-cli-service serve", &#160; &#160;"build": "vue-cli-service build", &#160; &#160;"lint": "eslint --ext .js,.vue src", &#160; &#160;"build:prod": "vue-cli-service build", &#160; &#160;"build:stage": "vue-cli-service build --mode staging", &#160; &#160;"dev": "vue-cli-service serve", &#160; &#160;"preview": "node build/index.js --preview" }, &#160;"dependencies": { &#160; &#160;"@riophae/vue-treeselect": "0.4.0", &#160; &#160;"axios": "0.24.0", &#160; &#160;"clipboard": "2.0.8", &#160; &#160;"core-js": "3.25.3", &#160; &#160;"echarts": "5.4.0", &#160; &#160;"element-ui": "2.15.12", &#160; &#160;"file-saver": "2.0.5", &#160; &#160;"fuse.js": "6.4.3", &#160; &#160;"gxdpt-components": "^1.0.18", &#160; &#160;"highlight.js": "9.18.5", &#160; &#160;"js-beautify": "1.13.0", &#160; &#160;"js-cookie": "3.0.1", &#160; &#160;"jsencrypt": "3.0.0-rc.1", &#160; &#160;"nprogress": "0.2.0", &#160; &#160;"quill": "1.3.7", &#160; &#160;"screenfull": "5.0.2", &#160; &#160;"sortablejs": "1.10.2", &#160; &#160;"vue": "^2.6.14", &#160; &#160;"vue-count-to": "1.0.13", &#160; &#160;"vue-cropper": "0.5.5", &#160; &#160;"vue-meta": "2.4.0", &#160; &#160;"vue-pdf": "^4.1.0", &#160; &#160;"vue-router": "3.4.9", &#160; &#160;"vuedraggable": "2.24.3", &#160; &#160;"vuex": "3.6.0", &#160; &#160;"watermark-dom": "^2.3.0" }, &#160;"devDependencies": { &#160; &#160;"@babel/core": "^7.12.16", &#160; &#160;"@babel/eslint-parser": "^7.12.16", &#160; &#160;"@vue/cli-plugin-babel": "4.4.6", &#160; &#160;"@vue/cli-plugin-eslint": "4.4.6", &#160; &#160;"@vue/cli-service": "4.4.6", &#160; &#160;"@vue/eslint-config-standard": "^6.1...</p>
<p><a href="http://www.knockatdatabase.com/2024/07/19/how-to-resolve-eslint-plugin-vue-error/">解决eslint-plugin-vue构建报错</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">一项目背景</h3>



<p>在构建前端Vue工程时，遇到下述错误：</p>



<pre class="wp-block-code"><code>+ npm config set registry http://nexus.celoan.opt/repository/npm-public/
+ npm install
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: goods@0.1.0
npm ERR! Found: eslint-plugin-vue@8.7.1
npm ERR! node_modules/eslint-plugin-vue
npm ERR!   dev eslint-plugin-vue@"^8.0.3" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer eslint-plugin-vue@"^7.0.0" from @vue/eslint-config-standard@6.1.0
npm ERR! node_modules/@vue/eslint-config-standard
npm ERR!   dev @vue/eslint-config-standard@"^6.1.0" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /root/.npm/eresolve-report.txt for a full report.
​
npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2024-07-11T09_36_42_223Z-debug-0.log
Build step 'Execute shell' marked build as failure
Finished: FAILURE
</code></pre>



<h3 class="wp-block-heading">二 解决错误</h3>



<p>从报错日志，看应该是eslint-plugin-vue依赖的版本不对。参考GitHub上有网友提出的issue，以及解决办法，把该依赖的版本改为7.20.0。</p>



<p>将package.json中的&#8221;eslint-plugin-vue&#8221;: &#8220;^8.0.3&#8243;,修改为&#8221;eslint-plugin-vue&#8221;: &#8220;^7.20.0&#8243;。下述是修改后的文件。</p>



<pre class="wp-block-preformatted">{<br> &nbsp;"name": "gxd-backend-multi-ui",<br> &nbsp;"version": "0.1.0",<br> &nbsp;"private": true,<br> &nbsp;"scripts": {<br> &nbsp; &nbsp;"serve": "vue-cli-service serve",<br> &nbsp; &nbsp;"build": "vue-cli-service build",<br> &nbsp; &nbsp;"lint": "eslint --ext .js,.vue src",<br> &nbsp; &nbsp;"build:prod": "vue-cli-service build",<br> &nbsp; &nbsp;"build:stage": "vue-cli-service build --mode staging",<br> &nbsp; &nbsp;"dev": "vue-cli-service serve",<br> &nbsp; &nbsp;"preview": "node build/index.js --preview"<br>  },<br> &nbsp;"dependencies": {<br> &nbsp; &nbsp;"@riophae/vue-treeselect": "0.4.0",<br> &nbsp; &nbsp;"axios": "0.24.0",<br> &nbsp; &nbsp;"clipboard": "2.0.8",<br> &nbsp; &nbsp;"core-js": "3.25.3",<br> &nbsp; &nbsp;"echarts": "5.4.0",<br> &nbsp; &nbsp;"element-ui": "2.15.12",<br> &nbsp; &nbsp;"file-saver": "2.0.5",<br> &nbsp; &nbsp;"fuse.js": "6.4.3",<br> &nbsp; &nbsp;"gxdpt-components": "^1.0.18",<br> &nbsp; &nbsp;"highlight.js": "9.18.5",<br> &nbsp; &nbsp;"js-beautify": "1.13.0",<br> &nbsp; &nbsp;"js-cookie": "3.0.1",<br> &nbsp; &nbsp;"jsencrypt": "3.0.0-rc.1",<br> &nbsp; &nbsp;"nprogress": "0.2.0",<br> &nbsp; &nbsp;"quill": "1.3.7",<br> &nbsp; &nbsp;"screenfull": "5.0.2",<br> &nbsp; &nbsp;"sortablejs": "1.10.2",<br> &nbsp; &nbsp;"vue": "^2.6.14",<br> &nbsp; &nbsp;"vue-count-to": "1.0.13",<br> &nbsp; &nbsp;"vue-cropper": "0.5.5",<br> &nbsp; &nbsp;"vue-meta": "2.4.0",<br> &nbsp; &nbsp;"vue-pdf": "^4.1.0",<br> &nbsp; &nbsp;"vue-router": "3.4.9",<br> &nbsp; &nbsp;"vuedraggable": "2.24.3",<br> &nbsp; &nbsp;"vuex": "3.6.0",<br> &nbsp; &nbsp;"watermark-dom": "^2.3.0"<br>  },<br> &nbsp;"devDependencies": {<br> &nbsp; &nbsp;"@babel/core": "^7.12.16",<br> &nbsp; &nbsp;"@babel/eslint-parser": "^7.12.16",<br> &nbsp; &nbsp;"@vue/cli-plugin-babel": "4.4.6",<br> &nbsp; &nbsp;"@vue/cli-plugin-eslint": "4.4.6",<br> &nbsp; &nbsp;"@vue/cli-service": "4.4.6",<br> &nbsp; &nbsp;"@vue/eslint-config-standard": "^6.1.0",<br> &nbsp; &nbsp;"babel-eslint": "10.1.0",<br> &nbsp; &nbsp;"babel-plugin-dynamic-import-node": "2.3.3",<br> &nbsp; &nbsp;"chalk": "4.1.0",<br> &nbsp; &nbsp;"compression-webpack-plugin": "5.0.2",<br> &nbsp; &nbsp;"connect": "3.6.6",<br> &nbsp; &nbsp;"eslint": "^7.32.0",<br> &nbsp; &nbsp;"eslint-plugin-import": "^2.25.3",<br> &nbsp; &nbsp;"eslint-plugin-node": "^11.1.0",<br> &nbsp; &nbsp;"eslint-plugin-promise": "^5.1.0",<br> &nbsp; &nbsp;"eslint-plugin-vue": "^7.20.0",<br> &nbsp; &nbsp;"lint-staged": "^11.1.2",<br> &nbsp; &nbsp;"runjs": "4.4.2",<br> &nbsp; &nbsp;"sass": "1.32.13",<br> &nbsp; &nbsp;"sass-loader": "10.1.1",<br> &nbsp; &nbsp;"script-ext-html-webpack-plugin": "2.1.5",<br> &nbsp; &nbsp;"svg-sprite-loader": "5.1.1",<br> &nbsp; &nbsp;"vue-template-compiler": "2.6.12"<br>  },<br> &nbsp;"engines": {<br> &nbsp; &nbsp;"node": "&gt;=8.9",<br> &nbsp; &nbsp;"npm": "&gt;= 3.0.0"<br>  },<br> &nbsp;"gitHooks": {<br> &nbsp; &nbsp;"pre-commit": "lint-staged"<br>  },<br> &nbsp;"husky": {<br> &nbsp; &nbsp;"hooks": {<br> &nbsp; &nbsp; &nbsp;"pre-commit": "lint-staged"<br> &nbsp;  }<br>  },<br> &nbsp;"keywords": [<br> &nbsp; &nbsp;"vue",<br> &nbsp; &nbsp;"admin",<br> &nbsp; &nbsp;"dashboard",<br> &nbsp; &nbsp;"element-ui",<br> &nbsp; &nbsp;"boilerplate",<br> &nbsp; &nbsp;"admin-template",<br> &nbsp; &nbsp;"management-system"<br>  ],<br> &nbsp;"repository": {<br> &nbsp; &nbsp;"type": "git",<br> &nbsp; &nbsp;"url": "https://gitee.com/y_project/RuoYi-Cloud.git"<br>  }<br>}<br>​</pre>



<h3 class="wp-block-heading">三 重新构建</h3>



<pre class="wp-block-preformatted">+ npm config set registry http://nexus.celoan.opt/repository/npm-public/<br>+ npm install<br>npm WARN ERESOLVE overriding peer dependency<br>npm WARN deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.<br>​<br>....<br>added 1700 packages in 49s<br>​<br>161 packages are looking for funding<br>  run `npm fund` for details<br>+ npm run build:prod<br>​<br>&gt; goods@0.1.0 build:prod<br>&gt; vue-cli-service build<br>​</pre>



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



<p><a href="https://github.com/vuejs/eslint-config-standard/issues/24">https://github.com/vuejs/eslint-config-standard/issues/24</a></p>
<p><a href="http://www.knockatdatabase.com/2024/07/19/how-to-resolve-eslint-plugin-vue-error/">解决eslint-plugin-vue构建报错</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2024/07/19/how-to-resolve-eslint-plugin-vue-error/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>如何把elasticsearch添加到systemd系统服务</title>
		<link>http://www.knockatdatabase.com/2024/05/13/how-to-add-elasticsearch-to-systemd/</link>
					<comments>http://www.knockatdatabase.com/2024/05/13/how-to-add-elasticsearch-to-systemd/#respond</comments>
		
		<dc:creator><![CDATA[Admin]]></dc:creator>
		<pubDate>Mon, 13 May 2024 03:56:35 +0000</pubDate>
				<category><![CDATA[elasticsearch]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">http://www.knockatdatabase.com/?p=1274</guid>

					<description><![CDATA[<p>如何把elasticsearch添加到systemd系统服务</p>
<p><a href="http://www.knockatdatabase.com/2024/05/13/how-to-add-elasticsearch-to-systemd/">如何把elasticsearch添加到systemd系统服务</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">一背景说明</h3>



<p>在一个3节点的elasticsearch集群，当前是以elastic用户通过手工启动服务来运行。机器信息如下：</p>



<pre class="wp-block-code"><code>&#91;root@localhost ~]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
&#91;root@localhost ~]# uname -rm
3.10.0-1160.el7.x86_64 x86_64
&#91;root@localhost ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           7821        5013        2458           9         349        2568
Swap:          8063           0        8063
&#91;root@localhost ~]# </code></pre>



<p>elasticsearch版本为7.17.1，信息：</p>



<pre class="wp-block-preformatted">[root@localhost ~]# su - elastic<br>上一次登录：五 5月 10 11:56:57 CST 2024pts/0 上<br>-bash-4.2$ pwd<br>/home/elastic<br>-bash-4.2$ ll<br>总用量 0<br>drwxr-xr-x 11 elastic elastic 179 6月 &nbsp; 7 2023 elasticsearch-7.17.1<br>-bash-4.2$ ./elasticsearch-7.17.1/<br>bin/ &nbsp; &nbsp; config/  data/ &nbsp;  jdk/ &nbsp; &nbsp; lib/ &nbsp; &nbsp; logs/ &nbsp;  modules/ –p/ &nbsp; &nbsp;  plugins/ <br>-bash-4.2$ ./elasticsearch-7.17.1/bin/elasticsearch --version<br>warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME<br>Future versions of Elasticsearch will require Java 11; your Java version from [/usr/local/jdk1.8.0_341/jre] does not meet this requirement. Consider switching to a distribution of Elasticsearch with a bundled JDK. If you are already using a distribution with a bundled JDK, ensure the JAVA_HOME environment variable is not set.<br>Version: 7.17.1, Build: default/tar/e5acb99f822233d62d6444ce45a4543dc1c8059a/2022-02-23T22:20:54.153567231Z, JVM: 1.8.0_341<br>-bash-4.2$ </pre>



<p>elastic用户配置信息：</p>



<pre class="wp-block-preformatted">-bash-4.2$ id<br>uid=1001(elastic) gid=1001(elastic) 组=1001(elastic)<br>-bash-4.2$ ulimit -a<br>core file size &nbsp; &nbsp; &nbsp; &nbsp;  (blocks, -c) 0<br>data seg size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (kbytes, -d) unlimited<br>scheduling priority &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (-e) 0<br>file size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (blocks, -f) unlimited<br>pending signals &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (-i) 31191<br>max locked memory &nbsp; &nbsp; &nbsp; (kbytes, -l) 64<br>max memory size &nbsp; &nbsp; &nbsp; &nbsp; (kbytes, -m) unlimited<br>open files &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (-n) 65536<br>pipe size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (512 bytes, -p) 8<br>POSIX message queues &nbsp; &nbsp; (bytes, -q) 819200<br>real-time priority &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (-r) 0<br>stack size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (kbytes, -s) 8192<br>cpu time &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (seconds, -t) unlimited<br>max user processes &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (-u) 4096<br>virtual memory &nbsp; &nbsp; &nbsp; &nbsp;  (kbytes, -v) unlimited<br>file locks &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  (-x) unlimited<br>-bash-4.2$ </pre>



<p>手动启动命令为：</p>



<pre class="wp-block-preformatted">-bash-4.2$ /home/elastic/elasticsearch-7.17.1/bin/elasticsearch &amp;</pre>



<h3 class="wp-block-heading">二 需求场景</h3>



<p>需要将这个3节点的elasticsearch集群启动方式，修改为随着操作系统的启动而自动启动。而不要每次操作系统重启之后，还需要人为介入，去手工登录每台机器，然后再去启动elasticsearch服务。</p>



<h3 class="wp-block-heading">三 解决方案</h3>



<p>由于系统是CentOS 7.9，可以考虑将该服务加入到systemd，有操作系统去管控该服务。</p>



<h4 class="wp-block-heading">1 创建配置文件</h4>



<pre class="wp-block-preformatted">cat &lt;&lt;EOF &gt; /etc/systemd/system/elasticsearch.service<br>[Unit]<br>Description=elasticsearch<br>​<br>[Service]<br>User=elastic<br>ExecStart=/home/elastic/elasticsearch-7.17.1/bin/elasticsearch<br>Restart=always<br>​<br>[Install]<br>WantedBy=multi-user.target<br>EOF</pre>



<h4 class="wp-block-heading">2 加载systemd daemon服务</h4>



<pre class="wp-block-preformatted">systemctl daemon-reload </pre>



<h4 class="wp-block-heading">3 配置和启动elasticsearch服务</h4>



<pre class="wp-block-preformatted">systemctl enable elasticsearch.service <br>​<br>systemctl start elasticsearch.service <br>​<br>systemctl status elasticsearch.service </pre>



<h3 class="wp-block-heading">四 故障处理</h3>



<h4 class="wp-block-heading">1 启动日志</h4>



<p>通过systemctl start elasticsearch之后，发现服务表面上来看是正常启动的。但是，9200,9300端口在服务器上根本没有打开，客户端也无法正常访问elasticsearch服务。</p>



<p>通过journalctl -f来查看日志时，发现elasticsearch在不断重启，且看到有类似下述错误：</p>



<pre class="wp-block-preformatted">[root@localhost ~]# journalctl -f<br>.....<br>5月 10 15:11:36 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:36,047][INFO ][o.e.t.NettyAllocator &nbsp; &nbsp; ] [ES01] creating NettyAllocator with the following configs: [name=elasticsearch_configured, chunk_size=1mb, suggested_max_allocation_size=1mb, factors={es.unsafe.use_netty_default_chunk_and_page_size=false, g1gc_enabled=true, g1gc_region_size=4mb}]<br>5月 10 15:11:36 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:36,088][INFO ][o.e.i.r.RecoverySettings ] [ES01] using rate limit [40mb] with [default=40mb, read=0b, write=0b, max=0b]<br>5月 10 15:11:36 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:36,139][INFO ][o.e.d.DiscoveryModule &nbsp;  ] [ES01] using discovery type [zen] and seed hosts providers [settings]<br>5月 10 15:11:36 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:36,737][INFO ][o.e.g.DanglingIndicesState] [ES01] gateway.auto_import_dangling_indices is disabled, dangling indices will not be automatically detected or imported and must be managed manually<br>5月 10 15:11:37 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:37,774][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] initialized<br>5月 10 15:11:37 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:37,775][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] starting ...<br>5月 10 15:11:37 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:37,798][INFO ][o.e.x.s.c.f.PersistentCache] [ES01] persistent cache index loaded<br>5月 10 15:11:37 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:37,800][INFO ][o.e.x.d.l.DeprecationIndexingComponent] [ES01] deprecation component started<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:38,009][INFO ][o.e.t.TransportService &nbsp; ] [ES01] publish_address {10.0.9.239:9300}, bound_addresses {[::]:9300}<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:38,877][INFO ][o.e.b.BootstrapChecks &nbsp;  ] [ES01] bound or publishing to a non-loopback address, enforcing bootstrap checks<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch.<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: bootstrap check failure [1] of [1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535]<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: ERROR: Elasticsearch did not exit normally - check the logs at /home/elastic/elasticsearch-7.17.1/logs/es-cluster.log<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:38,904][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] stopping ...<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:38,929][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] stopped<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:38,930][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] closing ...<br>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: [2024-05-10T15:11:38,950][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] closed<br>5月 10 15:11:39 localhost.localdomain systemd[1]: elasticsearch.service: main process exited, code=exited, status=78/n/a<br>5月 10 15:11:39 localhost.localdomain systemd[1]: Unit elasticsearch.service entered failed state.<br>5月 10 15:11:39 localhost.localdomain systemd[1]: elasticsearch.service failed.<br>5月 10 15:11:39 localhost.localdomain systemd[1]: elasticsearch.service holdoff time over, scheduling restart.<br>5月 10 15:11:39 localhost.localdomain systemd[1]: Stopped elasticsearch.<br>5月 10 15:11:39 localhost.localdomain systemd[1]: Started elasticsearch.<br>5月 10 15:11:44 localhost.localdomain elasticsearch[8755]: [2024-05-10T15:11:44,383][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] version[7.17.1], pid[8755], build[default/tar/e5acb99f822233d62d6444ce45a4543dc1c8059a/2022-02-23T22:20:54.153567231Z], OS[Linux/3.10.0-1160.el7.x86_64/amd64], JVM[Eclipse Adoptium/OpenJDK 64-Bit Server VM/17.0.2/17.0.2+8]<br>5月 10 15:11:44 localhost.localdomain elasticsearch[8755]: [2024-05-10T15:11:44,385][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] JVM home [/home/elastic/elasticsearch-7.17.1/jdk], using bundled JDK [true]<br>5月 10 15:11:44 localhost.localdomain elasticsearch[8755]: [2024-05-10T15:11:44,386][INFO ][o.e.n.Node &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ] [ES01] JVM arguments [-Xshare:auto, -Des.networkaddress.cache.ttl=60, -Des.networkaddress.cache.negative.ttl=10, -XX:+AlwaysPreTouch, -Xss1m, -Djava.awt.headless=true, -Dfile.encoding=UTF-8, -Djna.nosys=true, -XX:-OmitStackTraceInFastThrow, -XX:+ShowCodeDetailsInExceptionMessages, -Dio.netty.noUnsafe=true, -Dio.netty.noKeySetOptimization=true, -Dio.netty.recycler.maxCapacityPerThread=0, -Dio.netty.allocator.numDirectArenas=0, -Dlog4j.shutdownHookEnabled=false, -Dlog4j2.disable.jmx=true, -Dlog4j2.formatMsgNoLookups=true, -Djava.locale.providers=SPI,COMPAT, --add-opens=java.base/java.io=ALL-UNNAMED, -Xms4g, -Xmx4g, -XX:+UseG1GC, -Djava.io.tmpdir=/tmp/elasticsearch-2589143606734508201, -XX:+HeapDumpOnOutOfMemoryError, -XX:+ExitOnOutOfMemoryError, -XX:HeapDumpPath=data, -XX:ErrorFile=logs/hs_err_pid%p.log, -Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m, -XX:MaxDirectMemorySize=2147483648, -XX:G1HeapRegionSize=4m, -XX:InitiatingHeapOccupancyPercent=30, -XX:G1ReservePercent=15, -Des.path.home=/home/elastic/elasticsearch-7.17.1, -Des.path.conf=/home/elastic/elasticsearch-7.17.1/config, -Des.distribution.flavor=default, -Des.distribution.type=tar, -Des.bundled_jdk=true]<br>^C<br>[root@localhost ~]# </pre>



<p>5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: bootstrap check failure [1] of [1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535] 5月 10 15:11:38 localhost.localdomain elasticsearch[8504]: ERROR: Elasticsearch did not exit normally &#8211; check the logs at /home/elastic/elasticsearch-7.17.1/logs/es-cluster.log</p>



<h4 class="wp-block-heading">2 分析问题：</h4>



<p>通过手工切换到elastic用户，并且手工启动服务时，没有任何问题。且，elastic用户的系统配额也的确有设置file descrptor指标。</p>



<p>可是，为什么通过加入到systemd之后，再去启动服务时，抛出错误呢？</p>



<h4 class="wp-block-heading">3 解决问题</h4>



<p>通过分析排查，发现可以在把elasticsearch加入到systemd系统服务时，可以添加参数来实现，如下：</p>



<pre class="wp-block-preformatted">cat &lt;&lt;EOF &gt; /etc/systemd/system/elasticsearch.service<br>[Unit]<br>Description=elasticsearch<br>​<br>[Service]<br>User=elastic<br>ExecStart=/home/elastic/elasticsearch-7.17.1/bin/elasticsearch<br>Restart=always<br>LimitNOFILE=65535<br>​<br>​<br>[Install]<br>WantedBy=multi-user.target<br>EOF</pre>



<p>然后，依次执行下述命令：</p>



<pre class="wp-block-preformatted">systemctl disable elasticsearch.service <br>systemctl daemon-reload <br>systemctl start elasticsearch.service<br>systemctl status elasticsearch.service <br>[root@localhost ~]# netstat -anp|grep 9200<br>tcp6 &nbsp; &nbsp; &nbsp; 0 &nbsp; &nbsp; &nbsp;0 :::9200 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :::* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  LISTEN &nbsp; &nbsp; &nbsp;22472/java &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br>[root@localhost ~]# </pre>



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



<p>关于设置/etc/systemd/system/elasticsearch.service</p>



<p><a href="https://stackoverflow.com/questions/46771233/max-file-descriptors-for-elasticsearch-process-is-too-low">https://stackoverflow.com/questions/46771233/max-file-descriptors-for-elasticsearch-process-is-too-low</a></p>



<p>关于查看elasticsearch日志：</p>



<p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.17/starting-elasticsearch.html#_running_elasticsearch_from_the_command_line">https://www.elastic.co/guide/en/elasticsearch/reference/7.17/starting-elasticsearch.html#_running_elasticsearch_from_the_command_line</a></p>
<p><a href="http://www.knockatdatabase.com/2024/05/13/how-to-add-elasticsearch-to-systemd/">如何把elasticsearch添加到systemd系统服务</a>最先出现在<a href="http://www.knockatdatabase.com">数据库敲门人</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.knockatdatabase.com/2024/05/13/how-to-add-elasticsearch-to-systemd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
