All Secondary die, Primary hang? – SQL Server 2017 on Linux

关于AVAILABILITY_MODE

需要注意的是,与Oracle Data Guard不尽相同的概念是,在Always On AG中每个replica上都可以设置自己的AVAILABILITY_MODE。
AVAILABILITY_MODE参数有三个可选值,分别是SYNCHRONOUS_COMMIT、ASYNCHRONOUS_COMMIT和CONFIGURATION_ONLY。

  • SYNCHRONOUS_COMMIT:同步提交,意味着主replica的事务必须等到备replica将变更日志写入磁盘中才可以提交。可以设置包括主replica在内的最多三个replica处于同步提交状态。
  • ASYNCHRONOUS_COMMIT:异步提交,意味着replica无需等待备replica的动作而可以直接提交成功。
  • CONFIGURATION_ONLY:仅同步AG配置元数据。设置为该值的replica仅会从主replica中将AF配置的元数据同步过来,不会同步任何用户表数据。

在一个多节点replica的AG环境中,如果:

  • 主库和其中任何一个备库设置为SYNCHRONOUS_COMMIT,则主库的日志提交必须等待该备库完成日志写入;
  • 主库设置为SYNCHRONOUS_COMMIT,而所有备库都设置为ASYNCHRONOUS_COMMIT,则主库无需等待;
  • 主库设置为ASYNCHRONOUS_COMMIT,则无视备库上该参数的设置,主库均无需等待。

在多节点的AG环境中,假设一个主库配置了两个同步的secondary,那么是不是要等待这两个secondary都完成日志写入才能提交事务呢?此时又引入了required_synchronized_secondaries_to_commit参数。

关于required_synchronized_secondaries_to_commit

required_synchronized_secondaries_to_commit参数是在SQL Server 2017中引入的,这个参数从直观意义上就可以看得出是指定当commit的时候需要有个几个同步的secondary replica存活。

这个参数在三节点的AG集群中,默认值为1,也就是如果至少要存活一个secondary replica,主库上的事务才可以提交,否则commit就会一直等待。这很好理解。
但是不好理解的是,该参数可以手工修改为0,从字面上看应该是说,即使所有secondary replica都不同步了,也是可以允许commit的。

但是实际情况却并非如此,修改为0是不起作用的。通过以下测试可以知道。

首先,设置required_synchronized_secondaries_to_commit参数为0

sudo pcs resource update ag_cluster required_synchronized_secondaries_to_commit=0
[Kamus@centos1 ~]$ sql
1> select name,required_synchronized_secondaries_to_commit from sys.availability_groups;
2> GO
name required_synchronized_secondaries_to_commit
------------------------------ -------------------------------------------
ag1                            0
(1 rows affected)

现在三个节点都是正常状态。

1> select r.replica_server_name,r.availability_mode_desc,r.session_timeout ,rs.connected_state_desc
2> from sys.availability_replicas r,sys.dm_hadr_availability_replica_states rs
3> where r.replica_id=rs.replica_id;
4> GO
replica_server_name            availability_mode_desc         session_timeout connected_state_desc
------------------------------ ------------------------------ --------------- ------------------------------
centos1                        SYNCHRONOUS_COMMIT             10 CONNECTED
centos2                        SYNCHRONOUS_COMMIT             10 CONNECTED
centos3                        SYNCHRONOUS_COMMIT             10 CONNECTED
(3 rows affected)

在主节点上进行Insert,可以成功,这很好。

1> insert into t1 select * from sys.databases;
2> GO
(6 rows affected)

停掉一个secodary replica。显示第二个节点已经DISCONNECTED。

1> select r.replica_server_name,r.availability_mode_desc,r.session_timeout ,rs.connected_state_desc
2> from sys.availability_replicas r,sys.dm_hadr_availability_replica_states rs
3> where r.replica_id=rs.replica_id;
4> GO
replica_server_name availability_mode_desc session_timeout connected_state_desc
------------------------------ ------------------------------ --------------- ------------------------------
centos1 SYNCHRONOUS_COMMIT 10 CONNECTED
centos2 SYNCHRONOUS_COMMIT 10 DISCONNECTED
centos3 SYNCHRONOUS_COMMIT 10 CONNECTED
(3 rows affected)

在主库上进行Insert,还是可以成功,这很好。

1> insert into t1 select * from sys.databases;
2> GO
(6 rows affected)

再停掉一个secodary replica。显示2、3节点都已经DISCONNECTED。

1> select r.replica_server_name,r.availability_mode_desc,r.session_timeout ,rs.connected_state_desc
2> from sys.availability_replicas r,sys.dm_hadr_availability_replica_states rs
3> where r.replica_id=rs.replica_id;
4> GO
replica_server_name availability_mode_desc session_timeout connected_state_desc
------------------------------ ------------------------------ --------------- ------------------------------
centos1 SYNCHRONOUS_COMMIT 10 CONNECTED
centos2 SYNCHRONOUS_COMMIT 10 DISCONNECTED
centos3 SYNCHRONOUS_COMMIT 10 DISCONNECTED
(3 rows affected)

在主库上执行Insert,此时hang住,这很不好。

1> insert into t1 select * from sys.databases;
2> GO

更讨厌的是,对于该表的查询也会hang住,这就更不好了。

2> select count(*) from t1;
3> GO

现在数据库中的等待是什么呢?确实是HADR_SYNC_COMMIT。

1> select STATUS,COMMAND,DATABASE_ID,WAIT_TYPE,WAIT_TIME from sys.dm_exec_requests where command='INSERT';
2> GO
STATUS COMMAND DATABASE_ID WAIT_TYPE WAIT_TIME
------------------------------ ------------------------------ ----------- ------------------------------ -----------
suspended INSERT 5 HADR_SYNC_COMMIT 1670
(1 rows affected)

如果我们更进一步做一个session的xevent trace,可以看到等待的是WaitForHarden,而Harden的意思即是remote replica的日志写入。现在主库在等待一个备库的日志完成写入,然后自己才能提交成功。在正常情况下,当主库不再需要等待备库而可以自行commit的情况下,在xevent trace中应该出现将备库的commit_policy标志为donothing状态,也就是在xevent中应该要出现hadr_db_partner_set_policy事件才是正常的,然而这里并没有出现。

但是我们明明把required_synchronized_secondaries_to_commit参数设置为0了,这很违反常识,不是吗?

结论

在SQL on Linux中如果设置了availability_mode为SYNCHRONOUS_COMMIT,那么必须至少有一个secondary replica(或者一个config node)是存活的,否则priamry replica中就不再允许任DML操作,而尝试对于某表进行DML之后,还会进一步阻塞对于该表的查询。即使设置了required_synchronized_secondaries_to_commit=0也是无效的。也许微软需要更新一下文档,明确说明在多个sync的secondary存在的情况下,该参数即使修改为0也仍然按照1来处理。
这是一个很奇怪的design,因为这强制去掉了当一个集群中所有备库都崩溃时,主库能够自动转为异步提交模式的功能,从而造成了所有备库失效则会影响主库业务正常进行这样一个大问题。
实际上这个design是在SQL on Linux 2017 CU1之后才修改的,在CU1之前还是允许当所有备库都失效以后,主库仍然是可以正常读写的。甚至在现在的文档中仍然保留了这样的描述。


以上文档描述来自:High availability and data protection for availability group configurations

这意味着在SQL Server 2017 CU 1之后,不再支持单纯的read-scale功能的AG了。虽然不太理解微软的SQL Server程序员是怎么考虑这个问题的,但是现状就是如此。

相比起Oracle的Data Guard而言,也就是现在SQL Server的AG只有同步(等同于DG的Maximum protection),异步(等同于DG的Maximum performance)这样两种方式,而缺少了DG的Maximum availability模式。
我只能认为这是一个设计理念的问题,微软的程序员更倾向于关注数据一致性,但是我期望在未来SQL Server可以对此进行改进。

Configuring Always On Availability Groups in SQL Server 2017 on Linux

在之前的预览版中,Public preview of the next release of SQL Server on Linux,Always On Availability Groups还是不支持的功能,但是在最新的SQL Server 2017 on Linux中,该功能已经引入。

准备测试环境的服务器

在Always On AG中如果需要自动Failover至少需要集群中有3台服务器,但是我只是测试功能,因此只使用了两台服务器。并且本文不涉及任何Pacemaker的设置,完全是数据库层面的AG配置。 我使用的是Google Compute Engine的2台VM,最低配的1vCPU,3.75GB内存。 如果要通过远程客户端配置SQL Server,则需要在VPC network的Firewall rules中将1433端口开放,如果是在虚拟机本地的sqlcmd中操作,则无需配置。 操作系统:CentOS7

$ cat /etc/centos-release CentOS Linux release 7.4.1708 (Core) 

在/etc/hosts中配置双方服务器的名称和IP地址的解析,以保证两台机器可以通过服务器名称互相访问。 重要!服务器主机的hostname必须少于等于15个字符,否则在配置过程会出现各种莫名其妙的权限报错。

安装SQL Server

SQL Server for Linux的安装非常简单,可以参考我之前的这篇文章。 Public preview of the next release of SQL Server on Linux

