5种Docker日志最佳实践

译者注:微服务和容器很好地结合了,但是它们的结合让日志记录也变成了一个难题。作者在本文描述了一些因素,在设置监控的时候是需要考虑的。以下为译文

在过去的几年中,容器已经成为IT领域的一个重要话题,尤其是在DevOps领域。简单地说,当从一个环境迁移到另一个环境时,容器提供了一种简单且可扩展的方法可以运行软件。

容器是通过在一个包中提供完整的运行环境实现的,其中就包括了应用程序,所有的依赖项,库,其它二进制文件以及运行时所需的配置文件。

与容器紧密结合的是微服务,它代表了开发应用程序的一种更灵活的方式。微服务体系结构将应用程序构建为一组松耦合的服务,这些服务通过处理离散业务功能的API连接起来。微服务主要为应用程序开发提供了一种“分而治之”的方法,而不是一个大型的单一代码库。

Docker在容器的基础架构领域是处于世界领先地位的,它是一个部署容器级软件应用的平台。容器的真正价值在于它们允许团队动态地启动一个完整的运行环境。Docker可以说是让企业采用微服务的最具影响力的平台。

类似于虚拟机通过向来自一个服务器的终端用户提供一个操作系统的多个实例来简化软件开发和测试,容器在应用程序和主机操作系统之间添加了一个额外的抽象层。最大的不同是,容器不需要管理程序,只运行操作系统的一个实例;总的来说,这等同于内存更少,运行时间更快。

与开发任何应用程序一样,日志记录是过程的中心部分,在出现问题时尤其有用。但是,在集装箱化应用程序的世界里,与传统应用程序相比,它是不同的。日志Docker实际上意味着不仅记录应用程序和应用程序
主机操作系统,以及Docker服务。在处理多码应用程序时,有许多日志记录技术和方法可以记住。我们将在下面详细介绍前五种最佳实践。

基于应用程序的日志记录

在基于应用程序的方法中,容器内的应用程序使用日志框架来处理日志记录过程。例如,某个Java应用程序可能会使用Log4j 2来对日志文件格式化,然后发送到远程服务器,并完全绕过Docker环境和操作系统。

虽然基于应用程序的日志记录使开发人员对日志事件有了最大的控制权,但是这种方法也会在应用程序过程中产生大量的消耗。这种方法对于那些工作在传统应用程序环境中的人来说可能是有用的,因为它允许开发人员继续使用应用程序的日志框架(例如Log4j 2)而不需要向主机添加日志功能。

Logging Docker实际上意味着不仅需要记录应用程序和主机操作系统,还包括了Docker服务。

使用数据卷

容器本质上是临时的,这意味着如果容器关闭了,那么容器内的任何文件最终都会丢失。相反,容器必须将日志事件转发到集中式日志记录服务(比如Loggly),或者将日志事件存储在数据卷中。数据卷的定义为“容器内的一个标记目录,该目录用来保存持久或共享的数据”。

使用数据卷来记录事件的好处是,由于它们链接到主机上的一个目录,所以日志数据仍然存在,并且可以与其它容器共享。这种方法的优点是它减少了在容器失败或关闭时丢失数据的可能性。在这里可以找到关于在Ubuntu中设置Docker数据卷的说明。

Docker日志驱动

在Docker中进行日志记录的第三种方法是使用平台的日志驱动程序将日志事件转发给在主机上运行的syslog实例。Docker日志驱动程序直接从容器的stdout和stderr输出里面读取日志事件;这就消除了从日志文件中读取和写入的需要,最终也会稍微改善性能。

然而,使用Docker日志驱动程序也有一些缺点:

  • 它不允许进行日志解析,只允许进行日志转发。

  • Docker日志命令只与日志驱动程序JSON文件一起工作。

  • 当TCP服务器不可访问时,容器就会终止。

这里可以找到为Docker配置默认日志驱动程序的说明。

容器专用日志

这种方法的主要优点是允许在Docker环境中完全地管理日志事件。由于专用的日志容器可以从其他容器收集日志事件,聚合它们,然后将事件存储或转发到第三方服务,这种方法消除了对主机的依赖。

专用日志容器的其它优点是:

  • 自动收集、监视和分析日志事件。

  • 在没有配置的情况下自动缩放日志事件。

  • 通过多个日志事件、stats和Docker API数据流来检索日志。

Sidecar方法

