0%

sftp是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的网络的加密方法。sftp 与 ftp 有着几乎一样的语法和功能。本文主要介绍了Mac系统中常用的sftp命令

登陆命名

sftp -P 端口 用户@服务器IP

示例:sftp -P 22 user@192.168.0.101

服务器目录显示/操作命令

pwd 打印服务器当前目录

cd 切换服务器当前目录

ls 列出服务器当前目录下的文件

mkdir 为服务器创建目录

本机目录显示/操作命令

比服务器目录操作命令多了一个”l”(Local)

lpwd 打印本机当前目录

lcd 切换本机当前目录

lls 列出本机当前目录下的文件

lmkdir 为本机创建目录

文件操作命令

get 取得远程服务器上的指定文件

put 上传本地指定的文件到远程服务器上

示例:

get -r ./* /Users/voidcc.com/本地项目目录/

从远程下载所有文件及文件夹到本地项目目录

帮助命令

help 取得帮助

有两个简单例子,以说明 “exists”和“in”的效率问题
1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a);
T1数据量小而T2数据量非常大时,T1<<T2 时,1) 的查询效率高。

2) select * from T1 where T1.a in (select T2.a from T2);
T1数据量非常大而T2数据量小时,T1>>T2 时,2) 的查询效率高。

exists 用法:

请注意 1)句中的有颜色字体的部分 ,理解其含义;
其中 “select 1 from T2 where T1.a=T2.a” 相当于一个关联表查询,相当于
“select 1 from T1,T2 where T1.a=T2.a”
但是,如果你只执行 1) 句括号里的语句,是会报语法错误的,这也是使用exists需要注意的地方。
“exists(xxx)”就表示括号里的语句能不能查出记录,它要查的记录是否存在。
因此“select 1”这里的 “1”其实是无关紧要的,换成“*”也没问题,它只在乎括号里的数据能不能查找出来,是否存在这样的记录,如果存在,这 1) 句的where 条件成立。

in 的用法:

继续引用上面的例子
2) select * from T1 where T1.a in (select T2.a from T2);
这里的“in”后面括号里的语句搜索出来的字段的内容一定要相对应,一般来说,T1和T2这两个表的a字段表达的意义应该是一样的,否则这样查没什么意义。
打个比方:T1,T2表都有一个字段,表示工单号,但是T1表示工单号的字段名叫“ticketid”,T2则为“id”,但是其表达的意义是一样的,而且数据格式也是一样的。这时,用 2)的写法就可以这样:

1
2
3
select * from T1 where T1.ticketid in (select T2.id from T2);
select name from employee where name not in (select name from student);
select name from employee where not exists (select name from student);

第一句SQL语句的执行效率不如第二句。
通过使用EXISTS,Oracle会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。

引言

对于从事 Oracle 技术开发的同学,肯定都要连接 Oracle 数据库,而Oracle 自带的 sqlplus 命令行工具功能太弱了,不支持命令联想、数据显示不美观,还要安装什么 Oracle Client,导致很多同学不得不用其他工具(PL/SQL Developer、Oracle SQL Developer)来连接数据库。但 PL/SQL Developer 仅支持 Windows 平台,Oracle SQL Developer 虽然是跨平台的,但显得又太重了。

有没有更好的命令行工具呢?其实 Oracle 早就提供了另一个用来替代 sqlplus 的命令行工具,它就是今天的主角SQLcl。

安装 SQLcl,准备工作

确保你的机器上安装了 Java 8 或以上版本(JRE 或 JDK 均可),下载地址在这里。

下载 SQLcl 安装包

SQLcl 的安装相当简单,首先去 Oracle 网站 下载 SQLcl 的安装包,截止到该文写作时为止,最新的 SQLcl 版本是 18.1.1(2018年4月12日发布的)。

配置 SQLcl

下载到本地以后是个 zip 压缩包,解压缩后进入 sqlcl/bin,里面的sql是给 Mac 或 Linux 平台准备的,而sql.exe是给 Windows 平台准备的。

钢哥注:由于我用的是 Mac,每次只要进到这个目录,再执行./sql即可启动 SQLcl 了。做得更干脆一点儿,由于我的 SQLcl 目录是/Users/kwang/sqlcl/bin,所以只要把这个目录添加到~/.bash_profile文件的PATH变量里即可,这样以后只要在命令行里输入sql,就自动启动SQLcl了。

以下是我的~/.bash_profile 文件内容

1
export PATH=/Users/kwang/sqlcl/bin:$PATH

想要立刻生效,别忘了source ~/.bash_profile。

SQLcl 实战

让我们来看看 SQLcl 到底跟 sqlplus 有什么区别?

数据库连接

1
sql sys/welcome@localhost:1521:orcl as sysdba

清除屏幕

使用clear screen命令,整个世界清静了。

钢哥注:命令不需要曲敲全,SQLcl会自动智能提示/补全的,这一点比 sqlplus 好太多了。

help - 帮助命令

输入help命令可以展示相关帮助主题。

show pdbs - 显示命令

由于我用的是 Oracle Database 12c,可以用如下命令显示目前数据库中已有的 Plugin DB:

1
show pdbs

alter session - 切换会话

切换当前 session 到特定的 Plugin DB:

1
alter session set container=orclpdb1;

执行 sql 脚本

执行 sql 脚本,跟 sqlplus 一样用 @ 即可,运行以下命令,创建emp和dept表及插入演示数据。

1
@https://raw.githubusercontent.com/OraOpenSource/OXAR/master/oracle/emp_dept.sql

ddl - 生成对象定义语句

假如我们想快速生成emp这张表的定义语句,可以用如下命令:

1
ddl emp

键盘左键 - 编辑已输入的命令

使用过 sqlplus 的同学都知道,如果一个 sql 命令很长,需要分多行输入,这都没问题。但有时候再输入了很多行以后,突然想改一下之前输入的命令,这就尴尬了,你会发现根本没办法修改,只能大侠重新来过,WTF。。。

有了SQLcl就不存在这个问题了,它允许你用键盘左键进入快速编辑模式,然后就可以愉快地修改已经输入的命令了。

键盘 tab 键 - 智能提示/补全

如果在快速编辑模式下,输入表字段名的前几个字母,SQLcl会自动提示/补全剩余的字符,比sqlplus人性化多了。

键盘上下键 - 快速切换已输入的命令

这个没什么好说的。

sqlformat - 格式化 SQL 执行结果

默认样式下执行select * from emp,显示结果如下图所示:

执行show sqlformat可以看到当前格式化样式为:default

set sqlformat ansiconsole
让我们修改下显示结果的样式:

1
set sqlformat ansiconsole

再次执行select * from emp,格式如下:

set sqlformat csv - 输出成CSV格式

1
set sqlformat csv

再次执行select * from emp,格式如下:

set sqlformat - 恢复默认样式

1
set sqlformat

set head off - 清除 SQL 输出结果头信息行

1
set head off

history - 访问历史记录

可以用history命令查看已经输入过的历史命令。

想要再次输入某个历史命令,只需要在history命令后面加上对应的编号,然后再敲/执行即可。

1
history 15

结语

以上就是关于 Oracle SQLcl 简单的介绍和命令,用来替代 sqlplus 绝对绰绰有余了,希望对喜欢命令行操作的同学有所帮助,谢谢关注!

作为技术人 没有一个好用的命令行工具 是不能忍受的
而Mac自带的Terminal稍弱 问 有没有一个好用的命令行工具可以替代Terminal?
今天介绍的iTerm 或许可以满足你的需求

下载安装

移步 iTerm官网 点击 Download下载

常用Preferences配置

菜单进入Preferences ->Profiles

在左侧白色窗口中 我们可以看到有一个Default默认选项
这个代表 iTerm默认窗口模板
当然你也可以添加新的窗口模板
点击下方 + 号按钮新建模板 出现如下界面

Name:模板名称 这里我们叫它Red 因为我们将要设置它为红色背景
Shortcut key:打开此窗口的快捷键 可以看到control+command是固定前缀 选择你要设置的完整快捷键
在这里我们选择R
Tags(标签): Tags将会作为搜索条件 (快速查找)
搜索效果

然后我们切换到 Colors 选项

Foreground:前景色 设置文字字体 这里我们设置为白色
Background:设置窗口背景 这里我们设置为红色
其他选项不在一一介绍 设置完成后 关闭Preferences
按下快捷键**control+command+R **

可以看到我们打开了Red主题窗口

Hotkey Window (快速调出窗口)

实际使用时我们经常会遇到这种场景 有时候 只是执行几行命令 然后就不再使用它 可是我们还是必须要打开Terminal 然后使用后关闭它 在这种情况下借住iTerm的**Hotkey Window **功能我们将会得到前所未有的体验
Hotkey Window支持一键调出iTerm 它将以半透明的形式 覆盖在屏幕上方 如下图

使用Hotkey Window功能 需要我们做点工作 那就是启用Hotkey Window并设置调出快捷键

如上图 菜单选择Preferences -> Keys -> 选中下方两个复选框
并在Hotkey处设置快捷键 这里我们设置为command+/
关闭该窗口 按下command+/快捷键试试
当我们再次回到Preferences->Profiles时 你将看到
如下界面 新增了一个Hotkey Window主题

当然我们也可以按照Red主题的方设置法 为Hotkey Window设置样式 这里不再赘述

剪贴板历史记录

iTerm允许我们快速查看剪贴板内容 只需要按下快捷键
**Command + Shift + H **如图所示

时间轴(命令快照)

如果你查看某一段时间执行的操作 可以使用时间轴功能
按下快捷键 Command + Option + B

快速选择

使用命令行的优势是 可以脱离鼠标操作 专注事情本身
但是当我们想要选择一段文本时 Terminal必须借助鼠标才能完成(难道是我不知道?) 而iTerm要做的只是按下Tab键即可完成
比如我们需要选择FarBar文本
按下Command+F 输入Far 按下Tab键 自动进入剪贴板中
在合适的位置按下Command+V就可以粘贴内容

快速预览所有标签页

如果你打开了很多标签页 想要快速查找某个标签
按下Command + Option + E键 iTerm将会为你展示所有标签页
有没有很熟悉这个效果???

下面的命令 我们不再详细介绍
Command+T 新建标签页
**Command+W **关闭标签页
Command+左右方向键 切换显示标签页
Command+shift+左右方向键 移动当前选中的标签页位置
**Command+上下方向键 **上下滚动内容
Command+数字(Number) 切换显示指定位置的标签页
**Command+alt+数字(Number) **切换指定位置的窗口
**Command+, **打开Perferences窗口
Command + Shift + M 标记命令
Command + Shift + J 回到标记处 结合上个快捷键使用
defaults delete com.googlecode.iterm2 恢复默认设置
以上命令感兴趣的 可以实际操作感受下
你准备好使用iTerm了吗?

在windows下用xshell、secureCRT等工具只要在服务端装好lrzsz工具包就可以实现简单方便的文件上传下载。昨天在Mac上用iTerm的时候发现iTerm原生不支持rz/sz命令,也就是不支持Zmodem来进行文件传输。遂查了一下,发现解决办法还算简单,不过有点小坑。

通过brew安装lrzsz

首先先假定你安装了Homebrew,然后我们通过它,先给Mac安装lrzsz。
在终端下输入brew install lrzsz,静等一会即可安装完毕。

下载配置iTerm2的相关脚本

这一步,在给iTerm2加上相应配置前需要下载两个前人已经写好的脚本文件。

这里是下载地址,将iterm2-recv-zmodem.sh和iterm2-send-zmodem.sh下载到本机,然后将它们放到/usr/local/bin目录下。

如果你安装过wget,也可以在/usr/local/bin目录下直接执行:

1
wget https://raw.githubusercontent.com/mmastrac/iterm2-zmodem/master/iterm2-send-zmodem.sh https://raw.githubusercontent.com/mmastrac/iterm2-zmodem/master/iterm2-recv-zmodem.sh

然后我们将这两个文件赋予可执行权限:

1
chmod +x /usr/local/bin/iterm2-send-zmodem.sh /usr/local/bin/iterm2-recv-zmodem.sh

配置iTerm2

找到iTerm2的配置项:iTerm2的Preferences-> Profiles -> Default -> Advanced -> Triggers的Edit按钮。

然后配置项如下:

Regular Expression Action Parameters Instant
rz waiting to receive.**B0100 Run Silent Coprocess /usr/local/bin/iterm2-send-zmodem.sh checked
**B00000000000000 Run Silent Coprocess /usr/local/bin/iterm2-recv-zmodem.sh checked

尤其注意最后一项需要你将Instant选项勾上,否则将不生效

注意看图:

至此结束。只要服务端也已经装好了lrzsz工具包便可以方便地通过rz\sz来进行文件上传下载了。

最近在mac中折腾ssh自动登录的问题,不自动登录每次输入命令太痛苦了,采取的方案是expect脚本的方式。

expect脚本

1
2
3
4
5
6
7
8
9
10
11
12
vim /usr/local/bin/login.exp
#!/usr/bin/expect

set timeout 30
spawn ssh [lindex $argv 0]@[lindex $argv 1] -p [lindex $argv 2]
expect {
"(yes/no)?"
{send "yes\n";exp_continue}
"password:"
{send "[lindex $argv 3]\n"}
}
interact

该脚本比较简单,需要四个参数,第一个参数是远程用户名,第二个参数是远程地址,第三个参数是SSH端口,第四个是密码。
给expect脚本赋予可执行权限。

1
chmod +x /usr/local/bin/login.exp

配置iterm2

在iterm2中用command+o快捷键打开profiles,点击Edit Profiles,按照下图的方式配好后,双击可即可自动登录。
Preferences

环境

CentOS7.5 最小安装
数据库软件
linuxx64_12201_database.zip

操作系统配置

关闭 SELinux

1
sed -i '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config

配置防火墙

1
2
3
4
systemctl enable firewalld
systemctl restart firewalld
firewall-cmd --zone=public --add-port=1521/tcp --add-port=5500/tcp --permanent
firewall-cmd --reload

重启操作系统

1
reboot

安装依赖

安装可能用到的工具

1
2
3
4
yum install epel-release
yum clean all
yum makecache fast
yum install vim unzip rlwrap

安装 oracle 需要的包

1
2
3
4
5
6
yum install binutils compat-libcap1 compat-libstdc++-33 \
compat-libstdc++-33*i686 gcc gcc-c++ glibc glibc*.i686 \
glibc-devel glibc-devel*.i686 ksh libaio libaio*.i686 libaio-devel \
libgcc libgcc*.i686 libstdc++ libstdc++*.i686 libstdc++-devel \
libXi libXi*.i686 libXtst libXtst*.i686 make sysstat unixODBC \
unixODBC*.i686 unixODBC-devel unixODBC-devel*.i686

配置安装环境

创建 oracle 用户

1
2
3
4
groupadd oinstall
groupadd dba
groupadd oper
useradd -g oinstall -G dba,oper oracle

创建 oracle 安装目录

1
2
3
4
5
mkdir -p /opt/oracle/app/product/12.2.0
mkdir -p /opt/oracle/app/oradata
mkdir -p /opt/oracle/app/fast_recovery_area
chown -R oracle:oinstall /opt/oracle
chmod -R 775 /opt/oracle

修改 sysctl.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat << EOF >> /etc/sysctl.conf
fs.aio-max-nr = 1048576
fs.file-max = 6815744
#物理内存一半和4G中的较大者,当前服务器16G
kernel.shmmax = 8589934592
#shmmax / 4k (getconf PAGESIZE)
kernel.shmall = 2097152
kernel.shmmni = 4096
kernel.sem = 250 32000 200 200
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.wmem_max = 1048586
net.core.rmem_max = 4194304
EOF
sysctl -p

修改 limits.conf

1
2
3
4
5
6
7
cat << EOF >> /etc/security/limits.conf
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
oracle soft stack 10240
EOF

修改 login

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat << EOF >> /etc/pam.d/login
session required /lib64/security/pam_limits.so
session required pam_limits.so
EOF
修改 profile
cat << EOF >> /etc/profile
if [ \$USER = "oracle" ] ; then
if [ \$SHELL = "/bin/ksh" ]; then
ulimit -p 16384
ulimit -n 65536
else
ulimit -u 16384 -n 65536
fi
umask 022
fi
EOF

修改 oracle 用户的 .bash_profile

1
2
3
4
5
6
7
8
cat << EOF >> /home/oracle/.bash_profile
export ORACLE_BASE=/opt/oracle/app
export ORACLE_HOME=\$ORACLE_BASE/product/12.2.0
export ORACLE_SID=orcl
export PATH=\$PATH:\$ORACLE_HOME/bin
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8"
#export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
EOF

安装数据库

上传数据库软件到 /root 下,解压

1
2
unzip linuxx64_12201_database.zip -d /home/oracle/
chown -R oracle.oinstall /home/oracle/database

切换到 oracle 用户,后续操作都在该 oracle 用户下执行

1
su - oracle

创建 response 文件

1
2
cd /home/oracle
cp database/response/*.rsp ./

修改 db_install.rsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sed -i \
-e '/^oracle\.install\.option=/s#=.*$#=INSTALL_DB_SWONLY#' \
-e '/^UNIX_GROUP_NAME=/s#=.*$#=oinstall#' \
-e '/^INVENTORY_LOCATION=/s#=.*$#=/opt/oracle/oraInventory#' \
-e '/^ORACLE_HOME=/s#=.*$#=/opt/oracle/app/product/12.2.0#' \
-e '/^ORACLE_BASE=/s#=.*$#=/opt/oracle/app#' \
-e '/^oracle\.install\.db\.InstallEdition=/s#=.*$#=EE#' \
-e '/^oracle\.install\.db\.OSDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSOPER_GROUP=/s#=.*$#=oper#' \
-e '/^oracle\.install\.db\.OSBACKUPDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSDGDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSKMDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle\.install\.db\.OSRACDBA_GROUP=/s#=.*$#=dba#' \
-e '/^oracle.install.db.config.starterdb.type=/s#=.*$#=GENERAL_PURPOSE#' \
-e '/^oracle\.install\.db\.config\.starterdb\.characterSet=/s#=.*$#=ZHS16GBK#' \
-e '/^DECLINE_SECURITY_UPDATES=/s#=.*$#=true#' \
/home/oracle/db_install.rsp

无需修改 netca.rsp
修改 dbca.rsp

1
2
3
4
5
6
7
8
9
10
11
sed -i \
-e '/^gdbName=/s#=.*$#=orcl#' \
-e '/^sid=/s#=.*$#=orcl#' \
-e '/^createAsContainerDatabase=/s#=.*$#=true#' \
-e '/^numberOfPDBs=/s#=.*$#=1#' \
-e '/^pdbName=/s#=.*$#=pdborcl#' \
-e '/^templateName=/s#=.*$#=General_Purpose.dbc#' \
-e '/^pdbAdminPassword=/s#=.*$#=P@sswo2d#' \
-e '/^sysPassword=/s#=.*$#=P@sswo2d#' \
-e '/^systemPassword=/s#=.*$#=P@sswo2d#' \
/home/oracle/dbca.rsp

安装 oracle 软件

1
2
cd /home/oracle/database
./runInstaller -silent -responseFile /home/oracle/db_install.rsp -ignorePrereq

安装成功后,系统提示需要在 root 下执行两个脚本

1
2
/opt/oracle/oraInventory/orainstRoot.sh
/opt/oracle/app/product/12.2.0/root.sh

配置监听

1
netca /silent /responseFile /home/oracle/netca.rsp

配置成功后,监听启动,查看监听状态

1
lsnrctl status

创建数据库

1
dbca -silent -createDatabase -responseFile /home/oracle/dbca.rsp

查看屏幕输出的创建进度
简单使用
登陆数据库,切换到 pdb 数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[oracle@oracle ~]$ rlwrap sqlplus / as sysdba
SQL*Plus: Release 12.2.0.1.0 Production on 星期一 6月 25 14:41:16 2018
Copyright (c) 1982, 2016, Oracle. All rights reserved.
连接到:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
SQL> alter session set container=pdborcl;
会话已更改。
SQL> show con_name
CON_NAME
------------------------------
PDBORCL
SQL> select file_name from dba_data_files;
FILE_NAME
--------------------------------------------------------------------------------
/opt/oracle/app/oradata/orcl/pdborcl/system01.dbf
/opt/oracle/app/oradata/orcl/pdborcl/sysaux01.dbf
/opt/oracle/app/oradata/orcl/pdborcl/undotbs01.dbf
/opt/oracle/app/oradata/orcl/pdborcl/users01.dbf
SQL>

最后,将localhost替换为0.0.0.0。

1
2
3
4
5
6
7
8
9
10
11
12
vim $ORACLE_HOME/network/admin/listener.ora

# listener.ora Network Configuration File: /opt/oracle/app/product/12.2.0/network/admin/listener.ora
# Generated by Oracle configuration tools.

LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 0.0.0.0)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)

配置Oracle开机自启

添加启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[oracle@oracle ~]$ vim /etc/systemd/system/oracle-rdbms.service
# /etc/systemd/system/oracle-rdbms.service
# Invoking Oracle scripts to start/shutdown Instances defined in /etc/oratab
# and starts Listener

[Unit]
Description=Oracle Database(s) and Listener
Requires=network.target

[Service]
Type=forking
Restart=no
ExecStart=/opt/oracle/app/product/12.2.0/bin/dbstart /opt/oracle/app/product/12.2.0
ExecStop=/opt/oracle/app/product/12.2.0/bin/dbshut /opt/oracle/app/product/12.2.0
User=oracle

[Install]
WantedBy=multi-user.target

修改 /etc/oratab 文件最后一行的N改成Y。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[oracle@oracle ~]$ vim /etc/oratab
#



# This file is used by ORACLE utilities. It is created by root.sh
# and updated by either Database Configuration Assistant while creating
# a database or ASM Configuration Assistant while creating ASM instance.

# A colon, ':', is used as the field terminator. A new line terminates
# the entry. Lines beginning with a pound sign, '#', are comments.
#
# Entries are of the form:
# $ORACLE_SID:$ORACLE_HOME:<N|Y>:
#
# The first and second fields are the system identifier and home
# directory of the database respectively. The third field indicates
# to the dbstart utility that the database should , "Y", or should not,
# "N", be brought up at system boot time.
#
# Multiple entries with the same $ORACLE_SID are not allowed.
#
#
orcl:/opt/oracle/app/product/12.2.0:Y

开启关闭em

开启em

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[oracle@oracle ~]$ rlwrap sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on Sat Dec 15 09:09:47 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

SP2-0136: DEFINE requires an equal sign (=)
SQL> exec DBMS_XDB_CONFIG.SETHTTPPORT(5500);

PL/SQL procedure successfully completed.

SQL>

关闭em

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[oracle@oracle ~]$ rlwrap sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on Sat Dec 15 09:11:28 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

SP2-0136: DEFINE requires an equal sign (=)
SQL> exec DBMS_XDB_CONFIG.SETHTTPPORT(0);

PL/SQL procedure successfully completed.

SQL>

python 介绍

python的创始人为吉多·范罗苏姆(Guido van Rossum)。1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承。

Python 是一款易于学习且功能强大的编程语言。 它具有高效率的数据结构,能够简单又有效地实现面向对象编程。Python 简洁的语法与动态输入之特性,加之其解释性语言的本质,使得它成为一种在多种领域与绝大多数平台都能进行脚本编写与应用快速开发工作的理想语言。

Hello World 程序

案例(保存为 hello.py):

1
2
3
#!/usr/bin/env python3

print ("Hello World!")

给予可执行权限chmod +x HelloWorld.py
这样执行: ./HelloWorld.py 即可

变量

如果只使用字面常量很快就会让人感到无聊——我们需要一些能够存储任何信息并且也能操纵它们的方式。这便是 变量(Veriables) 登场的时刻。正如其名字所述那般,变量的值是可以变化的,也就是说,你可以用变量来存储任何东西。变量只是你的计算机内存中用以存储信息的一部分。与文字常量不同,你需要通过一些方式来访问这些变量,因此,你需要为它们命名。

标识符命名

变量是标识符的一个例子。标识符(Identifiers) 是为 某些东西 提供的给定名称。在你命名标识符时,你需要遵守以下规则:

第一个字符必须是字母表中的字母(大写 ASCII 字符或小写 ASCII 字符或 Unicode 字符)或下划线(_)。
标识符的其它部分可以由字符(大写 ASCII 字符或小写 ASCII 字符或 Unicode 字符)、下划线(_)、数字(0~9)组成。
标识符名称区分大小写。例如,myname 和 myName 并不等同。要注意到前者是小写字母 n 而后者是大写字母 N。
有效 的标识符名称可以是 i 或 name_2_3 ,无效 的标识符名称可能是 2things,this is spaced out,my-name 和 >a1b2_c3。

用户输入

1
2
3
4
#!/usr/bin/env python3

name = input("What is your name?")
print ("Hello " + name )

输入密码时,如果想要不可见,需要利用getpass 模块中的 getpass方法,即:

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3

import getpass

# 将用户输入的内容赋值给 name 变量
pwd = getpass.getpass("请输入密码:")

# 打印输入的内容
print(pwd)

函数

函数(Functions)是指可重复使用的程序片段。它们允许你为某个代码块赋予名字,允许你通过这一特殊的名字在你的程序任何地方来运行代码块,并可重复任何次数。这就是所谓的调用(Calling)函数。我们已经使用过了许多内置的函数,例如 len 和 range。

函数概念可能是在任何复杂的软件(无论使用的是何种编程语言)中最重要的构建块,所以我们接下来将在本章中探讨有关函数的各个方面。

函数可以通过关键字 def 来定义。这一关键字后跟一个函数的标识符名称,再跟一对圆括号,其中可以包括一些变量的名称,再以冒号结尾,结束这一行。随后而来的语句块是函数的一部分。下面的案例将会展示出这其实非常简单:

案例(保存为 function1.py):

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3

def say_hello():
# 该块属于这一函数
print('hello world')
# 函数结束

say_hello() # 调用函数
say_hello() # 再次调用函数
1
2
3
4
5
输出:

$ python3 function1.py
hello world
hello world

它是如何工作的

我们以上文解释过的方式定义名为 say_hello 的函数。这个函数不使用参数,因此在括号中没有声明变量。函数的参数只是输入到函数之中,以便我可以传递不同的值给它,并获得相应的结果。

要注意到我们可以两次调用相同的函数,这意味着我们不必重新把代码再写一次。

函数参数

函数可以获取参数,这个参数的值由你所提供,借此,函数便可以利用这些值来做一些事情。这些参数与变量类似,这些变量的值在我们调用函数时已被定义,且在函数运行时均已赋值完成。

函数中的参数通过将其放置在用以定义函数的一对圆括号中指定,并通过逗号予以分隔。当我们调用函数时,我们以同样的形式提供需要的值。要注意在此使用的术语——在定义函数时给定的名称称作“形参”(Parameters),在调用函数时你所提供给函数的值称作“实参”(Arguments)。

案例(保存为 function_param.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3

def print_max(a, b):
if a > b:
print(a, 'is maximum')
elif a == b:
print(a, 'is equal to', b)
else:
print(b, 'is maximum')

# 直接传递字面值
print_max(3, 4)

x = 5
y = 7

# 以参数的形式传递变量
print_max(x, y)

输出:

1
2
3
$ python function_param.py
4 is maximum
7 is maximum

它是如何工作的

在这里,我们将函数命名为 print_max 并使用两个参数分别称作 a 和 b。我们使用一个简单的 if…else 语句来找出更大的那个数,并将它打印出来。

第一次调用函数 print_max 时,我们以实参的形式直接向函数提供这一数字。在第二次调用时,我们将变量作为实参来调用函数。print_max(x, y) 将使得实参 x 的值将被赋值给形参 a,而实参 y 的值将被赋值给形参 b。在两次调用中,print_max 都以相同的方式工作。

局部变量

当你在一个函数的定义中声明变量时,它们不会以任何方式与身处函数之外但具有相同名称的变量产生关系,也就是说,这些变量名只存在于函数这一局部(Local)。这被称为变量的作用域(Scope)。所有变量的作用域是它们被定义的块,从定义它们的名字的定义点开始。

案例(保存为 function_local.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3

x = 50


def func(x):
print('x is', x)
x = 2
print('Changed local x to', x)


func(x)
print('x is still', x)

输出:

1
2
3
4
$ python function_local.py
x is 50
Changed local x to 2
x is still 50

它是如何工作的

当我们第一次打印出存在于函数块的第一行的名为 x 的值时,Python 使用的是在函数声明之上的主代码块中声明的这一参数的值。

接着,我们将值 2 赋值给 x。x 是我们这一函数的局部变量。因此,当我们改变函数中 x 的值的时候,主代码块中的 x 则不会受到影响。

随着最后一句 print 语句,我们展示出主代码块中定义的 x 的值,由此确认它实际上不受先前调用的函数中的局部变量的影响。

global 语句

如果你想给一个在程序顶层的变量赋值(也就是说它不存在于任何作用域中,无论是函数还是类),那么你必须告诉 Python 这一变量并非局部的,而是全局(Global)的。我们需要通过 global 语句来完成这件事。因为在不使用 global 语句的情况下,不可能为一个定义于函数之外的变量赋值。

你可以使用定义于函数之外的变量的值(假设函数中没有具有相同名字的变量)。然而,这种方式不会受到鼓励而且应该避免,因为它对于程序的读者来说是含糊不清的,无法弄清楚变量的定义究竟在哪。而通过使用 global 语句便可清楚看出这一变量是在最外边的代码块中定义的。

案例(保存为 function_global.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3

x = 50


def func():
global x

print('x is', x)
x = 2
print('Changed global x to', x)


func()
print('Value of x is', x)

输出:

1
2
3
4
$ python function_global.py
x is 50
Changed global x to 2
Value of x is 2

它是如何工作的

global 语句用以声明 x 是一个全局变量——因此,当我们在函数中为 x 进行赋值时,这一改动将影响到我们在主代码块中使用的 x 的值。

你可以在同一句 global 语句中指定不止一个的全局变量,例如 global x, y, z。

默认参数值

对于一些函数来说,你可能为希望使一些参数可选并使用默认的值,以避免用户不想为他们提供值的情况。默认参数值可以有效帮助解决这一情况。你可以通过在函数定义时附加一个赋值运算符(=)来为参数指定默认参数值。

要注意到,默认参数值应该是常数。更确切地说,默认参数值应该是不可变的——这将在后面的章节中予以更详细的解释。就目前来说,只要记住就行了。

案例(保存为 function_default.py):

1
2
3
4
5
6
7
#!/usr/bin/env python3

def say(message, times=1):
print(message * times)

say('Hello')
say('World', 5)

输出:

1
2
3
4
$ python function_default.py
Hello
WorldWorldWorldWorldWorld

它是如何工作的

名为 say 的函数用以按照给定的次数打印一串字符串。如果我们没有提供一个数值,则将按照默认设置,只打印一次字符串。我们通过为参数 times 指定默认参数值 1 来实现这一点。

在第一次使用 say 时,我们只提供字符串因而函数只会将这个字符串打印一次。在第二次使用 say 时,我们既提供了字符串,同时也提供了一个参数 5,声明我们希望说(Say)这个字符串五次。

注意

只有那些位于参数列表末尾的参数才能被赋予默认参数值,意即在函数的参数列表中拥有默认参数值的参数不能位于没有默认参数值的参数之前。

这是因为值是按参数所处的位置依次分配的。举例来说,def func(a, b=5) 是有效的,但 def func(a=5, b) 是无效的。

关键字参数

如果你有一些具有许多参数的函数,而你又希望只对其中的一些进行指定,那么你可以通过命名它们来给这些参数赋值——这就是关键字参数(Keyword Arguments)——我们使用命名(关键字)而非位置(一直以来我们所使用的方式)来指定函数中的参数。

这样做有两大优点——其一,我们不再需要考虑参数的顺序,函数的使用将更加容易。其二,我们可以只对那些我们希望赋予的参数以赋值,只要其它的参数都具有默认参数值。

案例(保存为 function_keyword.py):

1
2
3
4
5
6
7
8
#!/usr/bin/env python3

def func(a, b=5, c=10):
print('a is', a, 'and b is', b, 'and c is', c)

func(3, 7)
func(25, c=24)
func(c=50, a=100)

输出:

1
2
3
4
$ python function_keyword.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50

它是如何工作的

名为 func 的函数有一个没有默认参数值的参数,后跟两个各自带有默认参数值的参数。

在第一次调用函数时,func(3, 7),参数 a 获得了值 3,参数 b 获得了值 7,而 c 获得了默认参数值 10。

在第二次调用函数时,func(25, c=24),由于其所处的位置,变量 a 首先获得了值 25。然后,由于命名——即关键字参数——指定,变量 c 获得了值 24。变量 b 获得默认参数值 5。

在第三次调用函数时,func(c=50, a=100),我们全部使用关键字参数来指定值。在这里要注意到,尽管 a 在 c 之前定义,但我们还是我们在变量 a 之前指定了变量 c。

可变参数

有时你可能想定义的函数里面能够有任意数量的变量,也就是参数数量是可变的,这可以通过使用星号来实现(将下方案例保存为 function_varargs.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python3

def total(a=5, *numbers, **phonebook):
print('a', a)

#遍历元组中的所有项目
for single_item in numbers:
print('single_item', single_item)

#遍历字典中的所有项目
for first_part, second_part in phonebook.items():
print(first_part,second_part)

print(total(10,1,2,3,Jack=1123,John=2231,Inge=1560))

输出:

1
2
3
4
5
6
7
8
9
$ python function_varargs.py
a 10
single_item 1
single_item 2
single_item 3
Inge 1560
John 2231
Jack 1123
None

它是如何工作的

当我们声明一个诸如 *param 的星号参数时,从此处开始直到结束的所有位置参数(Positional Arguments)都将被收集并汇集成一个称为“param”的元组(Tuple)。

类似地,当我们声明一个诸如 **param 的双星号参数时,从此处开始直至结束的所有关键字参数都将被收集并汇集成一个名为 param 的字典(Dictionary)。

我们将在后面的章节探索有关元组与字典的更多内容。

return 语句

return 语句用于从函数中返回,也就是中断函数。我们也可以选择在中断函数时从函数中返回一个值。

案例(保存为 function_return.py):

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3

def maximum(x, y):
if x > y:
return x
elif x == y:
return 'The numbers are equal'
else:
return y

print(maximum(2, 3))

输出:

1
2
$ python function_return.py
3

它是如何工作的

maximum 函数将会返回参数中的最大值,在本例中是提供给函数的数值。它使用一套简单的 if…else 语句来找到较大的那个值并将其返回。

要注意到如果 return 语句没有搭配任何一个值则代表着 返回 None。None 在 Python 中一个特殊的类型,代表着虚无。举个例子, 它用于指示一个变量没有值,如果有值则它的值便是 None(虚无)。

每一个函数都在其末尾隐含了一句 return None,除非你写了你自己的 return 语句。你可以运行 print(some_function()),其中 some_function 函数不使用 return 语句,就像这样:

1
2
def some_function():
pass

Python 中的 pass 语句用于指示一个没有内容的语句块。

提示:有一个名为 max 的内置函数已经实现了“找到最大数”这一功能,所以尽可能地使用这一内置函数。

DocStrings

Python 有一个甚是优美的功能称作文档字符串(Documentation Strings),在称呼它时通常会使用另一个短一些的名字docstrings。DocStrings 是一款你应当使用的重要工具,它能够帮助你更好地记录程序并让其更加易于理解。令人惊叹的是,当程序实际运行时,我们甚至可以通过一个函数来获取文档!

案例(保存为 function_docstring.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3

def print_max(x, y):
'''Prints the maximum of two numbers.打印两个数值中的最大数。

The two values must be integers.这两个数都应该是整数'''
# 如果可能,将其转换至整数类型
x = int(x)
y = int(y)

if x > y:
print(x, 'is maximum')
else:
print(y, 'is maximum')

print_max(3, 5)
print(print_max.__doc__)

输出:

1
2
3
4
5
$ python function_docstring.py
5 is maximum
Prints the maximum of two numbers.

The two values must be integers.

它是如何工作的

函数的第一行逻辑行中的字符串是该函数的 文档字符串(DocString)。这里要注意文档字符串也适用于后面相关章节将提到的模块(Modules)与类(Class) 。

该文档字符串所约定的是一串多行字符串,其中第一行以某一大写字母开始,以句号结束。第二行为空行,后跟的第三行开始是任何详细的解释说明。5在此强烈建议你在你所有重要功能的所有文档字符串中都遵循这一约定。

我们可以通过使用函数的 __doc__(注意其中的双下划綫)属性(属于函数的名称)来获取函数 print_max 的文档字符串属性。只消记住 Python 将所有东西都视为一个对象,这其中自然包括函数。我们将在后面的类(Class)章节讨论有关对象的更多细节。

如果你曾使用过 Python 的 help() 函数,那么你应该已经了解了文档字符串的用途了。它所做的便是获取函数的 doc 属性并以一种整洁的方式将其呈现给你。你可以在上方的函数中尝试一下——只需在程序中包含 help(print_max) 就行了。要记住你可以通过按下 q 键来退出 help。

自动化工具可以以这种方式检索你的程序中的文档。因此,我强烈推荐你为你编写的所有重要的函数配以文档字符串。你的 Python 发行版中附带的 pydoc 命令与 help() 使用文档字符串的方式类似。

模块

在上一章,你已经了解了如何在你的程序中通过定义一次函数工作来重用代码。那么如果你想在你所编写的别的程序中重用一些函数的话,应该怎么办?正如你可能想象到的那样,答案是模块(Modules)。

编写模块有很多种方法,其中最简单的一种便是创建一个包含函数与变量、以 .py 为后缀的文件。

另一种方法是使用撰写 Python 解释器本身的本地语言来编写模块。举例来说,你可以使用 C 语言来撰写 Python 模块,并且在编译后,你可以通过标准 Python 解释器在你的 Python 代码中使用它们。

一个模块可以被其它程序导入并运用其功能。我们在使用 Python 标准库的功能时也同样如此。首先,我们要了解如何使用标准库模块。

案例 (保存为 module_using_sys.py):

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3

import sys

print('The command line arguments are:')
for i in sys.argv:
print(i)

print('\n\nThe PYTHONPATH is', sys.path, '\n')

输出:

1
2
3
4
5
6
7
8
9
10
11
12
$ python module_using_sys.py we are arguments
The command line arguments are:
module_using_sys.py
we
are
arguments


The PYTHONPATH is ['/tmp/py',
# many entries here, not shown here
'/Library/Python/2.7/site-packages',
'/usr/local/lib/python2.7/site-packages']

它是如何工作的

首先,我们通过 import 语句导入 sys 模块。基本上,这句代码将转化为我们告诉 Python 我们希望使用这一模块。sys 模块包含了与 Python 解释器及其环境相关的功能,也就是所谓的系统功能(system)。

当 Python 运行 import sys 这一语句时,它会开始寻找 sys 模块。在这一案例中,由于其是一个内置模块,因此 Python 知道应该在哪里找到它。

如果它不是一个已编译好的模块,即用 Python 编写的模块,那么 Python 解释器将从它的 sys.path 变量所提供的目录中进行搜索。如果找到了对应模块,则该模块中的语句将在开始运行,并能够为你所使用。在这里需要注意的是,初始化工作只需在我们第一次导入模块时完成。

sys 模块中的 argv 变量通过使用点号予以指明,也就是 sys.argv 这样的形式。它清晰地表明了这一名称是 sys 模块的一部分。这一处理方式的另一个优点是这个名称不会与你程序中的其它任何一个 argv 变量冲突。

sys.argv 变量是一系列字符串的列表(List)(列表将在后面的章节予以详细解释)。具体而言,sys.argv 包含了命令行参数(Command Line Arguments)这一列表,也就是使用命令行传递给你的程序的参数。

如果你正在使用一款 IDE 来编写并运行这些程序,请在程序菜单中寻找相关指定命令行参数的选项。

在这里,当我们运行 python module_using_sys.py we are arguments 时,我们通过 python 命令来运行 module_using_sys.py 模块,后面的内容则是传递给程序的参数。 Python 将命令行参数存储在 sys.argv 变量中供我们使用。

在这里要记住的是,运行的脚本名称在 sys.argv 的列表中总会位列第一。因此,在这一案例中我们将会有如下对应关系:’module_using_sys.py’ 对应 sys.argv[0],’we’ 对应 sys.argv[1],’are’ 对应 sys.argv[2],’arguments’ 对应 sys.argv[3]。要注意到 Python 从 0 开始计数,而不是 1。

sys.path 内包含了导入模块的字典名称列表。你能观察到 sys.path 的第一段字符串是空的——这一空字符串代表当前目录也是 sys.path 的一部分,它与 PYTHONPATH 环境“储在 sys.argv 变量中供我们使用。

在这里要记住的是,运行的脚本名称在 sys.argv 的列表中总会位列第一。因此,在这一案例中我们将会有如下对应关系:’module_using_sys.py’ 对应 sys.argv[0],’we’ 对应 sys.argv[1],’are’ 对应 sys.argv[2],’arguments’ 对应 sys.argv[3]。要注意到 Python 从 0 开始计数,而不是 1。

sys.path 内包含了导入模块的字典名称列表。你能观察到 sys.path 的第一段字符串是空的——这一空字符串代表当前目录也是 sys.path 的一部分,它与 PYTHONPATH 环境变量等同。这意味着你可以直接导入位于当前目录的模块。否则,你必须将你的模块放置在 sys.path 内所列出的目录中。

另外要注意的是当前目录指的是程序启动的目录。你可以通过运行 import os; print(os.getcwd()) 来查看你的程序目前所处在的目录。

一、分区提示未对齐

[root@lab8106 ceph]# parted /dev/sdd 
GNU Parted 3.1
Using /dev/sdd
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p                                                                
Model: SEAGATE ST3300657SS (scsi)
Disk /dev/sdd: 300GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start  End  Size  File system  Name  Flags

(parted) mkpart primary 0 100%                                            
Warning: The resulting partition is not properly aligned for best performance.
Ignore/Cancel?
Warning: The resulting partition is not properly aligned for best performance.

分区的时候提示不是最好的模式,这个是因为没有对齐的原因,在默认情况下我都是
mkpart primary 1 100%
这个一般都是对齐的,但是最近遇到一个做了raid5的怎么都提示不行,然后搜索了下资料,这个地方是要计算下比较好的
二、通过计算分区
获取磁盘的几个参数(这里是软raid)

# cat /sys/block/md127/queue/optimal_io_size
3670016
# cat /sys/block/md127/queue/minimum_io_size
524288
# cat /sys/block/md127/alignment_offset
0
# cat /sys/block/md127/queue/physical_block_size
512

optimal_io_size 加上 alignment_offset 的和 然后除以 physical_block_size
在这个环境下是:
(3670016 + 0) / 512 = 7168
那么分区的时候命令就应该是

mkpart primary 7168s 100%

如果上面的顺利的完成检查一下 (‘1’是分区的编号):

(parted) align-check optimal 1
1 aligned

这个是正常的结果,如果没对齐就会是

(parted) align-check optimal 1
1 not aligned

三、其他情况
默认情况下直接用下列的分区参数就可以,出现提示再用上面的计算,总之最后align-check 验证下

mkpart primary 1 100%

四、相关文章
How to align partitions for best performance using parted

nginx
很多人会提出这样的问题:
能不能够将 Ceph journal 分区从一个磁盘替换到另一个磁盘?
怎样替换 Ceph 的 journal 分区?
有两种方法来修改Ceph的journal:
创建一个journal分区,在上面创建一个新的journal
转移已经存在的journal分区到新的分区上,这个适合整盘替换
Ceph 的journal是基于事务的日志,所以正确的下刷journal数据,然后重新创建journal并不会引起数据丢失,因为在下刷journal的数据的时候,osd是停止的,一旦数据下刷后,这个journal是不会再有新的脏数据进来的
第一种方法
在开始处理前,最开始要设置OSD状态为noout

[root@lab8106 ~]# ceph osd set noout
set noout

停止需要替换journal的osd(这里是osd.1)

[root@lab8106 ~]# systemctl stop ceph-osd@1

我的版本是jewel的,如果是hammer版本,就使用 /etc/init.d/ceph stop osd.1
下刷journal到osd,使用 -i 指定需要替换journal的 osd的编号

[root@lab8106 ~]# ceph-osd -i 1 --flush-journal
SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 01 cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
SG_IO: bad/missing sense data, sb[]: 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 01 cf 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2016-07-26 22:47:20.185292 7fc54a6c3800 -1 flushed journal /var/lib/ceph/osd/ceph-1/journal for object store /var/lib/ceph/osd/ceph-1

创建一个新的journal
删除原来的journal

[root@lab8106 ~]# ll /var/lib/ceph/osd/ceph-1/journal
lrwxrwxrwx 1 ceph ceph 58 Jul 25 09:25 /var/lib/ceph/osd/ceph-1/journal -> /dev/disk/by-partuuid/872f8b40-a750-4be3-9150-033b990553f7
[root@lab8106 ~]# rm -rf /var/lib/ceph/osd/ceph-1/journal

准备一个新的分区
我的环境准备使用/dev/sdd1,分区大小为10G,这个注意磁盘大小比参数设置的要大一点即可

[root@lab8106 ~]# ls -l /dev/disk/by-partuuid/
total 0
lrwxrwxrwx 1 root root 10 Jul 25 14:25 4766ce93-a476-4e97-9aac-894d461b367e -> ../../sdb2
lrwxrwxrwx 1 root root 10 Jul 26 22:51 5bb48687-6be6-4aef-82f6-5af822c3fad8 -> ../../sdd1
lrwxrwxrwx 1 root root 10 Jul 26 22:47 872f8b40-a750-4be3-9150-033b990553f7 -> ../../sdc2

我的新的journal的uuid的路径为/dev/disk/by-partuuid/5bb48687-6be6-4aef-82f6-5af822c3fad8
将这个磁盘的分区链接到原始路径

[root@lab8106 ~]# ln -s /dev/disk/by-partuuid/5bb48687-6be6-4aef-82f6-5af822c3fad8 /var/lib/ceph/osd/ceph-1/journal
[root@lab8106 ~]# chown ceph:ceph /var/lib/ceph/osd/ceph-1/journal
[root@lab8106 ~]# echo 5bb48687-6be6-4aef-82f6-5af822c3fad8 > /var/lib/ceph/osd/ceph-1/journal_uuid

创建journal

[root@lab8106 ~]# ceph-osd -i 1 --mkjournal

启动进程

[root@lab8106 ~]# systemctl restart ceph-osd@1

去除noout的标记

[root@lab8106 ~]# ceph osd unset noout

启动后检查集群的状态
第二种方法
这个属于备份和转移分区表的方法
首先进行上面方法的停进程,下刷journal
备份需要替换journal的分区表

[root@lab8106 ~]# sgdisk --backup=/tmp/backup_journal_sdd /dev/sdd

还原分区表

[root@lab8106 ~]# sgdisk --load-backup=/tmp/backup_journal_sde /dev/sde
[root@lab8106 ~]# parted -s /dev/sde print

新的journal磁盘现在跟老的journal的磁盘的分区表一样的了。这意味着新的分区的UUID和老的相同的。如果选择的是这种备份还原分布的方法,那么journal的那个软连接是不需要进行修改的,因为两个磁盘的uuid是一样的,所以需要注意将老的磁盘拔掉或者清理掉分区,以免冲突
在做完这个以后同样跟上面的方法一样需要重建journal
创建journal

[root@lab8106 ~]# chown ceph:ceph /var/lib/ceph/osd/ceph-1/journal
[root@lab8106 ~]# ceph-osd -i 1 --mkjournal

启动进程

[root@lab8106 ~]# systemctl restart ceph-osd@1

去除noout的标记

[root@lab8106 ~]# ceph osd unset noout