启用AlwaysOn AG功能

执行范围:在所有机器上执行 安装完的SQL Server,默认是没有启用AlwaysOn AG功能的,需要手工开启,开启的方法很简单。开启该功能需要重启数据库实例。

sudo /opt/mssql/bin/mssql-conf set hadr.hadrenabled 1 sudo systemctl restart mssql-server 

启用AlwaysOn_health事件

执行范围:在所有机器上执行 这一步不是必须的。

ALTER EVENT SESSION AlwaysOn_health ON SERVER WITH (STARTUP_STATE=ON); 

创建数据库复制的用户

执行范围:在所有机器上执行

CREATE LOGIN dbm_login WITH PASSWORD = ‘YourPassword’; CREATE USER dbm_user FOR LOGIN dbm_login; 

创建认证

执行范围:在Primary Replica机器上执行

CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'YourPassword'; CREATE CERTIFICATE dbm_certificate WITH SUBJECT = 'dbm'; BACKUP CERTIFICATE dbm_certificate TO FILE = '/var/opt/mssql/data/dbm_certificate.cer' WITH PRIVATE KEY ( FILE = '/var/opt/mssql/data/dbm_certificate.pvk', ENCRYPTION BY PASSWORD = 'YourPassword' ); 

将生成的dbm_certificate.cer和dbm_certificate.pvk文件scp到另外一台服务器的相同位置并修改属主,这台服务器就是Secondary Replica。

cd /var/opt/mssql/data chown mssql:mssql dbm_certificate.* 

然后在这台服务器上导入认证。 执行范围:在Secondary Replica机器上执行

CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'YourPassword'; CREATE CERTIFICATE dbm_certificate AUTHORIZATION dbm_user FROM FILE = '/var/opt/mssql/data/dbm_certificate.cer' WITH PRIVATE KEY ( FILE = '/var/opt/mssql/data/dbm_certificate.pvk', DECRYPTION BY PASSWORD = 'YourPassword' ); 

创建数据库复制的Endpoint

执行范围:在所有机器上执行

CREATE ENDPOINT [Hadr_endpoint] AS TCP (LISTENER_PORT = 5022) FOR DATA_MIRRORING ( ROLE = ALL, AUTHENTICATION = CERTIFICATE dbm_certificate, ENCRYPTION = REQUIRED ALGORITHM AES ); ALTER ENDPOINT [Hadr_endpoint] STATE = STARTED; use master GRANT CONNECT ON ENDPOINT::[Hadr_endpoint] TO [dbm_login]; 

创建Availability Groups

执行范围:在Primary Replica机器上执行

CREATE AVAILABILITY GROUP [ag1] WITH (CLUSTER_TYPE = EXTERNAL) FOR REPLICA ON N'centos1' WITH ( ENDPOINT_URL = N'tcp://centos1:5022', AVAILABILITY_MODE = SYNCHRONOUS_COMMIT, FAILOVER_MODE = EXTERNAL, SEEDING_MODE = AUTOMATIC ), N'centos2' WITH ( ENDPOINT_URL = N'tcp://centos2:5022', AVAILABILITY_MODE = SYNCHRONOUS_COMMIT, FAILOVER_MODE = EXTERNAL, SEEDING_MODE = AUTOMATIC ); ALTER AVAILABILITY GROUP [ag1] GRANT CREATE ANY DATABASE; 

在主库上创建了AG之后,备库需要加入AG。 执行范围:在Secondary Replica机器上执行

ALTER AVAILABILITY GROUP [ag1] JOIN WITH (CLUSTER_TYPE = EXTERNAL); ALTER AVAILABILITY GROUP [ag1] GRANT CREATE ANY DATABASE; 

将数据库加入AG

这里新建一个数据库db1,将它加入到ag1中。由于上面设置的SEEDING_MODE参数为AUTOMATIC,因此这个db1数据库将会在备库实例中自动创建,后续对于该库进行的任何操作也会自动复制到备库中。 执行范围:在Primary Replica机器上执行

CREATE DATABASE [db1]; ALTER DATABASE [db1] SET RECOVERY FULL; BACKUP DATABASE [db1] TO DISK = N'/var/opt/mssql/data/db1.bak'; ALTER AVAILABILITY GROUP [ag1] ADD DATABASE [db1]; 

允许Secondary Replica可以被只读访问

在以上的创建过程中创建出来的AG中的备库是不允许被访问的,如果要访问将会遇到以下错误。 The target database, ‘db1’, is participating in an availability group and is currently not accessible for queries. Either data movement is suspended or the availability replica is not enabled for read access. To allow read-only access to this and other databases in the availability group, enable read access to one or more secondary availability replicas in the group. For more information, see the ALTER AVAILABILITY GROUP statement in SQL Server Books Online. 执行范围:在Primary Replica机器上执行,立刻生效。

use master ALTER AVAILABILITY GROUP ag1 MODIFY REPLICA ON N'centos2' WITH ( SECONDARY_ROLE (ALLOW_CONNECTIONS = ALL ) ); 

测试

在主库中随便创建一张新表,再插入几条记录。

1> use db1 2> select * into t_test from sys.databases; 3> insert into t_test select * from t_test; 4> GO Changed database context to 'db1'. (5 rows affected) (5 rows affected) 

在备库中查询,这张表已经复制成功。

1> use db1 2> select count(*) from t_test; 3> GO Changed database context to 'db1'. ------- 10 (1 rows affected) 

如果在备库中尝试更新数据,将会遇到以下错误。

1> delete from t_test; 2> GO Msg 3906, Level 16, State 2, Server centos2, Line 1 Failed to update database "db1" because the database is read-only. 

监控AG状态

通过以下这些视图可以监控AG中各个部分的状态。 group的监控

select * from sys.availability_groups; select * from sys.availability_groups_cluster; select * from sys.dm_hadr_availability_group_states; 

replica的监控

select * from sys.availability_replicas; select * from sys.dm_hadr_availability_replica_states; select * from sys.dm_hadr_availability_replica_cluster_nodes; select * from sys.dm_hadr_availability_replica_cluster_states; 

在AG中的database的监控

select * from sys.availability_databases_cluster; select * from sys.dm_hadr_database_replica_states; select * from sys.dm_hadr_database_replica_cluster_states; select name,database_id,replica_id,group_database_id from sys.databases; 

参考文档

本文配置步骤的参考文档为: https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-availability-group-configure-ha?view=sql-server-linux-2017

Oracle 18c New Features documentation released

为什么从Oracle 12c直接跳到Oracle 18c

这是很多人还在疑惑的问题。实际上Oracle 18c相当于Oracle 12c Release 2的初始版本12.2.0.1的升级版本12.2.0.2。之所以改名为18c,是因为Oracle修改了版本发布计划,将之前每隔2年发布一个新版本的方式修改为每隔1年发布一个版本,因此18c可以认为是2018年的Oracle数据库版本,之后应该会持续用19,20这样的版本号来发布。

Oracle 12c Release 2有什么新功能

在谈Oracle 18c新功能之前,先回顾一下Oracle 12cR2的新功能。除了增强在12cR1版本中引入的多租户(Multitenant)以及混合列式缓存(Database In-Memory)之外,崭新的功能是Oracle Database Sharding,这是专门为超大事务量应用提供的具备高扩展和高可用性的数据库分片功能。

实际上Oracle 12cR2引入了超过600项新功能,详细信息可以参看官方文档:New Features guide for Oracle Database 12c Release 2

Oracle Database 18c的官方文档在哪里

官方已经释出Oracle Database 18c的系列文档。建议大家从New Features开始阅读,本文后续部分的18c新功能解读也都基于该官方文档。

更多的Oracle Database 18c技术文章

在我们的blog.enmotech.com网站中已经有大量的关于Oracle 18c新特性的介绍文章,并且在18c官方文档放出以后,我们也会持续更新更多的技术细节文章,欢迎大家阅读。Oracle 18c New Features Articles by Enmotech.com

Moving MySQL Group Replication instances to Docker container on macOS

前提条件,已经在自己的macOS操作系统中设置成功了都运行在本地的3节点MySQL Group Replication集群,如何设置,可以参考官方文档中的Deploying Group Replication in Single-Primary Mode。 假设在我们的macOS上已经实现了如下了架构的3节点MGR集群,我们的目标是将这三个数据库全部挪到docker容器中去运行,并且可以互相通信,仍然是MGR集群。

Docker on macOS

接下来我们把MySQL放在一边,先介绍一下在macOS中的docker架构,在macOS中,docker的实现跟在其它Linux系统中略有不同,在其它Linux系统中,操作系统本身就是docker容器的宿主机,docker镜像都是直接存储在宿主机本身的文件系统中,比如我们通过docker info命令可以看到docker的根目录是:

$ docker info|grep "Docker Root Dir" Docker Root Dir: /var/lib/docker 

但是在macOS下,我们直接查看这个目录,其实是根本不存在的。

$ ls /var/lib/docker ls: /var/lib/docker: No such file or directory 

Docker宿主机是谁