Sidecars已经成为管理微服务架构的流行方法。Sidecar的想法来自于类似摩托车的sidecar是如何附着在摩托车上的。引用一个消息源,“Sidecar作为第二个过程在你的服务旁边运行,并通过类似于HTTP上的REST-like API 这样一个同类接口提供了’平台基础设施’的特性。”

从日志记录的角度来看,Sidecar方法的优点是每个容器都与它自己的日志容器有关(应用程序容器保存日志事件和日志容器标记,然后像Loggly那样将它们转发到日志管理系统)。

未分类

Sidecar方法对于大型部署来说尤其有用,因为这些部署需要有更专门的日志信息和自定义标记。不过,建立Sidecar非常复杂,而且难度也很大。

使用awk来统计访问站点的响应状态码

使用awk来通知nginx的日志来实现对某站点响应状态码的统计

代码:

awk 'BEGIN{
        print "状态码t比例"
    }
    {
        if ($11 ~ /http://blog.longway.pw/) {
            count+=1;
            item[$9]+=1
        }
    }
    END{
        for(i in item) 
            print i,"t",item[i]/count * 100
    }' /usr/local/nginx/logs/access.log | sort -nk2

awk中引用变量的两种方式

结合编辑数据文件的shell脚本学习awk传参方式,该脚本功能:

  • 取VIDEOUSR_11082017_0102_ONLINE_STASTIC.dat文件中第87个字段的低8位;

  • 将每行数据的第3列和第87列对调;

  • 修改后的数据生成到最新时间戳文件中。

1、常规用法

#!/usr/bin/bash