那么这个目录到底在哪里?实际上是在一个QEMU虚拟机中,当我们在macOS中安装完docker并启动,就是启动了一个虚拟机,这个虚拟机的整个内容全部都在一个文件里,可以在docker程序属性界面中看到这个文件的路径,比如在我的机器上,路径就是/Users/Kamus/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/Docker.qcow2,该文件通常比较大,特别是安装了多个docker镜像之后,会轻易占用到数十GB的空间。 如上图所示,就是Disk image location的位置。 从上图中同样可以看到,这个虚拟机被限制只能使用2颗CPU和2GB内存。 那么,我们是否可以登录这个虚拟机来确认这点呢?使用macOS自带的screen命令可以登录该台虚拟机。如下,可以看到这是一个拥有非常新的Linux 4.9.38版本内核的虚拟机,在这个虚拟机中才有/var/lib/docker目录,只有2颗CPU,总共有2GB内存。

$ screen /Users/Kamus/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
/ # uname -a 
Linux moby 4.9.38-moby #1 SMP Wed Jul 26 10:02:46 UTC 2017 x86_64 Linux 
/ # hostname 
moby
/ # ls /var/lib/docker 
aufs containers network swarm tmp-old volumes builder image plugins tmp trust
/ # cat /proc/cpuinfo|grep "processor" 
processor : 0 processor : 1 
/ # cat /proc/meminfo |grep "MemTotal" 
MemTotal: 2047040 kB 

在screen的窗口按组合键control+a d(先按control+a,再按d)可以暂时dettach出这个screen,screen -r可以重新打开窗口。更多的screen命令,可以自行man screen来查看。 所以现在我们可以明确一个概念,macOS本身并不是以后将运行的docker容器的宿主机,而这个Linux虚拟机才是真正的宿主机。这台机器的主机名是moby,这正是docker项目社区版的名称。

Docker宿主机与macOS操作系统的目录共享

由于如下共享文件夹功能的存在,在这个虚拟机中可以访问并更新macOS操作系统本地的目录,这在后面我们将运行在本地的MySQL数据库搬迁到docker容器中起了重要的作用。 我们还是在screen中看一下这些共享目录的情况。


/ # df -h|grep osxfs 
osxfs 465.1G 324.1G 140.7G 70% private 
osxfs 465.1G 324.1G 140.7G 70% /tmp 
osxfs 465.1G 324.1G 140.7G 70% /Volumes 
osxfs 465.1G 324.1G 140.7G 70% /Users 
/ # cd /Users 
/Users # ls 
Guest Kamus Shared 

可以看到,确实macOS操作系统中的目录在虚拟机中是可以直接访问的,而且更方便的地方是,在虚拟机中自动挂载的目录路径跟macOS中的路径是完全相同的,比如我的个人主目录无论是在macOS中还是在这个虚拟机中,都是/Users/Kamus。 那现在我们的思路基本上有了,就是要将原本运行在macOS操作系统中的MySQL数据库的数据文件和配置文件挪到Docker宿主机可以访问的目录下,然后在docker容器中启动MySQL实例。

安装MySQL docker镜像

先要将MySQL docker镜像安装上,这是运行MySQL docker容器的基础。安装镜像极其简单,只需要一步就可以,以下命令在macOS操作系统中执行。 标准步骤是:

$ docker pull mysql 

但是由于这样会安装latest版本,而我原先在macOS中的MySQL数据库是5.7.17版本,为了避免可能产生的版本升级问题,我做了指定版本的镜像拉取。

$ docker pull mysql:5.7.17 

从官方的docker store中拉取MySQL镜像,大约只需要几分钟时间,完毕以后,可以通过docker images命令来查看。

$ docker images 
REPOSITORY TAG IMAGE ID CREATED SIZE 
mysql 5.7.17 9546ca122d3a 4 months ago 407MB 
store/oracle/database-enterprise 12.1.0.2 f5ffadfccb74 5 months ago 5.27GB 
alpine latest 13e1761bf172 15 months ago 4.8MB 
hello-world latest 94df4f0ce8a4 15 months ago 967B 

第一行就是最新拉取的MySQL镜像,这是创建者在4个月前创建的。

运行MySQL docker容器前的准备

设计docker宿主机目录结构

现在我们已经有了docker镜像,也有了在macOS操作系统中运行良好的MySQL MGR集群,开始迁移。首先当然是干净地关闭在macOS操作系统中的三台MySQL数据库,然后我们设计如下的目录结构,将三个数据库的数据文件全部分别挪进去。

$ mkdir /Users/Kamus/mysql_data 
$ mkdir /Users/Kamus/mysql_data/s1-docker 
$ mkdir /Users/Kamus/mysql_data/s2-docker 
$ mkdir /Users/Kamus/mysql_data/s3-docker 

根据之前阐述的共享文件夹功能,可以知道在docker宿主机中是可以通过完全相同的路径访问到这几个目录的,我们将原本在macOS操作系统中的三个数据库的数据文件分别移动到s1-docker,s2-docker,s3-docker目录中,至于哪些文件需要移动,这是MySQL DBA的基本知识,不在这里赘述。 由于目标是能运行MGR集群,那么是有一部分数据库初始化参数要额外设置的,而docker容器中的my.cnf内容无法改动,所以我们再设计一个专门的目录用来存储所有数据库的my.cnf文件。

$ mkdir /Users/Kamus/mysql_data/conf.d 
$ mkdir /Users/Kamus/mysql_data/conf.d/s1-docker 
$ mkdir /Users/Kamus/mysql_data/conf.d/s2-docker 
$ mkdir /Users/Kamus/mysql_data/conf.d/s3-docker 

然后将原本各个数据库的my.cnf文件分别拷贝到conf.d/s1-docker等三个目录下,最后形成了如下的目录结构。

$ tree /Users/Kamus/mysql_data/conf.d
/Users/Kamus/mysql_data/conf.d
├── s1-docker
│   └── my.cnf
├── s2-docker
│   └── my.cnf
└── s3-docker
    └── my.cnf 

3 directories, 3 files 

设计这些目录结构的目的是在运行docker容器的时候通过volume选项将数据文件目录挂载成容器内部的/var/lib/mysql目录,将my.cnf参数文件所在目录挂载成容器内部的/etc/mysql/conf.d目录,从而实现MySQL数据库实例启动所需要的所有关键文件都存储在宿主机中,而docker容器本身只提供MySQL软件镜像。这比将所有文件都存储在docker镜像内部更灵活。

设计docker容器主机名和IP地址

在macOS本机运行的MySQL实例中为MGR配置的各种参数中使用到的主机名往往是localhost,IP地址则是127.0.0.1,MGR集群的节点间通信端口也往往是指定了本机IP上的不同端口,如果我们参照了官方文档中的搭建指南,使用的就是24901,24902,24903三个端口。

group_replication_group_seeds= "127.0.0.1:24901,127.0.0.1:24902,127.0.0.1:24903" 

现在我们既然将数据库搬到了容器中,那么就完全可以重新设计更有意义的主机名和分别的IP地址。 在启动Docker容器的时候,可以通过hostname和ip选项指定主机名和静态IP。可以参照最后运行Docker容器的完整命令。 如果要为Docker容器指定静态IP,则必须要使用手动创建的network,通过以下命令可以创建,比如此处我们创建了名称为mynet的网络。

$ docker network create --subnet=192.168.100.0/24 mynet 

创建完毕以后,通过network ls命令可以查看新创建的网络。可以看到默认是桥接方式。

$ docker network ls 
NETWORK ID NAME DRIVER SCOPE 
45e872bc9b12 bridge bridge local 
a1e4739cb508 host host local 
9617f8d9b8df mynet bridge local 
b0b9d568e2f9 none null local 

设计docker容器资源占用限制

对于在同一宿主机上运行多个docker容器,进行资源限制是必不可少的需求,虽然在此文中我们只是进行将MySQL实例搬迁到docker容器中的测试,但是也仍然规划了容器资源限制,由于宿主机本身只有2颗CPU和2GB内存,因此做如下规划。 在启动Docker容器的时候,可以通过cpus和memory以及memory-swap选项指定CPU和内存的资源限制。可以参照最后运行Docker容器的完整命令。

根据以上设置修改各数据库的my.cnf配置

因为我们设计了容器启动时候会拥有不同的IP地址,因此在容器中运行的MySQL实例的初始化参数中关于MGR的部分也需要指定这些IP地址。以下是my.cnf文件的设置内容。

[mysqld]

# server configuration
datadir=/var/lib/mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock

port=3306
bind-address=0.0.0.0

server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
relay-log=bogon-relay-bin

# Group Replication Settings
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "192.168.100.11:24901"
loose-group_replication_group_seeds= "192.168.100.11:24901,192.168.100.12:24901,192.168.100.13:24901"
loose-group_replication_bootstrap_group= off 

三个节点的my.cnf文件内容除了loose-group_replication_local_address参数之外,其它内容都是完全相同的。 对于第一个容器s1-container会使用到的my.cnf文件,这个参数为:

loose-group_replication_local_address= "192.168.100.11:24901" 

对于第二个容器s2-container会使用到的my.cnf文件,这个参数为:

loose-group_replication_local_address= "192.168.100.12:24901" 