if [[ $# -eq 2 ]];then
  srcfile="$1" #文件名
  bit=$2 #低bit位
  filetimetmp=${srcfile#*_}
  filetime=${filetimetmp%%_*} #截取文件中时间戳,日+月+年
  realtime=`date +"%d%m%Y"` #生成最新时间戳,日+月+年
  let databit="2**$bit" #低bit位对应的值,通过取余截取第低bit位数值
  if [[ -f $srcfile ]];then
    newfile=${srcfile//$filetime/$realtime} #生成最新时间戳对应的文件
    if [[ -f $newfile && $newfilew =~ ".dat" ]];then
       rm -rf $newfile
    fi
       cat $srcfile|sed 's/ /#/'|awk -v mod=$databit -F ',' '{predata=$87%mod;$87=$3;$3=predata;print $0}'|sed 's/ /,/g'|sed 's/#/ /' >>$newfile
       ##其中sed 's/ /#/'和sed 's/#/ /'是对数据中带有空格时间(2017-08-11 17:30:21)做保护(编辑前空格替换为#看,编辑完后#替换为空格)
  fi
fi

调用方式:

sh datatransfomate.sh VIDEOUSR_11082017_0102_ONLINE_STASTIC.dat 8

awk传参:awk -v mod=$databit,之后可以在‘{}’中使用mod变量。

但字段值不能通过变量方式进行修改,即$87和$3如何使用外部变量进行传参。

2、${}变量传参

#!/usr/bin/bash

if [[ $# -eq 4 ]];then
  srcfile="$1" #文件名
  exchghead=$2 #对应第3个字段
  exchgtail=$3 #对应第87个字段
  bit=$4 #低bit位
  filetimetmp=${srcfile#*_}
  filetime=${filetimetmp%%_*} #截取文件中时间戳,日+月+年
  realtime=`date +"%d%m%Y"` #生成最新时间戳,日+月+年
  let databit="2**$bit" #低bit位对应的值,通过取余截取第低bit位数值
  if [[ -f $srcfile ]];then
     newfile=${srcfile//$filetime/$realtime} #生成最新时间戳对应的文件

    if [[ -f $newfile && $newfilew =~ ".dat" ]];then
       rm -rf $newfile
    fi
       cat $srcfile|sed 's/ /#/'|awk -v mod=$databit -F ',' "{predata=$${exchgtail}%mod;$${exchgtail}=$${exchghead};$${exchghead}=predata;print $0}"|sed 's/ /,/g'|sed 's/#/ /' >>$newfile
       ##其中sed 's/ /#/'和sed 's/#/ /'是对数据中带有空格时间(2017-08-11 17:30:21)做保护(编辑前空格替换为#看,编辑完后#替换为空格)
  fi
fi

调用方式:

sh datatransfomate.sh VIDEOUSR_11082017_0102_ONLINE_STASTIC.dat 3 87 8

awk传参:由于使用了“”,shell会对“”中$进行索引替换,因此需要对部分$进行转译。

awk中“”经过shell处理后会转换:

awk -v mod=$databit -F ',' "{predata=$${exchgtail}%mod;$${exchgtail}=$${exchghead};$${exchghead}=predata;print $0}"

                                                    ==》awk -v mod=$databit -F ',' ‘{predata=$87%mod;$87=$3;$3=predata;print $0}’

3、使用总结

  • 常规使用 -v 即可传参,awk -v innerpara=$outerpara -F ‘,’ ‘{print innerpara,$0}’

  • 通过变量方式传参,awk -v -F ‘,’ “{print $${outerpara},$0}” ##注意使用转译符即可

  • 以上两种传参方式可以同时使用

解决apache中403 Forbidden的问题

今天刚编译安装了httpd2.2.34,绑定域名后发现

未分类

检查了目录,也不是权限的问题,检查了N遍httpd.conf才找到是什么问题,默认

<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all  ------就这段
</Directory>

无条件禁止任何访问
想要正常把

Deny from all注释掉或者改成allow from all就可以正常访问了。

如果你的服务器也出现了403错误,不防注意下httpd.conf 配置文件Deny from all

开启Apache的PATHINFO模式以支持ThinkPHP

前言

刚开始运行一个基于Think PHP开发的网站源码时(第一次接触ThinkPHP),在本地访问时一直出现404错误,检查地址也没有错误。后来查了很多资料后才发现,Think PHP的默认URL模式是PATHINFO模式,而我本地的Apache没有开启这个模式(ಥ _ ಥ),所以一直报错。在这里记录一下如何开启Apache的PATHINFO模式。

注释:本地服务器使用的是WAMPServer集成安装环境,安装路径为E:Wamp。

正文

第一步:在Apache安装目录的conf文件夹下的httpd.conf文件116行里找到:

#LoadModule rewrite_module modules/mod_rewrite.so

将前面的#去掉,改为:

LoadModule rewrite_module modules/mod_rewrite.so

注:我的路径是:E:WampwampbinapacheApache2.2.21conf,httpd.conf这个文件在其它目录也有,注意只有改动这个目录的文件才有效。

第二步:还是在该文件里进行修改,在118行找到:

Options FollowSymLinks

AllowOverride None

Order deny,allow

Deny from all

AcceptPathInfo On    //加入这行代码就OK了

之后在本地浏览器可以正常访问,不出现404错误了。

mysqldump导出备份数据库报Table ‘performance_schema.session_variables‘ doesn‘t exist

当你在mysql5.6或者5.7中进行备份数据库的时候可能会出现以下这个错误:

例如输入命令:

mysqldump -u root -p test > test.sql

出现的问题:

mysqldump: Couldn‘t execute ‘SHOW VARIABLES LIKE ‘gtid_mode‘‘: Table ‘performance_schema.session_variables‘ doesn‘t exist (1146)

网上说了好多解决方法,例如:使用“–set-gtid-grupe=off”参数等,试了结果并没什么用。

其实具体的解决方法是:

mysql_upgrade -u root -p –force #更新
service mysql restart #restart mysql service
mysqldump -u root -p test > test.sql #重新备份数据

Mysqldump的导出技巧

Mysqldump 是我们经常要用到的命令,Mysqldump 与Mysql 关于连接信息的参数是一致的。

  • -h 主机地址
  • -u 用户名
  • -P 端口
  • -p 密码

命令格式:

mysqldump -h 主机地址 -P 端口 -u 数据库用户名 -p密码  目标数据库名 表名 --where "" > dump.sql

主要看如何限定要导出的数据集范围:

目标数据库名 > 表名 > 表中某个字段的限定条件

三个限定条件,越往后条件越精确,除数据库名以外后面的两个条件都是可选的。这种参数设计思想值得借鉴。

例句:

mysqldump -p123456 cms content --where "date>'2017-08-30 00:00:00'" > dump.sql

上面的命令表示,导出cms数据库下面的content 表中字段 date 大于 2017-08-30 00:00:00 的数据。

UBUNTU 16.04 APACHE2开启HTTP2支持

UBUNTU 16.04默认源里的APACHE2没有HTTP2模块,如果启用HTTP2模块一般会报错找不到模块.

a2enmod http2
ERROR: Module http2 does not exist!

所以如果要启用HTTP2模块,需要从源码从头编一个APACHE2.不过编译好的HTTP2模块可以直接拷贝出来使用,所以已经安装过APACHE2了也不需要担心.
首先将源码源加入源列表之中:

vi /etc/apt/sources.list

添加以下:

deb-src http://archive.ubuntu.com/ubuntu/ xenial main universe restricted multiverse
deb-src http://security.ubuntu.com/ubuntu xenial-security main universe restricted multiverse
deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates main universe restricted multiverse

然后刷新源,如果有需要更新的包,顺便升下级:

apt update
apt upgrade

然后安装依赖:

apt install curl devscripts build-essential fakeroot libnghttp2-dev

创建一个工作的编译目录:

cd ~
mkdir apache2
cd apache2

从源里下载APACHE2的源码然后编译:

apt source apache2
apt build-dep apache2
cd apache2-2.4.18
apt install curl devscripts build-essential fakeroot
fakeroot debian/rules binary

将编译的好的HTTP2模块拷贝到APACHE2模块目录中:

cp debian/apache2-bin/usr/lib/apache2/modules/mod_http2.so /usr/lib/apache2/modules/

然后为HTTP2模块编写一个配置文件:

vim /etc/apache2/mods-available/http2.load

在其中写入以下:

LoadModule http2_module /usr/lib/apache2/modules/mod_http2.so

<IfModule http2_module>  
LogLevel http2:info  
</IfModule>

最后启用HTTP2模块:

service apache2 restart
a2enmod http2
service apache2 restart

编辑网站配置文件,加入HTTP2协议:

vim /etc/apache2/sites-enabled/default-ssl.conf

在默认配置文件的SERVERNAME下添加一行:

Protocols h2 http/1.1

如果没有默认配置文件,可参考以下配置文件:

<IfModule mod_ssl.c>  
 <VirtualHost _default_:443>
 ServerAdmin webmaster@localhost
 ServerName your-domain.com
 Protocols h2 http/1.1
 DocumentRoot /var/www/html

 ErrorLog ${APACHE_LOG_DIR}/error.log
 CustomLog ${APACHE_LOG_DIR}/access.log combined

 SSLEngine on

 SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
 SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

 <FilesMatch ".(cgi|shtml|phtml|php)$">
 SSLOptions +StdEnvVars
 </FilesMatch>
 <Directory /usr/lib/cgi-bin>
 SSLOptions +StdEnvVars
 </Directory>

 </VirtualHost>
</IfModule>

然后还需要将HTTP2协议加入APACHE2配置文件中:

vim /etc/apache2/apache2.conf

加入以下行:

Protocols h2 http/1.1

最后重启APACHE2

service apache2 restart

python flask-sqlalchemy如何设置使自动建的mysql表字符集charset为utf8

问题

发现flask-sqlalchemy自动创建的mysql表为默认的latin1,如何不更改mysql服务器的默认字符集,直接在flask里配置自动建的mysql表字符集为utf8?

最佳答案

配置table_args就可以了,如:

class Foo(Base):
    __tablename__ = "foo"
    __table_args__ = {'mysql_collate': 'utf8_general_ci'}

    ...

    column = db.Column(db.String(500))

MySQL InnoDB Cluster环境搭建和简单测试

InnoDB Cluster初印象

记得MySQL Group Replicatioin 刚开始的时候,MySQL界很是轰动,等待了多年,终于有了官方的这个高可用解决方案。你要说还有一些方案补充,比如MySQL Cluster,MySQL Proxy,这些的使用率个人感觉还是不高,也就是经受的考验还不够,原因有很多,就不赘述了。

不久,我和一个MySQL DBA有了下面的一个基本对话。

我: MySQL GR GA之后,里面的自动切换功能确实很赞,能够做到读写分离,原本MHA的方案现在MGR也可以做了。

MySQL DBA:如果数据库发生了故障,这个自动切换的过程,其实对于应用不是透明的,因为读写节点相当于漂移到了另外一台服务器上,除非再做个中间件。

我:单纯MGR目前还做不了这个,它目前只是保证数据库层面的这种切换和高可用。

MySQL DBA:所以说MGR的企业级应用还是需要一些辅助,这样才算是一个完整的解决方案。

不久,MySQL InnoDB Cluster推出,我觉得这个方案想比原来的MGR更进一步,说实话,我很看好这个方案,尽管目前愿意真正去用的用户确实不多。

如果你看一下官方的这个架构图,就会发现,MGR本身就是Innodb Cluster的一部分,还有两个组件,MySQL Shell,MySQL Router,这三板斧就是InnoDB Cluster的一个核心组件,而正如我之前所说,可以看到MySQL的一个格局和定位,他正在很努力去解决以前诟病的问题。

未分类

安装前先保证Python满足要求

要安装InnoDB Cluster,环境的一个基本要求就是Python,我看了下,很多默认的系统版本是2.6,而它的最低要求是2.7及以上,所以还是需要提前准备下这个部分。

如果你的系统是Python 2.6版本的,可以考虑升级到2.7,参考如下的方法。

下载安装包,部署

wget http://python.org/ftp/python/2.7/Python-2.7.tar.bz2     --no-check-certificate
./configure
make all
make install
make clean
make distclean

查看Python的版本

# /usr/local/bin/python2.7 -V
Python 2.7

做基本的环境设置,替换旧的Python

mv /usr/bin/python /usr/bin/python2.6
ln -s /usr/local/bin/python2.7 /usr/bin/python

sandbox安装部署InnoDB Cluster

搭建InnoDB Cluster显而易见需要多台服务器,而如果在一台服务器上练习测试,也是全然没有问题,如果想更快更方便的测试模拟,还可以使用sandbox来做,首先你得有sandbox,接着InnoDB Cluster的三大组件是MGR,MySQL Shell,MySQL Router,所以你可以从官网直接下载下来。

然后我们开启安装之旅。

使用MySQL Shell的命令mysqlsh开始部署,创建一个端口为3310的实例

mysql-js> dba.deploySandboxInstance(3310)
A new MySQL sandbox instance will be created on this host in
/root/mysql-sandboxes/3310

输入密码之后,一个3310端口的MySQL服务就启动了。

Please enter a MySQL root password for the new instance:
Deploying new MySQL instance...
Instance localhost:3310 successfully deployed and started.
Use shell.connect('root@localhost:3310'); to connect to the instance.

接着创建另外两个节点 3320,3330

dba.deploySandboxInstance(3320)
dba.deploySandboxInstance(3330)

我们切换到3310的MySQL实例,准备开始创建Cluster

mysql-js>  connect root@localhost:3310
Creating a Session to 'root@localhost:3310'
Enter password:
Closing old connection...
Classic Session successfully established. No default schema selected.

定义一个Cluster变量,节点1就开启了Cluster创建之旅,可以从下面的信息看出,至少需要3个节点

mysql-js>  var cluster = dba.createCluster('testCluster')
A new InnoDB cluster will be created on instance 'root@localhost:3310'.
Creating InnoDB cluster 'testCluster' on 'root@localhost:3310'...
Adding Seed Instance...
Cluster successfully created. Use Cluster.addInstance() to add MySQL instances.
At least 3 instances are needed for the cluster to be able to withstand up to  one server failure.

接着把另外两个节点加入进来,先加入端口为3320的节点

mysql-js> cluster.addInstance('root@localhost:3320')
A new instance will be added to the InnoDB cluster. Depending on the amount of
data on the cluster this might take from a few seconds to several hours.
Please provide the password for 'root@localhost:3320':
Adding instance to the cluster ...加入端口为3330的节点,日志和节点2相似。

mysql-js> cluster.addInstance('root@localhost:3330')

这个时候Cluster就创建好了。

这个时候,我们再配置一下MySQL Router,创建个软链接,保证能够正常调用。

# ln -s /home/innodb_cluster/mysql-router-2.1.3-linux-glibc2.12-x86-64bit/bin/mysqlrouter   /usr/bin/mysqlroute
# which mysqlroute
/usr/bin/mysqlroute

配置MySQL Router的启动节点为端口3310的实例

# mysqlrouter –bootstrap root@localhost:3310 –user=mysql

这个时候还是要输入密码,成功之后,这个绑定就打通了。

Please enter MySQL password for root:
Bootstrapping system MySQL Router instance...
MySQL Router  has now been configured for the InnoDB cluster 'testCluster'.
The following connection information can be used to connect to the cluster.
Classic MySQL protocol connections to cluster 'testCluster':
- Read/Write Connections: localhost:6446
- Read/Only Connections: localhost:6447
X protocol connections to cluster 'testCluster':
- Read/Write Connections: localhost:64460
- Read/Only Connections: localhost:64470

可以从上面的日志看出来,分配的读写端口是6446,只读端口是6447,还有x协议连接的端口为64460,64470

启动MySQL Router

# mysqlrouter &
[1] 2913

如果对MySQL Router还有些疑问,可以看看安装目录下,会生成下面的配置文件,我们就看里面的.conf文件,里面的一部分内容如下:

[routing:testCluster_default_rw]
bind_address=0.0.0.0
bind_port=6446
destinations=metadata-cache://testCluster/default?role=PRIMARY
mode=read-write
protocol=classic

验证测试

我们尝试使用6446来连接登录,这个时候就通过MySQL Shell开启了连接入口,MySQL Router做了转接,连接到了里面的读写节点3310

# mysqlsh --uri root@localhost:6446
Creating a Session to 'root@localhost:6446'
Enter password:
Classic Session successfully established. No default schema selected.
Welcome to MySQL Shell 1.0.9

切换到sql模式,查看端口就知道是哪个节点了。

mysql-js> sql
Switching to SQL mode... Commands end with ;
mysql-sql> select @@port;
+--------+
| @@port |
+--------+
|   3310 |
+--------+
1 row in set (0.00 sec)

如果切换为脚本模式查看实例的状态,可以使用里面定义的API来做,输出都是JSON串。

mysql-js> dba.configureLocalInstance('[email protected]:3310')
Please provide the password for '[email protected]:3310':
Detected as sandbox instance.
Validating MySQL configuration file at: /root/mysql-sandboxes/3310/my.cnf
Validating instance...
The instance '127.0.0.1:3310' is valid for Cluster usage
You can now use it in an InnoDB Cluster.
{
"status": "ok"
}如果查看Cluster的信息,可以看到下面的读写节点,只读节点的状态信息

mysql-js> dba.getCluster()
<Cluster:testCluster>

得到Cluster的信息

var cluster = dba.getCluster()
mysql-js> cluster.status()
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "localhost:3310",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"localhost:3310": {
"address": "localhost:3310",
"mode": "R/W",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
},
"localhost:3320": {
"address": "localhost:3320",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
},
"localhost:3330": {
"address": "localhost:3330",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
}
}
}
}

也可以使用describe得到一些基本的信息

mysql-js> cluster.describe();
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"instances": [
{
"host": "localhost:3310",
"label": "localhost:3310",
"role": "HA"
},
{
"host": "localhost:3320",
"label": "localhost:3320",
"role": "HA"
},
{
"host": "localhost:3330",
"label": "localhost:3330",
"role": "HA"
}
],
"name": "default"
}
}

切换测试

当然光看不练还是假把式,我们切换一下,看看好使不?

模拟一个节点出现问题,可以使用killSandboxInstance方法。

mysql-js> dba.killSandboxInstance(3310)
The MySQL sandbox instance on this host in
/root/mysql-sandboxes/3310 will be killed
Killing MySQL instance...
Instance localhost:3310 successfully killed.

节点被清理了,没有任何进程存在。

# ps -ef|grep mysql|grep 3310
#

我们还是使用6446的端口来统一连接,这个时候就切换到了端口3320的MySQL服务

# mysqlsh --uri root@localhost:6446
mysql-js> sql
Switching to SQL mode... Commands end with ;
mysql-sql> select @@port;
+--------+
| @@port |
+--------+
|   3320 |
+--------+
1 row in set (0.00 sec)

所以切换的部分没有问题,我们再次把“迷失”的节点启动起来。

# mysqlsh --uri root@localhost:6446
mysql-js> dba.startSandboxInstance(3310)
The MySQL sandbox instance on this host in
/root/mysql-sandboxes/3310 will be started
Starting MySQL instance...
Instance localhost:3310 successfully started.

这个时候再次查看Cluster的状态,3320就是主了,3310就是只读节点了。

mysql-js> dba.getCluster()
<Cluster:testCluster>

把节点2纳入到Cluster中

mysql-js> cluster.rejoinInstance('root@localhost:3310')
Rejoining the instance to the InnoDB cluster. Depending on the original
problem that made the instance unavailable, the rejoin operation might not be
successful and further manual steps will be needed to fix the underlying
problem.
Please monitor the output of the rejoin operation and take necessary action if
the instance cannot rejoin.
Please provide the password for 'root@localhost:3310':
Rejoining instance to the cluster ...
The instance 'root@localhost:3310' was successfully rejoined on the cluster.
The instance 'localhost:3310' was successfully added to the MySQL Cluster.
mysql-js>

可以想象如果是一个生产系统,这么多的日志,这个过程真是让人纠结。
最后来一个切换后的Cluster状态

mysql-js> cluster.status()
{
"clusterName": "testCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "localhost:3320",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"localhost:3310": {
"address": "localhost:3310",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
},
"localhost:3320": {
"address": "localhost:3320",
"mode": "R/W",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
},
"localhost:3330": {
"address": "localhost:3330",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
}
}
}
}