对于第三个容器s3-container会使用到的my.cnf文件,这个参数为:

loose-group_replication_local_address= "192.168.100.13:24901" 

运行MySQL docker容器

由于MGR集群要求每个数据库在主机层是可以直接访问到其它节点的主机名的,如果在普通的主机上,只需要修改/etc/hosts文件增加其它节点的主机名和IP地址对应条目即可,但是容器内的/etc/hosts却是无法手动修改的,即使手动增加了条目,只要重新启动容器,该条目就会丢失。 要应对该问题,可以在运行容器时使用add_host选项。在真实的生产环境中,我们可以选择配置专门的DNS服务器来做IP和主机名对应(DNS服务器同样可以是Docker容器,我们后续的测试将增加此部分内容,本文先暂时通过add_host的方式来解决)。 最终运行三个docker容器的完整命令如下:

$ docker run \ 
--detach \ 
--name=s1-docker \ 
--memory=500m --memory-swap=1g \ 
--cpus=1 \ 
--hostname=mysql-mgr-server1 \ 
--net=mynet --ip=192.168.100.11 \ 
--add-host mysql-mgr-server2:192.168.100.12 
--add-host mysql-mgr-server3:192.168.100.13 \ 
--publish 6601:3306 \ 
--volume=/Users/Kamus/mysql_data/conf.d/s1-docker:/etc/mysql/conf.d \ 
--volume=/Users/Kamus/mysql_data/s1-docker:/var/lib/mysql \
 mysql:5.7.17 

$ docker run \ 
--detach \ 
--name=s2-docker \ 
--memory=500m --memory-swap=1g \ 
--cpus=1 \ 
--hostname=mysql-mgr-server2 \ 
--net=mynet --ip=192.168.100.12 \ 
--add-host mysql-mgr-server1:192.168.100.11 
--add-host mysql-mgr-server3:192.168.100.13 \ 
--publish 6602:3306 \ 
--volume=/Users/Kamus/mysql_data/conf.d/s2-docker:/etc/mysql/conf.d \ 
--volume=/Users/Kamus/mysql_data/s2-docker:/var/lib/mysql \
 mysql:5.7.17 

$ docker run \ 
--detach \ 
--name=s3-docker \ 
--memory=500m --memory-swap=1g \ 
--cpus=1 \ 
--hostname=mysql-mgr-server3 \ 
--net=mynet --ip=192.168.100.13 \ 
--add-host mysql-mgr-server2:192.168.100.12 --add-host mysql-mgr-server1:192.168.100.11 \ 
--publish 6603:3306 \ 
--volume=/Users/Kamus/mysql_data/conf.d/s3-docker:/etc/mysql/conf.d \ 
--volume=/Users/Kamus/mysql_data/s3-docker:/var/lib/mysql \
 mysql:5.7.17 

全部容器都启动完毕以后,可以通过docker ps命令查看容器的运行状态,或者通过docker logs命令查看MySQL数据库日志的输出。非常方便。

$ docker ps 
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 
2765e9104fe1 mysql:5.7.17 "docker-entrypoint..." 27 hours ago Up 6 seconds 0.0.0.0:6603->3306/tcp s3-docker 
1966bea215bc mysql:5.7.17 "docker-entrypoint..." 27 hours ago Up 18 seconds 0.0.0.0:6601->3306/tcp s1-docker 
18f68523f3a9 mysql:5.7.17 "docker-entrypoint..." 27 hours ago Up 9 seconds 0.0.0.0:6602->3306/tcp s2-docker 

启动MGR

通过如下命令登录到Docker容器的操作系统中,再进入MySQL实例,启动MGR。我们目前设置的是Single Primary模式的MGR,先启动第一个Primary实例。

$ docker exec -it s1-docker /bin/bash 
root@mysql-mgr-server1:/# mysql 
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.17-log MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 
mysql> SET GLOBAL group_replication_bootstrap_group=ON; 
Query OK, 0 rows affected (0.00 sec) 
mysql> START GROUP_REPLICATION; 
Query OK, 0 rows affected (1.07 sec) 
mysql> SET GLOBAL group_replication_bootstrap_group=OFF; 
Query OK, 0 rows affected (0.00 sec) 
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------------+-------------+--------------+ | 
CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+-------------------+-------------+--------------+ | group_replication_applier | 72ad2062-08a3-11e7-a513-5bfce171938d | mysql-mgr-server1 | 3306 | ONLINE | +---------------------------+--------------------------------------+-------------------+-------------+--------------+ 1 row in set (0.00 sec) 

再依次启动第二个只读实例。

$ docker exec -it s2-docker /bin/bash 
root@mysql-mgr-server2:/# mysql 
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.17-log MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 
mysql> START GROUP_REPLICATION; 
Query OK, 0 rows affected (5.60 sec) 
mysql> SELECT * FROM performance_schema.replication_group_members;
 +---------------------------+--------------------------------------+-------------------+-------------+--------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+-------------------+-------------+--------------+ | group_replication_applier | 72ad2062-08a3-11e7-a513-5bfce171938d | mysql-mgr-server1 | 3306 | ONLINE | | group_replication_applier | 9003e830-08a3-11e7-8ae3-e62d2f6366d2 | mysql-mgr-server2 | 3306 | ONLINE | +---------------------------+--------------------------------------+-------------------+-------------+--------------+ 2 rows in set (0.00 sec) 

启动第三个只读实例。

$ docker exec -it s3-docker /bin/bash 
root@mysql-mgr-server3:/# mysql 
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.17-log MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 
mysql> START GROUP_REPLICATION; 
Query OK, 0 rows affected (2.21 sec) 
mysql> SELECT * FROM performance_schema.replication_group_members;
 +---------------------------+--------------------------------------+-------------------+-------------+--------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+-------------------+-------------+--------------+ | group_replication_applier | 72ad2062-08a3-11e7-a513-5bfce171938d | mysql-mgr-server1 | 3306 | ONLINE | | group_replication_applier | 9003e830-08a3-11e7-8ae3-e62d2f6366d2 | mysql-mgr-server2 | 3306 | ONLINE | | group_replication_applier | 96fe2b5a-08a3-11e7-b383-d7f02f17e847 | mysql-mgr-server3 | 3306 | ONLINE | +---------------------------+--------------------------------------+-------------------+-------------+--------------+ 3 rows in set (0.00 sec) 

到此为止,我们将原先运行在macOS中的一整套MGR集群全部搬迁到docker容器中。最终实现了如下的系统架构。

MySQL Enterprise Audit in Oracle MySQL Cloud Service

Oracle Cloud Service似乎是唯一个即使你只提交了创建RDS服务的请求,也会自动帮你创建一个虚拟主机,并且提供主机登录权限的服务提供商,也许这就是Oracle一直在宣称的IaaS+PaaS的整合。

在创建MySQL Cloud Service时,会要求提供一个SSH登录密钥,所有的Oracle云服务主机登录用户都是opc,因此在服务创建完毕,收到通知邮件之后,就可以通过以下命令登录到云主机上。

ssh -i id_rsa_oracle_cloud_enmotech opc@your_host_ip

登录到主机以后,屏幕欢迎词是个小惊喜,Oracle贴心得显示了MySQL运行状态和存储使用量的提示。
MySQL Cloud Service Host

在比较了多方的RDS之后,Oracle MySQL Cloud Service确实如一直以来宣传的那样,提供了最多的安全选件功能,如果我们用MySQL Workbench登录到数据库中,在Server Status页面可以看到:SSL连接,PAM验证,密码校验,数据库审计等多种安全功能全部是开启的。

Oracle RDS security

而与之相比,阿里云MySQL RDS提供的安全功能就少的可怜了。说少不合适,是一项安全功能都没开启。
Aliyun RDS security

Oracle对于数据库安全性的看重确实超越了大多数数据库提供商,而这也带来了一些小麻烦。

在创建MySQL云服务的时候,需要指定数据库root用户的密码,这个密码有比较强的安全要求,需要有大写、小写英文字母,有数字,同时还需要有特殊字符(比如#)。因此在后续创建Login Path时,在mysql_config_editor命令提示输入密码的时候,需要在密码前后加上双引号(比如”Passw#rd”),否则会一直出现拒绝访问的提示。

--opc用户没有办法直接登录MySQL,需要切换到oracle用户
[opc@mysql-cloud-mysql-1 ~]$ mysql -uroot -p
Please switch to "oracle" user to use mysql client
[opc@mysql-cloud-mysql-1 ~]$ sudo su - oracle
--使用密码直接登录是没有问题的
[oracle@mysql-cloud-mysql-1 ~]$ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1509246
Server version: 5.7.17-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> exit
Bye
--创建Login Path,仍然输入上述一样的密码
[oracle@mysql-cloud-mysql-1 ~]$ mysql_config_editor set --host=localhost --user=root --password
Enter password:
--检查确认Login Path已经创建成功
[oracle@mysql-cloud-mysql-1 ~]$ mysql_config_editor print --login-path=client
[client]
user = root
password = *****
host = localhost
--直接登录报错
[oracle@mysql-cloud-mysql-1 ~]$ mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
--在密码前后加上双引号重新创建Login Path
[oracle@mysql-cloud-mysql-1 ~]$ mysql_config_editor set --host=localhost --user=root --password
Enter password:
WARNING : 'client' path already exists and will be overwritten.
 Continue? (Press y|Y for Yes, any other key for No) : Y
--再次登录,成功
[oracle@mysql-cloud-mysql-1 ~]$ mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1510011
Server version: 5.7.17-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.7.17, for linux-glibc2.5 (x86_64) using  EditLine wrapper

Connection id:		1510011
Current database:
Current user:		root@localhost
SSL:			Not in use
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server version:		5.7.17-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial)
Protocol version:	10
Connection:		Localhost via UNIX socket
Server characterset:	utf8mb4
Db     characterset:	utf8mb4
Client characterset:	utf8
Conn.  characterset:	utf8
UNIX socket:		/tmp/mysql.sock
Uptime:			10 days 13 hours 24 min 56 sec

Threads: 13  Questions: 50733146  Slow queries: 0  Opens: 6203  Flush tables: 1  Open tables: 4808  Queries per second avg: 55.610
--------------

在进行Audit功能的检查之前,对于默认的mysql命令行提示只有mysql> 这样简陋的显示不能忍,要加上当前登录的用户和数据库名称。在oracle用户的.my.cnf下增加以下行。

[mysql]
prompt=\\u@\\h [\\d]>\\_

再次登录,mysql命令行的提示就比较顺眼了。

[oracle@mysql-cloud-mysql-1 ~]$ mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1510385
Server version: 5.7.17-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

root@localhost [(none)]> show databases;
+-------------------------+
| Database                |
+-------------------------+
| information_schema      |
| mem                     |
| mem__advisor_text       |
| mem__advisors           |
| mem__bean_config        |
| mem__config             |
| mem__enterprise         |
| mem__events             |
| mem__instruments        |
| mem__instruments_config |
| mem__inventory          |
| mem__quan               |
| mysql                   |
| performance_schema      |
| sys                     |
| testdb                  |
+-------------------------+
16 rows in set (0.00 sec)

root@localhost [(none)]> use testdb
Database changed
root@localhost [testdb]> show tables;
Empty set (0.00 sec)

root@localhost [testdb]>

接下来进入本文的正题,在Oracle MySQL Cloud Service中默认是如何设置Audit的?
首先先检查一下audit_log的相关参数设置。

root@localhost [testdb]> show variables like 'audit_log_%';
+-----------------------------+--------------+
| Variable_name               | Value        |
+-----------------------------+--------------+
| audit_log_buffer_size       | 1048576      |
| audit_log_connection_policy | ALL          |
| audit_log_current_session   | ON           |
| audit_log_exclude_accounts  |              |
| audit_log_file              | audit.log    |
| audit_log_filter_id         | 0            |
| audit_log_flush             | OFF          |
| audit_log_format            | NEW          |
| audit_log_include_accounts  |              |
| audit_log_policy            | ALL          |
| audit_log_rotate_on_size    | 1073741824   |
| audit_log_statement_policy  | ERRORS       |
| audit_log_strategy          | ASYNCHRONOUS |
+-----------------------------+--------------+
13 rows in set (0.01 sec)

那么audit_log_file=audit.log表示仍然使用了默认的名字,到MySQL的数据文件目录中检查一下audit.log文件的存在。

[oracle@mysql-cloud-mysql-1 mysql]$ ls -l audit*
-rw-r----- 1 oracle oracle  838348830 Apr 21 13:42 audit.log
-rw-r----- 1 oracle oracle 1073742130 Apr 14 23:20 audit.log.14922120508218349.xml

这里可以看到总共的audit日志已经有1.9GB之大,在第一个audit.log达到audit_log_rotate_on_size参数设置的大小之后,自动切换成了新的audit.log。

题外话,之所以有这么巨大的audit.log,是由于启用了MySQL Enterprise Monitor,不断地记录了Monitor进程的登录和退出,为了方便后面观察audit.log,先将Monitor停止。

[oracle@mysql-cloud-mysql-1 monitor]$ pwd
/u01/bin/enterprise/monitor
[oracle@mysql-cloud-mysql-1 monitor]$ ./mysqlmonitorctl.sh stop
Stopping tomcat service . [ OK ]

接下来进行一些常规操作,并观察audit.log文件的输出内容。

1. 用root用户登录,在audit文件中显示一条Connect类型的记录。TIMESTAMP记录了时间,USER标签记录了登录的用户,HOST标签记录了登录的机器,COMMAND_CLASS为connect。

NewImage

2. 尝试直接CTAS一张测试表,在enforce_gtid_consistency=ON时会报1786错误,这是GTID特性决定的。

root@localhost [testdb]> create table mytables as select * from information_schema.tables;
ERROR 1786 (HY000): Statement violates GTID consistency: CREATE TABLE ... SELECT.

在audit.log中也记录下了这次报错的操作,STATUS标签为错误代码1786,STATUS_CODE标签值为1表示这条SQL没有成功执行,SQLTEXT标签记录了整个SQL语句。

NewImage

3. 下面的三条语句,select,create table,insert均没有在audit.log中记录下来。

root@localhost [testdb]> select count(*) from information_schema.tables;
+----------+
| count(*) |
+----------+
|      591 |
+----------+
1 row in set (0.01 sec)

root@localhost [testdb]> create table mytables like information_schema.tables;
Query OK, 0 rows affected (0.10 sec)

root@localhost [testdb]> insert into mytables select * from information_schema.tables;
Query OK, 592 rows affected (1.94 sec)
Records: 592  Duplicates: 0  Warnings: 0

这样的行为是由audit_log_statement_policy=ERRORS参数决定的,默认只记录报错的SQL,而不会记录所有的执行语句。

4. 将audit_log_statement_policy参数修改为ALL,再执行同样的select语句。

root@localhost [testdb]> SET GLOBAL audit_log_statement_policy = ALL;
Query OK, 0 rows affected (0.00 sec)

root@localhost [testdb]> select count(*) from mytables;
+----------+
| count(*) |
+----------+
|      592 |
+----------+
1 row in set (0.00 sec)

可以发现audit.log中已经有记录了。

NewImage

结论:在Oracle MySQL Cloud Service中默认会启动MySQL Enterprise Audit组件,并且设置即记录用户登录又记录执行语句(audit_log_policy=ALL),用户登录情况则不管登录成功还是失败每次都记录(audit_log_connection_policy=ALL),而执行语句则只记录执行失败的语句(audit_log_statement_policy=ERRORS)。

How to Set MySQL Group Replication into Multi-Primary Mode

在MySQL 5.7.17版本中发布的MySQL Group Replication(后文简称为MGR)被很多人称为MySQL复制方案的正规军,可以一举取代现在的MySQL Replication,Semisynchronous replication,甚至是可以取代之前最成功的MySQL集群方案Galera。

MGR有两种模式,一种是Single-Primary,一种是Multi-Primary,单主或者多主。

在前一种模式Single-Primary中,无论集群中有多少个节点,只有一个节点允许写入,其它节点都是只读的,这个允许写入的节点被称为主节点,只有当这个主节点出现问题从集群中被踢出,才会在剩余的节点中选举出另外一个节点成为新的主节点,并且将该节点置为可写模式。

这个过程可以通过log清晰地看到。

2017-03-16T02:04:32.689278Z 0 [Note] Plugin group_replication reported: 'getstart group_id 4317e324'
2017-03-16T02:04:33.081743Z 0 [Note] Plugin group_replication reported: 'Unsetting super_read_only.'
2017-03-16T02:04:33.081756Z 28 [Note] Plugin group_replication reported: 'A new primary was elected, enabled conflict detection until the new primary applies all relay logs'

而在后一种模式Multi-Primary中,所有的节点都是主节点,都可以同时被读写,看上去这似乎更好,但是因为多主的复杂性,在功能上如果设置了多主模式,则会有一些使用的限制,比如不支持Foreign Keys with Cascading Constraints。

在多主模式下,集群中的节点退出集群,也不再会出现重新选举的动作,因为本来所有的节点都是Primary节点。

前面这些并不是本文的重点,实际上在5.7.17的官方文档中有详细地描述如何设置Single-Primary MGR的方法。
Deploying Group Replication in Single-Primary Mode

但是不确认是什么原因,却没有单独的章节来描述如何设置集群为Multi-Primary模式。只是在最后语焉不详地提及了一句:Multi-primary mode groups (members all configured with group_replication_single_primary_mode=OFF) 让读者可以知道跟group_replication_single_primary_mode参数有关。虽然确实也就是跟这个参数有关,但是文档写的这样半半拉拉也确实值得吐槽。

以下为设置Multi-Primary MGR的方法。假设集群之前已经处于Single-Primary模式。

--group_replication_single_primary_mode=ON,表示启动了Single-Primary模式,那么修改为OFF就意味着要启动Multi-Primary模式。
(root@localhost) [(none)]> show variables like 'group_replication_single_primary_mode';
+----------------------------------------------------+-------------------------------------------------+
| Variable_name                                      | Value                                           |
+----------------------------------------------------+-------------------------------------------------+
| group_replication_single_primary_mode              | ON                                              |
+----------------------------------------------------+-------------------------------------------------+

--如果MGR已经启动,则无法动态修改该参数
(root@localhost) [(none)]> set global group_replication_single_primary_mode=off;
ERROR 3093 (HY000): Cannot change into or from single primary mode while Group Replication is running.

--停止复制
(root@localhost) [(none)]> stop GROUP_REPLICATION;
Query OK, 0 rows affected (8.67 sec)

--设置单主模式参数为off
(root@localhost) [(none)]> set global group_replication_single_primary_mode=off;
Query OK, 0 rows affected (0.00 sec)

--该参数设置为ON,则禁用了在多主模式下一些可能产生未知数据冲突的操作
(root@localhost) [(none)]> set global group_replication_enforce_update_everywhere_checks=ON;
Query OK, 0 rows affected (0.00 sec)

--设置为第一个准备启动MGR(bootstrap)的节点
(root@localhost) [(none)]> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)

--启动复制
(root@localhost) [(none)]> START GROUP_REPLICATION;
Query OK, 0 rows affected (1.29 sec)

--为了防止后续由于意外再启动另外一个复制组,关闭bootstrap参数
(root@localhost) [(none)]> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)

--此时可以从视图中看到整个集群只有一个节点是ONLINE
(root@localhost) [(none)]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 72ad2062-08a3-11e7-a513-5bfce171938d | bogon       |       24801 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
1 row in set (0.00 sec)

可以加入第二个节点了。

--同样设置单主模式参数为off
(root@localhost) [(none)]> set global group_replication_single_primary_mode=off;
Query OK, 0 rows affected (0.00 sec)

--设置update检查参数为on
(root@localhost) [(none)]> set global group_replication_enforce_update_everywhere_checks=ON;
Query OK, 0 rows affected (0.00 sec)

--启动复制
(root@localhost) [(none)]> start group_replication;
Query OK, 0 rows affected (5.42 sec)

--此时检查视图,可以发现集群中已经存在两个节点
(root@localhost) [(none)]> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 9003e830-08a3-11e7-8ae3-e62d2f6366d2 | bogon       |       24802 | ONLINE       |
| group_replication_applier | 96fe2b5a-08a3-11e7-b383-d7f02f17e847 | localhost   |       24803 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)

--group_replication_primary_member值为空,表示启动的是Multi-Primary Mode,否则该参数显示的是单主模式中的Primary节点
(root@localhost) [(none)]> SELECT * FROM performance_schema.global_status WHERE VARIABLE_NAME='group_replication_primary_member';
+----------------------------------+----------------+
| VARIABLE_NAME                    | VARIABLE_VALUE |
+----------------------------------+----------------+
| group_replication_primary_member |                |
+----------------------------------+----------------+
1 row in set (0.00 sec)

同样的方法可以加入第三个节点,在当前版本中MGR最多支持一个集群中拥有9个节点。

如果需要在MySQL重启之后这些参数仍然生效,那么需要将这些参数加入到my.cnf文件中,一个典型的配置了MGR的my.cnf如下所示。

[mysqld]

# server configuration
datadir=/Users/Kamus/mysql_data/s2
basedir=/usr/local/Cellar/mysql/5.7.17

port=24802
socket=/tmp/s2.sock

#
# Replication configuration parameters
#
server_id=2
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW

#
# Group Replication configuration
#
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "127.0.0.1:24902"
loose-group_replication_group_seeds= "127.0.0.1:24901,127.0.0.1:24902,127.0.0.1:24903"
loose-group_replication_bootstrap_group= off

#
## Group Replication configuration multi-primary mode
##
# loose-group_replication_single_primary_mode=off
# loose-group_replication_enforce_update_everywhere_checks=ON

Public preview of the next release of SQL Server on Linux

SQL Server for Linux

当微软宣布即将发布SQL Server for Linux版本的时候,有些人觉得很兴奋,有些人觉得然并卵,但是既然Gartner在2016年的数据库管理系统魔力象限图中将微软列在了第一位,超过了一直以来的霸主Oracle,那么无论如何这个SQL Server for Linux版本的发布都是值得关注的,微软将这个版本称为SQL Server vNext on Linux。vNext,好直白的期望。

Gartner-OP-DBMS-MQ-2016
Gartner-OP-DBMS-MQ-2016

微软在2016年11月中旬正式发布了SQL Server for Linux的第一个公众预览版,这条产品线将支持所有的企业级Linux平台,在第一个预览版中支持Red Hat Enterprise Linux 7.2和Ubuntu Linux 16.04,并且支持在macOS和Linux中的Docker容器,后续还会支持Suse Linux Enterprise Server,另外,微软承诺Linux上的SQL Server绝对不会是“SQL Server Lite”这样的阉割版数据库,而会是一个具备SQL Server 2016完整功能集的真正的企业级数据库,比如 in-memory OLTP,还有always-on encryption和row-level security这样的企业级安全功能。在现在的预览版中以下这些功能还不支持,但是后续会逐渐支持。

SQL Server Unsupported features and services

本文中会对SQL Server for Linux的安装、配置、使用做简单的测试,说实话,如果Oracle数据库的安装使用也能这样简单就太好了。

本文使用的测试环境是AWS的一个EC2实例,Red Hat Enterprise Linux 7.2,整个安装过程,从开始下载一直到数据库启动结束,不超过20分钟,这其中还包括了下载RPM包的15分钟。

第一步:用root用户下载安装镜像库的repo文件

sudo curl -o /etc/yum.repos.d/mssql-server.repo https://packages.microsoft.com/config/rhel/7/mssql-server-2017.repo

第二步:通过yum安装

sudo yum install -y mssql-server

第三步:设置数据库并启动
Update@2017-05-11
与之前不同,设置数据库的命令整合到mssql-conf命令中,而不再有sqlservr-setup命令。

[root@opreative-server-3 ~]# /opt/mssql/bin/mssql-conf setup
The license terms for this product can be downloaded from
http://go.microsoft.com/fwlink/?LinkId=746388
and found in /usr/share/doc/mssql-server/LICENSE.TXT.

Do you accept the license terms? [Yes/No]:Y
Setting up Microsoft SQL Server
Enter the new SQL Server system administrator password:
Confirm the new SQL Server system administrator password:
Starting Microsoft SQL Server...
Enabling Microsoft SQL Server to run at boot...
Created symlink from /etc/systemd/system/multi-user.target.wants/mssql-server.service to /usr/lib/systemd/system/mssql-server.service.
Setup completed successfully.

[11:24:34:794][ec2-user@ip-172-31-11-228 ~]$ sudo /opt/mssql/bin/sqlservr-setup
[11:24:34:876]Microsoft(R) SQL Server(R) Setup
[11:24:34:876]
[11:24:34:876]You can abort setup at anytime by pressing Ctrl-C. Start this program
[11:24:34:876]with the –help option for information about running it in unattended
[11:24:34:876]mode.
[11:24:34:876]
[11:24:34:876]The license terms for this product can be downloaded from
[11:24:34:877]http://go.microsoft.com/fwlink/?LinkId=746388 and found
[11:24:34:877]in /usr/share/doc/mssql-server/LICENSE.TXT.
[11:24:34:880]
[11:24:45:937]Do you accept the license terms? If so, please type “YES”: YES
[11:24:45:938]
[11:24:55:008]Please enter a password for the system administrator (SA) account:
[11:24:59:810]Please confirm the password for the system administrator (SA) account:
[11:24:59:810]
[11:24:59:811]Setting system administrator (SA) account password…
[11:25:03:006]
[11:25:07:728]Do you wish to start the SQL Server service now? [y/n]: y
[11:25:11:927]Do you wish to enable SQL Server to start on boot? [y/n]: y
[11:25:12:022]Created symlink from /etc/systemd/system/multi-user.target.wants/mssql-server.service to /usr/lib/systemd/system/mssql-server.service.
[11:25:12:058]Created symlink from /etc/systemd/system/multi-user.target.wants/mssql-server-telemetry.service to /usr/lib/systemd/system/mssql-server-telemetry.service.
[11:25:12:087]
[11:25:12:088]Setup completed successfully.

That’s it! SQL Server for Linux数据库就安装完毕并正常启动了。

可以通过systemctl来检查mssql-server的服务的启动状态。

[root@opreative-server-3 ~]# systemctl status mssql-server
● mssql-server.service - Microsoft SQL Server Database Engine
   Loaded: loaded (/usr/lib/systemd/system/mssql-server.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2017-05-11 17:00:17 CST; 34s ago
     Docs: https://docs.microsoft.com/en-us/sql/linux
 Main PID: 16147 (sqlservr)
   CGroup: /system.slice/mssql-server.service
           ├─16147 /opt/mssql/bin/sqlservr
           └─16166 /opt/mssql/bin/sqlservr

May 11 17:00:20 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:20.52 spid18s     Server is listening on [ 0.0.0.0  1433].
May 11 17:00:20 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:20.53 Server      Server is listening on [ 127.0.0.1  1434].
May 11 17:00:20 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:20.53 Server      Dedicated admin connection support was established for listening locally on port 1434.
May 11 17:00:20 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:20.53 spid18s     SQL Server is now ready for client connections. This is an informational message... required.
May 11 17:00:20 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:20.86 spid11s     Starting up database 'tempdb'.
May 11 17:00:21 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:21.03 spid11s     The tempdb database has 1 data file(s).
May 11 17:00:21 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:21.03 spid22s     The Service Broker endpoint is in disabled or stopped state.
May 11 17:00:21 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:21.03 spid22s     The Database Mirroring endpoint is in disabled or stopped state.
May 11 17:00:21 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:21.05 spid22s     Service Broker manager has started.
May 11 17:00:21 opreative-server-3 sqlservr[16147]: 2017-05-11 17:00:21.08 spid7s      Recovery is complete. This is an informational message only. No user action is required.
Hint: Some lines were ellipsized, use -l to show in full.

[ec2-user@ip-172-31-11-228 ~]$ systemctl status mssql-server
● mssql-server.service – Microsoft(R) SQL Server(R) Database Engine
Loaded: loaded (/usr/lib/systemd/system/mssql-server.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2016-12-04 22:25:08 EST; 1min 59s ago
Main PID: 16558 (sqlservr)
CGroup: /system.slice/mssql-server.service
├─16558 /opt/mssql/bin/sqlservr
└─16571 /opt/mssql/bin/sqlservr

安装完毕以后可以通过自带的mssql-conf命令进行一些简单的配置,可配置项不多,主要是监听端口,默认的数据文件所在目录,日志所在目录,备份所在目录等。

[ec2-user@ip-172-31-11-228 ~]$ sudo /opt/mssql/bin/mssql-conf list
Supported settings using the 'set' option: 
tcpport
defaultbackupdir
defaultdumpdir
defaultlogdir
defaultdatadir
For all command line options use -h or --help

如果希望在服务器上直接通过sqlcmd命令行登入数据库,还需要额外安装一个mssql-tools的RPM包,这个安装包里包括sqlcmd和bcp(Bulk import-export utility)。

第一步:用root用户下载安装mssql-tools的repo文件

sudo curl -o /etc/yum.repos.d/msprod.repo https://packages.microsoft.com/config/rhel/7/prod.repo

第二步:通过yum安装

sudo yum install -y mssql-tools

然后就可以通过sqlcmd来登入数据库,并使用Transact-SQL (T-SQL)语言来进行各种操作和管理了。我并非专业的SQL Server DBA,只是浅尝辄止而已。登录以后,创建了一个新数据库testdb,然后进入testdb,创建了一张新表inventory,然后在inventory表中插入了2条记录。

[ec2-user@ip-172-31-11-228 ~]$ sqlcmd -S localhost -U SA -P 'PASSWORD OF SA'
1> SELECT Name from sys.Databases;
2> GO
Name                                                                                                                            
--------------------------------------------------------------------------------------------------------------------------------
master                                                                                                                          
tempdb                                                                                                                          
model                                                                                                                           
msdb                                                                                                                            

(4 rows affected)
1> create database testdb;
2> go
1> SELECT Name from sys.Databases;
2> go
Name                                                                                                                            
--------------------------------------------------------------------------------------------------------------------------------
master                                                                                                                          
tempdb                                                                                                                          
model                                                                                                                           
msdb                                                                                                                            
testdb                                                                                                                          

(5 rows affected)
1> use testdb
2> go
Changed database context to 'testdb'.
1> CREATE TABLE inventory (id INT, name NVARCHAR(50), quantity INT);
2> GO
1> INSERT INTO inventory VALUES (1, 'banana', 150);
2> INSERT INTO inventory VALUES (2, 'orange', 154);
3> GO

(1 rows affected)

(1 rows affected)
1> SELECT * FROM inventory WHERE quantity > 152;
2> GO
id          name                                               quantity   
----------- -------------------------------------------------- -----------
          2 orange                                                     154

(1 rows affected)

除了sqlcmd命令行之外,在Windows操作系统下有全套的SQL Server Management Studio (SSMS) ,可以直接使用这个具有丰富功能的图形化管理工具来直接管理SQL Server vNext on Linux。多说一句,由于是使用1433端口连接服务器上的数据库,因此需要在AWS EC2中将该服务器实例所属的Security Group中的Inbound策略中开放TCP 1433端口。

SQL Server Management Studio

【结论】SQL Server vNext on Linux预览版在安装、操作过程中非常顺畅,在后续有更多功能加入以后,应该是企业级数据库非常优秀的选择。先不说是否会有Oracle用户迁移到SQL Server上,这至少给了现在正在使用SQL Server的客户们更广阔的选择空间,现在他们运行在Windows Server上的SQL Server数据库也可以移植到Linux中了,无论如何,这是一个很大的进步,微软这步要是能早一些迈出可能就更好了。

Why I returned my purchase of New MacBook Pro with Multi-Touch Bar

是的,我把刚刚收到不到一周的新MacBook Pro退货了,听上去挺不可思议的。同时,我还退掉了刚刚收到的仍未拆封的两根接口线,一根是USB-C转Thunderbolt2,一根是USB-C转Lightning。实际上为了这台新MacBook Pro,我还早早地就购买了4个USB-C转USB3.0的转接头,他们由于收到货太久了,没法儿退货。 我拥有苹果刚刚开始使用Intel x86芯片做Macbook处理器时的第一代MacBook,那是2005年时候的事情,然后一直到今年,在10年多的时间里,几乎每一代MacBook Pro的新品我都拥有,从13寸到15寸,从普通显示屏到Retina显示屏,从普通机械硬盘到SSD,从Megasafe到Megasafe II,我甚至为家人购买了新的只有一个USB-C接口的Macbook,对于其上饱受很多程序员诟病的一代蝶式键盘,我也同样很喜欢。另外我还拥有从iPhone4开始的每一代iPhone,从第一代iPad开始的每一代iPad(嗯,不包括iPad Pro,因为实在找不到购买的理由)。在购买最新的MacBook Pro with Multi-Touch Bar之前,我在工作和生活中使用的是2015年年初出的那一批13寸顶配MacBook Pro。 你们一定要说这是在炫耀,实际上我只是想说,我是一个经验丰富的苹果产品使用者,还是一个彻头彻尾纯正的果粉,然而,在收到新MacBook Pro不到一周后的今天,我退货了。下面是退货的理由,总得给自己一个交代不是吗?在你阅读下面这些牵强附会的理由之前,如果你还在使用MacBook Air(像我的一个朋友那样),或者你在使用任何一款Windows笔记本,那么我仍然强烈建议你购买这一代MacBook Pro,但是如果你像我一样已经在使用上一款MacBook Pro,那么建议你可以体会一下。 1. Multi-Touch Bar。 Multi-Touch Bar是这一代MacBook Pro的最大卖点,也是看发布会时最让人惊艳的功能。 MacBook Pro with Multi-Touch Bar 虽然,这一段窄窄的触摸屏,苹果实现的非常不错,它拥有特别合适的位置和形状,显示在其上的各种图标也很优雅。然而除了最右侧的Touch ID让我们在解锁笔记本的时候感觉到很爽之外,在我使用这台本子的一周内,这条触摸屏仍然很少场景会被使用到。大部分时间,Touch Bar上都在不停地变换着用苹果内置的中文输入法时出现的备选字,然而谁会不用数字键去选择备选字,而是用手指戳那个触摸屏呢?连盲打都实现不了。不过值得一提的是,聊天时候输入emoji用触控条真的很方便。 找不到能够频繁使用Multi-Touch Bar的场景倒也罢了,由于取代了原本最上面一条的实体按键,还有一些不太方便的场景。 在很多情况下,调节声音和亮度的按钮是龟缩在整个Touch Bar的右侧的,需要调小音量,OK,你需要点一下音量按钮,然后在变幻出来的进度条上去拖动,这样的拖动让我非常抓狂,因为完全丧失了一下一下按音量键来确认到底哪个音量更合适的控制感。想一下,在只想快进和后退几格的时候,你是会用按键还是会去拖进度条? 在最开始让程序员抓狂的ESC键,现在还在,但是变成了虚拟键,虽然这部分是可以盲打的,在这个虚拟ESC键的周边敲击都有效,然而对于一个频繁会被使用到的按键,在大多数按键都有实体键反馈的时候,忽然小指触到一个平平的地方,这种需要迅速转换的体验,总让人疑惑是不是点击到了ESC。这是一种让人烦躁的感觉。 2. 超大的触控板。 触控板 MacBook Pro原本的触控板已经很大了,还需要更大吗?问题是大了以后会很容易误触啊。因为实际上在你打字的时候,你的两个大拇指甚至是手掌的半坨肉都是很容易会碰到触控板的,这个误触的频率已经到了有时候会让人心里暗骂“我靠”的地步,有些严重。 3. 四个USB-C接口。 即使拥有可以左右开工,找任意舒服的方位充电的好处,忽然间全部变成了USB-C仍然让人有些头痛。Megasafe这么优雅的电源接口就这样被丢弃了,着实让人心痛。特别是当我想到以前的各种线缆在很长一段时间里都又要再接一个转接口,这样的处理方案让我很纠结。一点儿也不优雅!也许再等几年,当所有的外接设备(U盘,移动硬盘,鼠标,演讲遥控器,网银U盾)都有了天生USB-C接口,这个问题就不存在了。 4. 电源绕线。 这是最让我沮丧的地方,完全不能理解为什么从新MacBook开始,苹果就取消了那么贴心的设计。以后再也不能像下面这样电源和线缆融为一体了。 img_0230 我甚至能想像出来,不出几周,线缆就会变成这样,这太让人忧伤了。 img_0240 【结论】新MacBook Pro仍然是笔记本电脑中最值得购买的机型(没有之一),但是如果你的手头上已经有一款运行状况良好的上一代MacBook Pro,就像我现在这样,那么值得更新换代的动机则不会那么强烈。

Network Settings Configuration in Oracle Cloud

对于Oracle DBA而言,网络上的配置可能都是短板,而如果在公有云中进行Oracle数据库的部署,那么几乎要求一个DBA变成全栈工程师,因为已经不需要你进行网络基础架构的安装,那么对整个环境进行简单的网络设定配置就成为必不可少的技能之一。

本文会着重介绍Oracle Cloud中关于网络设定的概念和设置方法。

在这之前要先简单介绍Oracle Cloud。

Screen Shot 2016-04-09 at 2.56.16 PM

也许你已经听说过Amazon AWS、Microsoft Azure,甚至你已经在使用阿里云、华为云、腾讯云、青云,而Oracle无疑是这场云大战中的迟到者,但是从过去的2015年看,Oracle在Cloud市场上的表现却是不俗的,Oracle一直宣称自己是全球唯一最全面、最集成的一朵完整的云,提供了IaaS,PaaS,SaaS三个层面的所有产品,而让Oracle Cloud特别引人注意的,无疑是在RDBMS全球市场中占据霸主地位的Oracle数据库的云化。

Oracle Database在Oracle Cloud中目前有以下几种产品方式。

1. Database as a Service 提供一个客户独占的虚拟机,可以选择在其上安装的是11g还是12c数据库,包括可以选择安装一个2节点的RAC;客户对于虚拟机和运行在其上的数据库有完全的管理权限,包括操作系统的root权限,还有数据库的SYSDBA权限,提供一键备份和一键打补丁等简便的管理功能。

2. Exadata Service 提供一个运行在Exadata上的11.2.0.4或者12.1.0.2的数据库,客户可以选择是全配、半配还是四分之一配,还可以选择是否是RAC,同样有操作系统的root权限和数据库的SYSDBA权限。

3. Database Schema Service 提供一个在11g数据库中的Schema,客户可以选择存储空间大小(5GB-50GB),只能通过RESTful网络服务接口来访问该Schema中的表数据,毫无疑问,没有数据库的SYSDBA权限,操作系统也是完全不可见的。

4. Database as a Service – Managed(该服务产品目前还没有正式发布) 提供一个Oracle数据库给客户,客户拥有SYSDBA权限,可以以包括SQL*Net在内的各种方式访问数据库,操作系统不可见,Oracle原厂承担必要的维护工作,比如备份和PITR恢复、打补丁和升级。

本文中使用的产品是Database as a Service,一套Oracle 12.1.0.2 RAC。CDB架构,初始化创建时候设定了一个PDB。

Screen Shot 2016-04-05 at 4.07.20 PM

在数据库创建完毕以后,Oracle也默认创建了承载Oracle数据库的虚拟机,也就是底层的IaaS架构,在本文中是两台2CPU4核,15GB内存的虚拟机,每台机器有161GB存储空间(这其中包括了安装操作系统和Oracle软件的75GB本地空间,以及ASM使用的66GB共享空间)。

Screen Shot 2016-04-05 at 5.19.23 PM

以上这些都不是本文的重点,我们要介绍的是Oracle Cloud的网络设定。要知道,新创建完的虚拟机虽然可以通过SSH来访问,但是数据库默认是无法通过监听来远程访问的,必须要进行网络设定的修改。

在Oracle Cloud中网络层面的设定要涉及到以下几个概念,我们从管理界面中可以看到这些名词。

Screen-Shot-2016-04-05-at-2_15_14-PM

Security Lists 每个Security List包含了一组Oracle Compute Cloud Service实例(每个Oracle Compute Cloud Service实例可以简单地认为就是一台Oracle Cloud虚拟机,用AWS的语言说是一个EC2实例,用阿里云的语言说是一个ECS实例,以下简称为OCCS),在同一个Security List中的机器可以无障碍地通过任何网络端口进行数据交互,但是与外界的机器进行交互就要看这个Security List中对于inbound和outbound的策略定义了。Inbound策略控制了想进入这个Security List中的网络防火墙定义,Outbound策略控制了想传出这个Security List中的网络防火墙定义。 inbound和outbound的策略都有3种,分别是permit,reject和deny。 permit:允许任何数据包传输(在inbound策略中就是传入,在outbound策略中就是传出) reject:丢弃所有数据包,但是有回传信息告知数据包被丢弃 deny:丢弃所有数据包,并且不回传任何信息 如下这张图清晰地表现了不同Security List中不同的inbound和outbound策略下数据的可能流向。

Screen Shot 2016-04-05 at 6.25.13 PM

默认创建的Security List的inbound策略都是deny,下图中有关联实例的命名为oracle-cloud-enmotech/1/db_1/ora_db的Security List是正在使用的,可以看到inbound策略是deny。 Screen Shot 2016-04-09 at 2.02.44 PM

也就意味着所有的数据包不能传入到新建的机器上和数据库里。那么为什么新建的机器可以通过SSH访问,而又确实无法通过数据库监听来远程访问?这就需要提到下面这个概念-Security Rules。

不过在解释Security Rules之前,需要先解释另外两个概念,Security Applications和Security IP Lists。

Security Applications Security Application就是一组网络协议和端口的组合,从下图中可以清晰地看出来。

命名为ssh的Security Application就是tcp协议的22端口,这就是ssh默认的端口。 Screen Shot 2016-04-09 at 1.41.50 PM

命名为ora_scan_listener的Security Application就是tcp协议的1521端口,这就是数据库SCAN监听默认的端口。 Screen Shot 2016-04-09 at 1.42.13 PM

再比如命名为ora_monitor_12c的Security Application就是tcp协议的5500端口,这就是12c新的EM Express默认使用的端口。 Screen Shot 2016-04-09 at 1.43.25 PM

Security IP Lists 另外一个关键的概念,就是Security IP List,这里定义的是一组IP地址或者子网,也就是防火墙设置中在源(source)和目标(destination)中设置的值。 比如在如下图的默认设置中,public-internet就表示了所有的IP地址。

Screen-Shot-2016-04-09-at-1_51_58-PM

最后,进入Security Rules的解释。

Security Rules 一个Security Rule实际上就是一个防火墙规则,用于定义对于特定的应用访问OCCS的防火墙策略。这些防火墙是在Security List之上设置的特例。简单地说,Security List的inbound策略是deny的话,那么只有在Security Rule中明确设置可以通过的端口才被允许通过;如果Security List的inbound策略是permit的话,就不需要再设置任何Security Rule,因为所有端口都被允许了。很明显,Oracle强烈建议第一种设置方法,而不要轻易设置Security List的inbound策略是permit。

为什么新建的机器可以通过SSH访问?因为SSH的Security Rule是默认打开的(Status=Enabled)。 Screen Shot 2016-04-09 at 1.30.38 PM

解读一下,图中的各个设定的含义。 Security Application=ssh,是这个防火墙规则针对的是tcp协议的22端口; Source=public-internet,是这个防火墙规则的源定义,是一个Security IP List的值,表示任何一个IP; Destination=oracle-cloud-enmotech/1/db_1/ora_db,是这个防火墙规则的目标定义,是一个Security List的值,就是上面提到的inbound策略为deny的那个Security List,这表示在这个Security List中的所有OCCS都是目标。

再通俗易懂地解释一下,就是该防火墙定义允许任何一个IP通过22端口访问本次创建的Database之下的所有OCCS,也就是允许通过SSH来访问RAC的2个节点。

为什么无法通过数据库监听来远程访问?因为跟SCAN Listener相关的Security Rule是默认关闭的(Status=Disabled)。 Screen Shot 2016-04-09 at 1.31.19 PM

修改很简单,将状态从Disabled修改为Enabled即可。

剩下在网络设定管理界面中的另外两个名词,就比较简单了。

IP Reservations 为虚拟主机保留的公网IP,可以通过这个IP直接访问主机。 Screen_Shot_2016-04-09_at_2_07_44_PM

SSH Public Keys 登录OCCS,不是通过用户名和密码,而必须要通过SSH Key,在创建Database的过程中就会要求上传Public Key,也可以在这个界面再次更新或者上传新的Public Key。 Screen_Shot_2016-04-09_at_2_08_10_PM

结论 通过以上的设置,Oracle Cloud基本上组成了一套完善的网络防火墙体系,可以细粒度的控制哪些IP通过哪些端口访问数据库或者数据库主机。