秦音

个人博客


  • 首页

  • 标签

  • 分类

  • 归档

Elasticsearch快照备份与还原

发表于 2020-05-22 | 分类于 Elasticsearch

使用snapshot实现es数据备份、还原与迁移

1.snapshot介绍

   snapshot api是Elasticsearch用于对数据进行备份和恢复的一组api接口,可以通过snapshot api进行跨集群的数据迁移,原理就是从源ES集群创建数据快照,然后在目标ES集群中进行恢复。需要注意ES的版本问题:
   1)目标ES集群的主版本号(如5.6.4中的5为主版本号)要大于等于源ES集群的主版本号;
   2)1.x版本的集群创建的快照不能在5.x版本中恢复;

2.数据备份

2.1 源ES集群中创建备份还原目录:

1
2
3
mkdir es_bak
# 为了避免权限问题,直接修改/opt/es_bak权限为777
chmod 777 /opt/es_bak

2.2 注册备份还原目录
   修改elasticsearch.yml,添加如下配置path.repo: ['/opt/elasticsearch/es_bak']
   即指定备份还原目录路径,然后重启elasticsearch
2.3 注册备份还原仓库(仓库名称为my_backup)
PUT http://地址:9200/_snapshot/my_backup/
参数:

1
2
3
4
5
6
7
8
9
{
"type": "fs",
"settings": {
"location": "/opt/elasticsearch/es_bak",
"max_snapshot_bytes_per_sec" : "50mb",
"max_restore_bytes_per_sec" : "50mb",
"compress" : true
}
}


查看仓库情况:GET http://地址:9200/_snapshot/my_backup/_all

这里执行完之后/opt/elasticsearch/es_bak目录下还什么数据都没有.
一个repository仓库可以包含多份快照文件,repository主要有一下几种类型:

fs: 共享文件系统,将快照文件存放于文件系统中
url: 指定文件系统的URL路径,支持协议:http,https,ftp,file,jar
s3: AWS S3对象存储,快照存放于S3中,以插件形式支持
hdfs: 快照存放于hdfs中,以插件形式支持
cos: 快照存放于腾讯云COS对象存储中,以插件形式支持

2.4 备份数据
在创建的my_backup仓库下备份数据,备份的名称为:yq
PUT http://地址:9200/_snapshot/my_backup/yq
指定备份的索引逗号分隔,不传默认备份所有索引

1
2
3
{
"indices": "index1,index2"
}

?wait_for_completion=true 等待备份完后再返回
参数 wait_for_completion 决定请求是在快照初始化后立即返回(默认),还是等快照创建完成之后再返回。

备份完成后可以看到备份状态,该yq备份已经完成,且能查看所备份的索引值:

备份完数据后就会在/opt/es_bak目录下生成备份的元数据:

3.数据还原

将步骤2中生成的备份元数据(即/opt/elasticsearch/es_bak目录下的所有文件)拷贝到要还原的目标机器的备份还原目录下。注意:在目标机器上2.1、2.2、2.3三个步骤同样需要进行操作,只是仓库的路径不比与源es仓库路径一样,根据个人情况而定。
元数据文件拷贝到目标机器后,在需要还原的机器上执行POST请求:
POST http://地址:9200/_snapshot/my_backup/yq/_restore

然后在目标机器上查看es中是否还原该索引数据

4.数据迁移

单节点情况下,数据迁移与数据还原类似,都是将元数据文件拷贝然后还原即可。

参考链接:
Elasticsearch快照备份与还原
es数据备份和恢复
ElasticSearch集群数据迁移备份方案

实际操作过程中所发出的请求记录:

1
2
3
4
5
6
7
8
PUT http://172.16.16.219:9200/_snapshot/my_backup/yq
GET http://172.16.16.219:9200/_snapshot/my_backup/_all
DELETE http://172.16.16.219:9200/_snapshot/my_backup/yq
PUT http://172.16.16.219:9200/_snapshot/my_backup/yq?wait_for_completion=true
{
"indices": "20200508.leadercase"
}
POST http://192.168.0.156:9200/_snapshot/my_backup/yq/_restore

Linux常用软件安装

发表于 2020-05-20 | 分类于 Linux

1.jdk安装

本地压缩包安装

1)将jdk的centos7 jar解压到指定位置

1
tar -zxvf jdk-8u211-linux-x64.tar.gz

2)修改环境变量:vi /etc/profile

1
2
3
4
5
#java environment
export JAVA_HOME=/usr/java/jdk1.8.0_211
export JRE_HOME=$JAVA_HOME/jre
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

3)重启系统文件:source /etc/profile
这种直接解压压缩包的安装方式卸载也极为简单:首先删除解压的文件夹jdk1.8.0_211,然后把环境变量中的配置删除,重启系统文件即可卸载该jdk

本地rpm安装

即将本地的rpm移动到服务器上安装,如果rpm只是jdk的rpm,而没有包含其所依赖的,则需要将jdk所依赖的rpm一起拷贝上去。
然后一个一个将子类安装好后,最后才能安装成功jdk。其中涉及到很多子类依赖yum安装步骤,极其复杂。
即只针对没有网络,且没有其他安装步骤时使用。


上面的截图只是其中的一部分,还有很多其他子rpm也是按照这个步骤安装。

2.linux中Expect工具的安装

Expect是一个用来处理交互的工具,通常用于需要手动输入数据的场景,可在脚本中使用expect来实现自动化。

安装
首先查看系统中是否有安装expect。

1
whereis expect

Expect工具是依赖tcl的,所以也需要安装tcl。

首先下载并安装tcl,这里安装8.4.19版本。

1
2
3
4
5
wget https://sourceforge.net/projects/tcl/files/Tcl/8.4.19/tcl8.4.19-src.tar.gz
tar zxvf tcl8.4.19-src.tar.gz
cd tcl8.4.19/unix && ./configure
make
make install

然后下载expect并安装。

1
2
3
4
5
6
7
wget http://sourceforge.net/projects/expect/files/Expect/5.45/expect5.45.tar.gz
tar zxvf expect5.45.tar.gz
cd expect5.45
./configure --with-tcl=/usr/local/lib --with-tclinclude=../tcl8.4.19/generic
make
make install
ln -s /usr/local/bin/expect /usr/bin/expect

安装完成之后运行expect命令,查看是否安装成功。

1
2
expect
expect1.1>

expect的基本操作:
Expect脚本中常用的命令包括spawn, expect, send, interact等。

spawn:该命令用于启动一个子进程,执行后续命令;

expect:该命令从进程接受字符串,如果接受的字符串和期待的字符串不匹配,则一直阻塞,直到匹配上或者等待超时才继续往下执行;

send:向进程发送字符串,与手动输入内容等效,通常字符串需要以’\r’结尾。

interact:该命令将控制权交给控制台,之后就可以进行人工操作了。通常用于使用脚本进行自动化登录之后再手动执行某些命令。如果脚本中没有这一条语句,脚本执行完将自动退出。

set timeout 30:设置超时时间timeout为30s,expect命令阻塞超时时会自动往下继续执行。将timeout配置为-1时表示expect一直阻塞直到与期待的字符串匹配上才继续往下执行。超时时间timeout默认为10s。

[lindex $argv n]:可以在脚本中使用该命令获取在脚本执行时传入的第n个参数。这里argv为传入的参数,另外argv为传入的参数,另外argc表示传入参数的个数,$argv0表示脚本名字。

另外我们也可以使用[lrange $argv sn en]命令获取第sn到第en个参数。
实例解析:这里我们写一个脚本,命名为restart_service.exp,该脚本先切换到指定账户,然后下载软件包到tomcat的webapps目录,然后重启tomcat服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/expect

set timeout -1

set user [lindex $argv 0]
set password [lindex $argv 1]
set cmd_prompt "# "

spawn su ${user}
expect ${cmd_prompt}
send "${password}\r"

expect ${cmd_prompt}
send "cd /opt/tomcat/webapps && wget http://host/path/to/package.war\r"
expect "100%"
# 直到wget下载任务打印出100%才表示软件包下载完成

expect ${cmd_prompt}
send "/opt/tomcat/bin/shutdown.sh\r"

expect ${cmd_prompt}
send "/opt/tomcat/bin/startup.sh\r"

expect eof
#interact

3.sshpass的安装使用

sshpass下载与安装
3.1 yum安装:

1
yum install sshpass

若yum安装不上,则用下面方法

1
2
3
4
5
https://sourceforge.net/projects/sshpass/files/
or
https://pan.baidu.com/s/1pLNxeLd
or
wget http://sourceforge.net/projects/sshpass/files/latest/download -O sshpass.tar.gz

3.2 下载后,解压,安装

1
2
3
4
5
tar -zxvf sshpass-1.06.tar.gz
cd sshpass-1.06
./configure
make
make install

3.3 使用命令

1
sshpass -p 123456(密码) scp /home/file.txt root@10.0.0.37:/home/copy

Linux常用命令

发表于 2020-05-14 | 分类于 linux

yum

修改yum的获取地址

即指定yum从哪个地址上下载指定软件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#备份原始yum相关配置文件
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
mv /etc/yum.repos.d/CentOS-Debuginfo.repo /etc/yum.repos.d/CentOS-Debuginfo.repo.bak
#添加文件,baseurl指定的就是目标yum路径
echo "#matthubin shell script generate this file
[aiidc-media]
name=aiidc-Media
baseurl=http://172.16.16.222/
gpgcheck=0
enabled=1" > /etc/yum.repos.d/aiidc.repo
#清除原来的yum缓存
yum clean all
yum makecache
#从指定路径中安装nginx
yum install nginx

注意:yum包管理工具支持centos,而apt-get包管理工具支持ubuntu。

rpm

查看当前rpm包的版本:

1
2
3
4
#查询哪个包里有nginx这个文件
yum list|grep nginx
#或
rpm -qa|grep 包名 (建议使用)

查看centos7.2系统本身所安装的yum依赖包: rpm -qa|grep yum
rpm -e如果删不掉可以试试 rpm -e --nodeps 文件名
卸载这些软件包:rpm -e yum-plugin-fastestmirror-1.1.31-34.el7.noarch --nodeps

unzip

linux下解压zip文件使用命令
用法:zip [参数] [打包后的文件名] [打包的目录路径]
路径可以是相对路径,也可以是绝对路径
如:

1
2
#将file.conf.zip解压到/data/bak 目录下
unzip file.conf.zip -d /data/bak

chmod、chown、chgrp文件权限操作

  Linux系统中文件或目录的访问权限分为只读,只写和可执行三种。文件被创建时,文件所有者自动拥有对该文件的读、写和可执行权限,以便于对文件的阅读和修改。用户也可根据需要把访问权限设置为需要的任何组合。
  有三种不同类型的用户可对文件或目录进行访问:文件所有者(属主),同组用户、其他用户。所有者一般是文件的创建者。所有者可以允许同组用户有权访问文件,还可以将文件的访问权限赋予系统中的其他用户。
  每一个文件或目录的访问权限都有三组,每组用三位表示,分别为文件属主的读、写和执行权限;与拥有者同组的用户的读、写和执行权限;系统中其他用户的读、写和执行权限。当用ls -l命令显示文件或目录的详细信息时,最左边的一列为文件的访问权限。例如:

1
2
-rw-r--r--. 1 root root      1207 5月  19 18:12 application.yml
drwxr-xr-x. 3 root root 18 4月 29 01:05 hanlp

  其中:r代表只读,w代表写,x代表可执行
  第一位为表示文件类型,如果这个字母是一个减号”-“,则说明该文件是一个普通文件.字母”d”表示该文件是一个目录,字母”d”,是dirtectory(目录)的缩写。(其他详细信息请参考:)。第一字段的后面9个字母表示文件的权限:前三个表示文件属主的权限,中间三个表示组用户权限,最后三个表示其他用户权限.

1.chmod 重新设定不同的访问权限

1.1 权限基本介绍
  修改文件夹及子文件夹权限命令:chmod -R 777 /opt/parse
  其中:-R:表示递归;
  777:最高位7是设置文件所有者访问权限,第二位是设置群组访问权限,最低位是设置其他人访问权限。其中每一位的权限用数字来表示。具体有这些权限:
  r(Read,读取,权限值为4):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目 录的权限。
  w(Write,写入,权限值为2):对文件而言,具有新增、修改文件内容的权限;对目录来说,具有删除、移动目录内文件的权限。
  x(eXecute,执行,权限值为1):对文件而言,具有执行文件的权限;对目录了来说该用户具有进入目录的权限。
  eg:当数字为7时,7用“rwx”表示:{4(r)+2(w)+1(x)=7}
  又如果数值为6,则用“rw-”表示:{4(r)+2(w)+0(x)=6},”-”表示不具备权限,这里表示不具备“执行”权限。
  当其他用户的访问权限为 “r–”,则数值为4+0+0=4
  简化理解:将rwx看成二进制数,如果有则用1表示,没有则有0表示,那么rwx则可以表示成为:111,而二进制的111就是7。
  故:如果文件所有者有“读”、“写”、“执行”权限,群组用户有“读”权限,其他用户有“读”权限,则对应的字母表示为”rwx r–r–”,对应的数字为744.一般都是最高位表示文件所有者权限值,第二位表示群组用户权限,最低位表示其他用户权限。
1.2 chmod包含字母和操作符表达式的文字设定法
  语法结构:chmod [who] [+|–|=] [mode] 文件名

操作对象who可是下述字母中的任一个或者它们的组合:

u 表示“用户(user)”,即文件或目录的所有者。
g 表示“同组(group)用户”,即与文件属主有相同组ID的所有用户。
o 表示“其他(others)用户”。
a 表示“所有(all)用户”。它是系统默认值。

操作符号可以是:

+ 添加某个权限。
– 取消某个权限。
= 赋予给定权限并取消其他所有权限(如果有的话)。
设置mode所表示的权限可用下述字母的任意组合:
r 可读。
w 可写。
x 可执行。
X 只有目标文件对某些用户是可执行的或该目标文件是目录时才追加x 属性。
s 在文件执行时把进程的属主或组ID置为该文件的文件属主。方式“u+s”设置文件的用户ID位,“g+s”设置组ID位。
t 保存程序的文本到交换设备上。
u 与文件属主拥有一样的权限。
g 与和文件属主同组的用户拥有一样的权限。
o 与其他用户拥有一样的权限。
-c : 若该档案权限确实已经更改,才显示其更改动作
-f : 若该档案权限无法被更改也不要显示错误讯息
-v : 显示权限变更的详细资料
-R : 对目前目录下的所有档案与子目录进行相同的权限变更(即以递回的方式逐个变更)
–help : 显示辅助说明
–version : 显示版本

文件名:

以空格分开的要改变权限的文件列表,支持通配符。在一个命令行中可给出多个权限方式,其间用逗号隔开。例如:chmod g+r,o+r example使同组和其他用户对文件example 有读权限。

1.3 包含数字的数字设定法
  数字表示的属性的含义:0表示没有权限,1表示可执行权限,2表示可写权限,4表示可读权限,然后将其相加。所以数字属性的格式应为3个从0到7的八进制数,其顺序是(u)(g)(o)。
  例如:如果想让某个文件的属主有“读/写”二种权限,需要把4(可读)+2(可写)=6(读/写)。

  数字设定法的一般形式为:chmod [mode] 文件名
例1:

1
2
3
$ chmod 644 mm.txt
$ ls –l
-rw-r--r-- 1 inin users 1155 Nov 5 11:22 mm.txt

即设定文件mm.txt的属性为:
文件属主(u)inin 拥有读、写权限
与文件属主同组人用户(g)拥有读权限
其他人(o) 拥有读权限

例2:

1
2
3
$ chmod 750 wch.txt
$ ls –l
-rwxr-x--- 1 inin users 44137 Nov 12 9:22 wchtxt

即设定wchtxt这个文件的属性为:
文件主本人(u)inin 可读/可写/可执行权
与文件主同组人(g) 可读/可执行权
其他人(o) 没有任何权限

2.chgrp 更改某个文件或目录所属的组

语法:chgrp [选项] group filename
参数:

-c或–changes 效果类似”-v”参数,但仅回报更改的部分。
-f或–quiet或–silent  不显示错误信息。
-h或–no-dereference  只对符号连接的文件作修改,而不更动其他任何相关文件。
-R或–recursive  递归处理,将指定目录下的所有文件及子目录一并处理。
-v或–verbose  显示指令执行过程。
–help  在线帮助。
–reference=<参考文件或目录>  把指定文件或目录的所属群组全部设成和参考文件或目录的所属群组相同。
–version  显示版本信息。

  该命令改变指定指定文件所属的用户组。其中group可以是用户组ID,也可以是/etc/group文件中用户组的组名。文件名是以空格分开的要改变属组的文件列表,支持通配符。如果用户不是该文件的属主或超级用户,则不能改变该文件的组。

  该命令的各选项含义为:–R 递归式地改变指定目录及其下的所有子目录和文件的属组。

3.chown 更改某个文件或目录的所有者

  功能:更改某个文件或目录的属主和属组。这个命令也很常用。例如root用户把自己的一个文件拷贝给用户yusi,为了让用户yusi能够存取这个文件,root用户应该把这个文件的属主设为yusi,否则,用户yusi无法存取这个文件。
语法:chown [选项] 用户或组 文件
说明:chown将指定文件的拥有者改为指定的用户或组。用户可以是用户名或用户ID。组可以是组名或组ID。文件是以空格分开的要改变权限的文件列表,支持通配符。
参数说明:

user : 新的档案拥有者的使用者 ID
group : 新的档案拥有者的使用者群体(group)
-c : 若该档案拥有者确实已经更改,才显示其更改动作
-f : 若该档案拥有者无法被更改也不要显示错误讯息
-h : 只对于连结(link)进行变更,而非该 link 真正指向的档案
-v : 显示拥有者变更的详细资料
-R : 对目前目录下的所有档案与子目录进行相同的拥有者变更(即以递回的方式逐个变更)
–help : 显示辅助说明
–version : 显示版本

例:

1
2
3
4
chown yusi yusi123.com(把文件yusi123.com的所有者改为yusi)
chown - R yusi.users /demo(把目录/demo及其下的所有文件和子目录的属主改成yusi,属组改成users)
chown qq /home/qq (把home目录下的qq目录的拥有者改为qq用户)
chown -R qq /home/qq (把home目录下的qq目录下的所有子文件的拥有者改为qq用户)

参考链接:Linux命令:修改文件权限命令chmod、chgrp、chown详解

scp文件传输

上传文件

1
2
3
4
5
6
#上传文件
scp test.txt root@107.172.27.254:/home
#上传目录
scp -r test root@107.172.27.254:/home
#从一个服务器上传到另一个服务器
scp root@192.168.1.104:/opt/xx.txt root@192.168.1.105:/opt/html/webs/

下载文件

#下载文件
scp root@107.172.27.254:/home/test.txt
#下载目录
scp -r root@107.172.27.254:/home/test
#下载多个文件
scp root@192.168.1.104:/opt/html/webs/\{index.css,json.js\}

Java对象不再使用时,为什么要赋值为null

发表于 2020-05-14 | 分类于 Java

   先来看看一段非常简单的代码:

1
2
3
4
5
6
7
public static void main(String[] args) {
if (true) {
byte[] placeHolder = new byte[64 * 1024 * 1024];
System.out.println(placeHolder.length / 1024);
}
System.gc();
}

   在if中实例化了一个数组placeHolder,然后在if的作用域外通过System.gc();手动触发了GC,其用意是回收placeHolder,因为placeHolder已经无法访问到了。来看看输出:

1
2
3
65536
[GC 68239K->65952K(125952K), 0.0014820 secs]
[Full GC 65952K->65881K(125952K), 0.0093860 secs]

   Full GC 65952K->65881K(125952K)代表的意思是:本次GC后,内存占用从65952K降到了65881K。意思其实是说GC没有将placeHolder回收掉,是不是不可思议?

   下面来看看遵循“不使用的对象应手动赋值为null“的情况:

1
2
3
4
5
6
7
8
public static void main(String[] args) {
if (true) {
byte[] placeHolder = new byte[64 * 1024 * 1024];
System.out.println(placeHolder.length / 1024);
placeHolder = null;
}
System.gc();
}

   其输出为:

1
2
3
65536
[GC 68239K->65952K(125952K), 0.0014910 secs]
[Full GC 65952K->345K(125952K), 0.0099610 secs]

   这次GC后内存占用下降到了345K,即placeHolder被成功回收了!对比两段代码,仅仅将placeHolder赋值为null就解决了GC的问题,真应该感谢“不使用的对象应手动赋值为null“。

   等等,为什么例子里placeHolder不赋值为null,GC就“发现不了”placeHolder该回收呢?这才是问题的关键所在。

典型的运行时栈

   方法在执行的时候,方法里的变量(局部变量)都是分配在栈上的;当然,对于Java来说,new出来的对象是在堆中,但栈中也会有这个对象的指针,和int一样。
   比如对于下面这段代码:

1
2
3
4
5
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = a + b;
}

   其运行时栈的状态可以理解成:

索引 变量
1 a
2 b
3 c

   “索引”表示变量在栈中的序号,根据方法内代码执行的先后顺序,变量被按顺序放在栈中。

再比如:

1
2
3
4
5
6
7
8
public static void main(String[] args) {
if (true) {
int a = 1;
int b = 2;
int c = a + b;
}
int d = 4;
}

   这时运行时栈就是:

索引 变量
1 a
2 b
3 c
4 d

   容易理解吧?其实仔细想想上面这个例子的运行时栈是有优化空间的。

Java的栈优化

   上面的例子,main()方法运行时占用了4个栈索引空间,但实际上不需要占用这么多。当if执行完后,变量a、b和c都不可能再访问到了,所以它们占用的1~3的栈索引是可以“回收”掉的,比如像这样:

索引 变量
1 a
2 b
3 c
1 d

   变量d重用了变量a的栈索引,这样就节约了内存空间。

注意:上面的“运行时栈”和“索引”是为方便引入而故意发明的词,实际上在JVM中,它们的名字分别叫做“局部变量表”和“Slot”。而且局部变量表在编译时即已确定,不需要等到“运行时”。

GC简单介绍

   如何确定对象可以被回收。另一种表达是,如何确定对象是存活的。在Java的世界中,对象与对象之间是存在关联的,我们可以从一个对象访问到另一个对象。如图所示:

   而这些对象与对象之间构成的引用关系,就像是一张大大的图;更清楚一点,是众多的树。如果找到了所有的树根,那么从树根走下去就能找到所有存活的对象,那么那些没有找到的对象,就是已经死亡的了!这样GC就可以把那些对象回收掉了。

   现在的问题是,怎么找到树根呢?JVM早有规定,其中一个就是:栈中引用的对象。也就是说,只要堆中的这个对象,在栈中还存在引用,就会被认定是存活的。

   上面介绍的确定对象可以被回收的算法,其名字是“可达性分析算法”。

JVM的“bug”

   我们再来回头看看最开始的例子:

1
2
3
4
5
6
7
public static void main(String[] args) {
if (true) {
byte[] placeHolder = new byte[64 * 1024 * 1024];
System.out.println(placeHolder.length / 1024);
}
System.gc();
}

   看看其运行时栈:

1
2
3
4
LocalVariableTable:
Start Length Slot Name Signature
0 21 0 args [Ljava/lang/String;
5 12 1 placeHolder [B

   栈中第一个索引是方法传入参数args,其类型为String[];第二个索引是placeHolder,其类型为byte[]。

   联系前面的内容,我们推断placeHolder没有被回收的原因:System.gc();触发GC时,main()方法的运行时栈中,还存在有对args和placeHolder的引用,GC判断这两个对象都是存活的,不进行回收。也就是说,代码在离开if后,虽然已经离开了placeHolder的作用域,但在此之后,没有任何对运行时栈的读写,placeHolder所在的索引还没有被其他变量重用,所以GC判断其为存活。

   为了验证这一推断,现在在System.gc();之前再声明一个变量,按照之前提到的“Java的栈优化”,这个变量会重用placeHolder的索引。

1
2
3
4
5
6
7
8
public static void main(String[] args) {
if (true) {
byte[] placeHolder = new byte[64 * 1024 * 1024];
System.out.println(placeHolder.length / 1024);
}
int replacer = 1;
System.gc();
}

   看看其运行时栈:

1
2
3
4
5
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 args [Ljava/lang/String;
5 12 1 placeHolder [B
19 4 1 replacer I

   不出所料,replacer重用了placeHolder的索引。来看看GC情况:

1
2
3
65536
[GC 68239K->65984K(125952K), 0.0011620 secs]
[Full GC 65984K->345K(125952K), 0.0095220 secs]

   placeHolder被成功回收了!我们的推断也被验证了。

   再从运行时栈来看,加上int replacer = 1;和将placeHolder赋值为null起到了同样的作用:断开堆中placeHolder和栈的联系,让GC判断placeHolder已经死亡。

   “不使用的对象应手动赋值为null“的一切根源都是来自于JVM的一个“bug”:代码离开变量作用域时,并不会自动切断其与堆的联系。导致JVM该变量任有对象在引用,不是垃圾对象。但实际上该对象无法再被其他对象引用,就跟垃圾一样。

参考链接:Java对象不再使用时,为什么要赋值为null?

shell脚本命令

发表于 2020-05-13 | 分类于 shell

让.sh文件变为可执行的脚本文件命令:

1
chmod 777 xxx.sh

1.for循环

for循环一般格式为:

1
2
3
4
5
6
7
for 变量名 in 列表
do
command1
command2
...
commandN
done

   当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。in列表是可选的,如果不用它,for循环使用命令行的位置参数。

例如,顺序输出当前列表中的数字:

1
2
3
4
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done

输出:

1
2
3
4
5
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

顺序输出字符串中的字符:

1
2
3
4
for str in 'This is a string'
do
echo $str
done

输出:

1
This is a string

2.获取当前时间,并进行格式转换的方法

1)原格式输出

1
2
time1=$(date)
echo $time1

输出:2018年 09月 30日 星期日 15:55:15 CST
2)时间串输出

1
2
3
1 #!bin/bash
2 time2=$(date "+%Y%m%d%H%M%S")
3 echo $time2

输出:20180930155515
3)格式转换输出

1
2
3
#!bin/bash
time3=$(date "+%Y-%m-%d %H:%M:%S")
echo $time3

输出:2018-09-30 15:55:15

1
2
3
#!bin/bash
time4=$(date "+%Y.%m.%d")
echo $time4

输出:2018.09.30

注意:
① $(date "")类似的格式转换时,date后面要留有空格
②time4=$(date "+%Y.%m.%d")time4变量赋值前后不能有空格

相关变量解释:

Y显示4位年份,如:2018;y显示2位年份,如:18。
m表示月份;M表示分钟。
d表示天;D则表示当前日期,如:1/18/18(也就是2018.1.18)。
H表示小时,而h显示月份。
s显示当前秒钟,单位为毫秒;S显示当前秒钟,单位为秒。

3.获取指定文件夹大小

3.1 获取指定文件夹大小

1
2
3
4
5
6
7
#/!bin/base
#设置文件夹地址(精确到文件夹名  如:需要获得file_name  文件夹的大小)
file_url="/home/file_name""
#获取[ 文件夹 ]大小(单位kb)
file_kb=$((`du --max-depth=1 ${file_url}|awk '{print $1}'`))
#打印输出文件夹大小
echo "file_size:$file_kb"

3.2 获取指定文件大小

1
2
3
4
5
6
#/!bin/base
#获取文件位置
file_url="/home/file_name/a.log"
#获取文件大小(单位kb)
file_kb=$((`ls -l ${file_url} | awk '{print $5}'`))
echo "file_size:$file_kb"

4.脚本变量$[#,@,0,1,2,*,$,?]含义

$# 是传给脚本的参数个数
$0 是脚本本身的名字
$1 是传递给该shell脚本的第一个参数
$2 是传递给该shell脚本的第二个参数
$@ 是传给脚本的所有参数的列表
$* 是以一个单字符串显示所有向脚本传递的参数,与位置变量不同,参数可超过9个
$$ 是脚本运行的当前进程ID号
$? 是显示最后命令的退出状态,0表示没有错误,其他表示有错误

$@, $*两者的区别:
   相同点:都是引用所有参数
   不同点:$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(“ “)包含时,都以”$1” “$2” … “$n” 的形式输出所有参数。但是当它们被双引号(“ “)包含时,”$*“ 会将所有的参数作为一个整体,以”$1 $2 … $n”的形式输出所有参数;”$@” 会将各个参数分开,以”$1” “$2” … “$n” 的形式输出所有参数。

shell中$*与$@的区别

5.if [ $# -ne 1 ];then命令

if [ $# -ne 1 ];then 是什么意思?

$# 是启动脚本时携带的参数个数
-ne 是不等于,这个语句的意思是“如果shell的启动参数不等于1个”
$# 表示提供到shell脚本或者函数的参数总数;
$1 表示第一个参数。
-ne 表示 不等于

另外:
整数比较

-eq 等于,如:if [“$a” -eq “$b” ]
-ne 不等于,如:if [“$a” -ne “$b” ]
-gt 大于,如:if [“$a” -gt “$b” ]
-ge 大于等于,如:if [“$a” -ge “$b” ]
-lt 小于,如:if [“$a” -lt “$b” ]
-le 小于等于,如:if [“$a” -le “$b” ]
< 小于(需要双括号),如:((“$a” < “$b”))
<= 小于等于(需要双括号),如:((“$a” <= “$b”))
大于(需要双括号),如:((“$a” > “$b”))
= 大于等于(需要双括号),如:((“$a” >= “$b”))

另外:$?是shell变量,表示”最后一次执行命令”的退出状态.0为成功,非0为失败.

参考链接:Linux 脚本编写基础知识

6.shell脚本实现scp文件传输

   scp是一个基于ssh的Linux环境下传输文件的好工具,但是使用shell脚本调用scp时会面临一个问题,即scp强制要求通过交互方式输入密码,而不像mysql等拥有-u -p选项。下面有两种方法帮助shell脚本跨过输入密码这个障碍。

6.1 建立机器间完全信任关系(这种方式没有操作过,不确定可靠性)

假设需要从机器A传输文件至机器B
1)在机器A上运行

1
ssh-keygen -t rsa

   上述命令会在~/.ssh/目录生成私钥证书id_rsa和公钥证书id_rsa.pub;
2)将公钥证书id_rsa.pub复制到机器B的用户根目录的.ssh子目录中,再将文件内容append到文件authorized_keys中。
   其实只要用一条单行命令就可以完成步骤2,它被commandlinefu.com的用户投票选为十大最酷的Linux单行命令之一:

1
ssh-copy-id  [-i [identity_file]]  [user@]machine

   identity_file是公钥证书的路径,默认情况下是~/.ssh/id_rsa.pub.

   如果要建立双方向的完全信任关系,还要从机器B到机器A再重复一遍上面的操作。
不过这样的方法并不完美,一是运维成本太高,二是机器间的安全屏障完全消失,安全代价太大,所以强烈推荐第二种方法。

6.2 expect脚本

   expect脚本是一种建立在tcl基础上的脚本语言,曝光率不高,却堪称shell脚本的好基友。expect脚本为交互而生,被设计为专门针对交互式程序的工具,常与对telnet、ftp、fsck、rlogin、tip、scp等配合使用。例如:

1
2
3
4
5
6
7
8
9
#! /bin/sh
/usr/expect/bin/expect -c "
spawn scp -r aiidc-parse-rundata-1.0-SNAPSHOT.jar root@172.16.16.184:/root
expect {
\"yes/no\" {send \"yes\r\"; exp_continue;}
\"*assword\" {set timeout 200; send \"aiidc@2019\r\"; exp_continue;}
}
expect eof
"

   这段脚本的含义是监听scp命令,如果输入包含*assword,则输入密码“passwd”;如果输入包含yes/no,输入yes并继续进行交互(exp_continue)。
   注:两个用户第一次scp连接时会提示“… Are you sure you want to continue connecting (yes/no)? …”,所以要考虑yes/no的情况。

6.3 使用sshpass免密操作

使用sshpass命令可以在脚本中提前输入密码便于直接运行命令:
eg:

1
2
sshpass -p aiidc@2019 scp -r aiidc-parse-rundata-1.0-SNAPSHOT.jar root@172.16.16.184:/root
sshpass -p aiidc@2019 ssh root@172.16.16.184 'cd /opt/parse-etl/kafka/'

   注意:在使用sshpass操作ssh命令时,通过ssh连接目标服务器后,如果有多个命令要执行,可将多条命令书写在一条命令上通过&&间隔,比如:

1
sshpass -p aiidc@2019 ssh root@172.16.16.184 'cd /opt/parse-etl/kafka/ && rm -rf aiidc-parse-rundata-1.0-SNAPSHOT.jar && ls && mv /root/aiidc-parse-rundata-1.0-SNAPSHOT.jar ./'

该命令的意思连接184服务器后,进入指定目录,先删除jar,然后将新jar移动到目标位置

ssh 用户名@目的主机地址 ‘要执行的命令或者脚本’
注意:

在调用脚本时,必须写全该脚本所在的全路径。
要执行的命令用单引号’ ’扩起来,引号扩起来的命令要和前面的内容写在一行,不能换行。

centos 7 jar包发布服务并开机启动

7.1 jar启动脚本start.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
#先检查是否已启动
count=`ps -ef | grep '/opt/parse/api/dimension/aiidc-justice-dimension-1.0-SNAPSHOT.jar' | grep -v "grep" | wc -l`
#echo $count
if [ $count -gt 0 ]
then
echo "is running..."
else
#下面的cd不能少
cd /opt/api/zgjdev/
nohup java -jar -Dhanlp_properties_path=/opt/parse/api/dimension/config/hanlp.properties -Dspringfox.documentation.swagger.v2.host=172.16.16.153:80 -Xmx1024m /opt/parse/api/dimension/aiidc-justice-dimension-1.0-SNAPSHOT.jar >/opt/parse/api/dimension/log 2>/dev/null & echo $! > /opt/parse/api/dimension/pid
echo "started"
fi
cat /opt/parse/api/dimension/pid

启动的时候会生成pid文件(这个在制作启动服务地方会用到)
注意:start.sh里面路径都要写成绝对路径

7.2 制作启动服务

服务名称:xxx.service
以解析应用为例:parse.service

服务脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=parse
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
User=root
Type=simple
PIDFile=/opt/parse/api/dimension/pid
ExecStart=/opt/parse/api/dimension/start.sh
ExecStop=/bin/kill -15 $MAINPID

[Install]
WantedBy=multi-user.target

需要修改的地方
Description 修改为自己的名字或者描述
PIDFile 修改为自己服务启动后保存的pid文件路径
ExecStart 修改为自己的启动脚本路径

7.3 通过服务启动

将做好的服务拷贝到/etc/systemd/system/路径下

执行
systemctl daemon-reload
加入开机启动
systemctl enable data-application.service

看到这个表示加入开机自启成功

另:

1
2
3
4
#通过服务启动程序
systemctl start data-application.service
#通过服务停止程序
systemctl stop data-application.service

参考链接:Linux centos7下jar包发布成服务并开机自启

ubuntu虚拟机忘记密码解决方法

发表于 2020-04-29 | 分类于 ubuntu

当在ubuntu虚拟机中想切换root或其他用户时,忘记了密码,通过下面的步骤重置密码:
1、重启ubuntu系统,开机时长按shift按键进入GRUB菜单,选择第二个高级选项。如下图:

2、在高级选择中选择Recovery mode模式,键盘按“e”键进入编辑模式。如下图,注意:不要先按enter键

3、在编辑模式中通过上下键寻找到RO修改为RW模式(可写入恢复模式)。如下图,然后按crtl+X进入系统

4、进行系统BIOS界面,通过上下键选择root命令行,点击enter键,如下图:

5、使用passwd命令重新设定密码,例如 passwd rico(rico是系统中已忘记密码所对应的username),回车确认;然后输入新密码并再次输入以确认新密码即可。若修改成功,则会看到密码设定成功提示:passwd: password updated successfully。最后,修改成功后,使用sudo reboot命令重启进入系统即可!

输入过程密码是不可见,有些显示不完全,可忽略,继续操作!

6、重启后通过验证刚才修改的密码是否可用,如下图输入密码后回车能进入系统,说明修改成功。

7、成功进入ubuntn kylin桌面,大功告成~~

参考链接:Ubuntn系统(虚拟机)忘记密码的解决方法

Centos7 端口开放与防火墙设置

发表于 2020-04-29 | 分类于 Centos7

Linux安装链接:使用VMware新建Red Hat Enterprse Linux 6操作系统

VirtualBox下安装CentOS7链接:VirtualBox下安装CentOS7系统

1.Centos7 端口开放及查看

1.1 开放|关闭端口

1
2
3
4
5
6
7
8
9
10
11
12
13
# 开放5672端口
firewall-cmd --zone=public --add-port=5672/tcp --permanent

#关闭5672端口
firewall-cmd --zone=public --remove-port=5672/tcp --permanent

# 配置立即生效,重载防火墙配置
firewall-cmd --reload

#命令含义:
--zone #作用域
--add-port=80/tcp #添加端口,格式为:端口/通讯协议
--permanent #永久生效,没有此参数重启后失效

1.2 设置防火墙便于端口可供外部访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#查看防火墙所有开放的端口
firewall-cmd --zone=public --list-ports

#查看防火墙状态
firewall-cmd --state

#关闭防火墙
systemctl stop firewalld.service

#查看监听的端口
netstat -lnpt
#注意:centos7默认没有 netstat 命令,需要安装 net-tools 工具,命令为:
yum install -y net-tools

#检查端口被哪个进程占用
netstat -lnpt |grep 5672

2.防火墙设置

1
2
3
4
5
6
7
8
9
#查看防火墙状态(not running表示防火墙关闭,running表示防火墙开启)
firewall-cmd --state

#查看防火墙已经开放的端口
firewall-cmd --list-ports
#如果防火墙已经关闭,则该命令显示:FirewallD is not running

#重启防火墙
firewall-cmd --reload

3.systemctl命令操作防火墙

历史上,Linux 的启动一直采用init进程。比如:

1
2
3
$ sudo /etc/init.d/apache2 start
# 或者
$ service apache2 start

这种方法有两个缺点。
   一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
   二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
   Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。使用了 Systemd,就不需要再用init了。Systemd 取代了initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。

参考链接:linux systemctl 指令

systemctl是 Systemd 的主命令,用于管理系统。命令格式:

1
systemctl 操作命令 服务名称

以systemctl操作防火墙服务为例,其他服务类似,修改服务名称即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#启动防火墙服务
systemctl start firewalld.service

#关闭防火墙服务
systemctl stop firewalld.service

#重启防火墙服务
systemctl restart firewalld.service

#查看防火墙的状态
systemctl status firewalld.service

#设置开机启动. 默认情况下,Centos7防火墙是打开的
systemctl enable firewalld.service

#设置开机时禁用防火墙服务
systemctl disable firewalld.service

#查看防火墙服务是否开机启动
systemctl is-enabled firewalld.service;echo $?

#查看已启动的服务列表
systemctl list-unit-files|grep enabled

4.CentOS7和6的默认防火墙的区别

CentOS 7默认使用的是firewall作为防火墙,而CentOS 6使用iptables作为防火墙
如果需要设置Centos 7的防火墙为iptables,步骤如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 4.1 先关闭CentOS 7的防火墙
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动

# 4.2 下载安装 iptables service服务
yum -y install iptables-services

# 4.3 如果要修改防火墙配置,如增加防火墙端口3306
vi /etc/sysconfig/iptables
#增加规则
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
#保存退出后

# 4.4 重启防火墙使配置生效
systemctl restart iptables.service

# 4.5 设置防火墙开机启动
systemctl enable iptables.service

# 4.6 最后重启系统使设置生效即可。
#打开防火墙
systemctl start iptables.service

#关闭防火墙。解决主机不能访问虚拟机CentOS中的站点,前阵子在虚拟机上装好了CentOS6.2,并配好了apache+php+mysql,但是本机就是无法访问。(没遇到过这种情况)
systemctl stop iptables.service

Nginx安装与常用命令

发表于 2020-04-24 | 分类于 Nginx

1.nginx在服务器上安装

  在Centos下,yum源不提供nginx的安装,可以通过切换yum源的方法获取安装。也可以通过直接下载安装包的方法,以下命令均需root权限执行.
  首先安装必要的库(nginx 中gzip模块需要 zlib 库,rewrite模块需要 pcre 库,ssl 功能需要openssl库)。选定/usr/local为安装目录,以下具体版本号根据实际改变。

1.1 安装gcc gcc-c++(如新环境,未安装请先安装,已安装跳过,同下)

1
$ yum install -y gcc gcc-c++

1.2 安装PCRE库

1
2
3
4
5
6
$ cd /usr/local/
$ wget http://jaist.dl.sourceforge.net/project/pcre/pcre/8.33/pcre-8.33.tar.gz
$ tar -zxvf pcre-8.36.tar.gz
$ cd pcre-8.36
$ ./configure
$ make && make install

如报错:

configure: error: You need a C++ compiler for C++ support
解决:

1
yum install -y gcc gcc-c++ 

1.3 安装SSL库

1
2
3
4
5
6
$ cd /usr/local/
$ wget http://www.openssl.org/source/openssl-1.0.1j.tar.gz
$ tar -zxvf openssl-1.0.1j.tar.gz
$ cd openssl-1.0.1j
$ ./config
$ make && make install

1.4 安装zlib库存

1
2
3
4
5
$ cd /usr/local/
$ wget http://zlib.net/zlib-1.2.11.tar.gz
$ tar -zxvf zlib-1.2.11.tar.gz
$ ./configure
$ make && make install

1.5 安装nginx

注意,此处根据个人想法是否修改nginx的安装路径。因为后期在添加nginx的jx.conf文件时是在nginx.conf中要配置的。默认情况下,配置文件nginx.conf放在/usr/local/nginx/conf, /etc/nginx或/usr/local/etc/nginx.

1
2
3
4
5
$ cd /usr/local/
$ wget http://nginx.org/download/nginx-1.8.0.tar.gz
$ tar -zxvf nginx-1.8.0.tar.gz
$ cd nginx-1.8.0
$ ./configure --user=nobody --group=nobody --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_gzip_static_module --with-http_realip_module --with-http_sub_module --with-http_ssl_module

注: –with-http_ssl_module:这个不加后面在nginx.conf配置,ssl:on后,启动会报nginx: [emerg] unknown directive “ssl” in /opt/nginx/conf/nginx.conf 异常

1
$ make && make install

如果提示以下错误:

./configure: error: SSL modules require the OpenSSL library.
运行此命令:

1
yum -y install openssl openssl-devel 

报错:

./configure: error: the HTTP gzip module requires the zlib library
在–prefix后面接以下命令:

1
2
--with-pcre=/usr/local/pcre-8.36 指的是pcre-8.36 的源码路径。
--with-zlib=/usr/local/zlib-1.2.8 指的是zlib-1.2.8 的源码路径。

  以上安装方法nginx的配置文件位于/usr/local/nginx/conf/nginx.conf
Nginx配置文件常见结构的从外到内依次是「http」「server」「location」等等,缺省的继承关系是从外到内,也就是说内层块会自动获取外层块的值作为缺省值。

1.6 启动

  根据上面的安装步骤,nginx 在服务器上安装后启动位置为:/usr/local/nginx/sbin/nginx,即直接运行该命令即可启动nginx。也可以修改指定配置文件地址,然后就可全局使用Nginx命令(个人理解)

1
2
3
4
5
6
7
8
9
10
11
#寻找含有nginx的文件:
find / -name nginx

#定位nginx文件位置:
whereis nginx

#指定配置文件地址(需要根据自己的nginx路径做相应的修改):
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

#重新加载nginx配置文件:
nginx -s reload

nginx的配置文件目录/usr/local/nginx/conf/nginx.conf中在http内添加:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name localhost;

location / {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
1.6.1 启动前准备

启动前先看它启动没有,通过linux命令查看所有端口,看看启动端口中有没有80端口

1
2
netstat -ntlp(查看端口情况)
sudo systemctl status nginx(查看nginx服务情况)

如果没有,则通过命令启动

1
2
3
4
5
6
7
8
#启动:
systemctl start nginx

#停止:
systemctl stop nginx

#重启:
systemctl restart nginx

如果在启动时报错误(没报错跳过):

-bash: nginx: command not found
原因是没有将nginx配置到环境变量中(没报错跳过)
把nginx所在的目录加入系统变量中:

1
2
3
4
5
6
7
#编辑系统环境变量文件
vim /etc/profile

在文件最后添加:
PATH=$PATH:/var/local/nginx/sbin

export PATH

1
2
3
4
5
#保存并退出,执行命令更新环境变量
source /etc/profile

#使配置文件生效,之后重启nginx
/usr/local/nginx/sbin/nginx (路径下启动,没有找到nginx命令时通过该命令启动)
1
2
3
4
5
6
7
8
#设置nginx开启启动
sudo chkconfig nginx on

#关闭Centos自带的firewall防火墙
systemctl stop firewalld.service

#禁止Firewall开机启动
systemctl disable firewalld.service

然后在浏览器上访问:服务器的Ip(192.168.216.128):80

2.nginx安装启动后,宿主机无法访问nginx主页

具体情况如下

①本机能ping通虚拟机
②虚拟机也能ping通本机
③虚拟机能访问自己的web
④本机无法访问虚拟机的web

   后来发现是防火墙将80端口屏蔽了的缘故。故检查是不是虚拟机的80端口被防火墙堵了,可以在宿主机通过命令:telnet 虚拟机Ip 80 来测试。如果能telnet通说明不是防火墙的问题,如果不能说明端口被堵住了。

解决方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#Centos6的防火墙为iptables,而Centos7的防火墙为firewall,根据自己的系统做对应修改
/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT

#然后保存:
/etc/rc.d/init.d/iptables save

#重启防火墙
/etc/init.d/iptables restart

#CentOS防火墙的关闭,关闭其服务即可
#查看CentOS防火墙信息
/etc/init.d/iptables status
#关闭CentOS防火墙服务
/etc/init.d/iptables stop

3.nginx所需常用命令

查看nginx进程

1
2
3
4
(lsof命令是一个列出当前系统打开文件的工具,详细百度)
sudo lsof -i:80
# 或者
ps -ef|grep nginx

修改配置文件后,需要测试修改的配置文件是否合法,然后再重启nginx。

1
2
3
4
5
6
7
8
9
10
#测试修改是否合法:
nginx -t

#重启命令:
nginx -s reload
#或
systemctl restart nginx

#查看已经开放的端口:
firewall-cmd --list-ports

开启端口:

1
firewall-cmd --zone=public --add-port=80/tcp --permanent

命令含义:
–zone #作用域
–add-port=80/tcp #添加端口,格式为:端口/通讯协议
–permanent #永久生效,没有此参数重启后将失效

1
2
3
4
5
6
7
8
9
10
11
#重启防火墙
firewall-cmd --reload

#停止firewall
systemctl stop firewalld.service

#禁止firewall开机启动
systemctl disable firewalld.service

#查看默认防火墙状态(关闭后显示notrunning,开启后显示running)
firewall-cmd --state

4. 解决Nginx出现403 forbidden (13: Permission denied)报错的四种方法

4.1 由于启动用户和nginx工作用户不一致所致

查看nginx的启动用户,发现是nobody,而未是用root启动的

1
ps aux | grep "nginx: worker process" | awk'{print $1}'

故将nginx.config的user改为和启动用户一致,

1
vi /usr/local/nginx/conf/nginx.conf

该文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
user nginx;  #将nginx改为和启动用户一致
worker_processes 1;

error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;

pid logs/nginx.pid;

events {
worker_connections 1024;
}

4.2 缺少index.html或者index.php文件,就是配置文件中index index.html index.htm这行中的指定的文件。

1
2
3
4
5
6
server {  
listen 80;
server_name localhost;
index index.php index.html;
root /data/www/;
}

如果在/data/www/下面没有index.php,index.html的时候,直接文件,会报403 forbidden。

4.3 权限问题,如果nginx没有web目录的操作权限,也会出现403错误。

解决办法:修改web目录的读写权限,或者是把nginx的启动用户改成目录的所属用户,重启Nginx即可解决

chmod 777 /etc/squid 运行命令后,squid文件夹(目录)的权限就被修改为777(可读可写可执行)。

1
2
chmod -R 777 /data
chmod -R 777 /data/www/

SELinux设置为开启状态(enabled)的原因。

4.4 查看当前selinux的状态。

1
/usr/sbin/sestatus


将SELINUX=enforcing 修改为 SELINUX=disabled 状态。

1
vi /etc/selinux/config

1
SELINUX=disabled

重启生效。reboot。

1
reboot

或者出现如下情况:

导致浏览器请求报502异常。同样修改上面的配置,但有可能修改的文件路径不一定相同,如果上面的文件路径不对,可试试下面的路径:

1
vi /etc/sysconfig/selinux

同时,在出现浏览器请求nginx报502的时候,可以在linux上通过curl命令排查是nginx出现问题还是对应的项目服务出现异常:
如:在浏览器上访问:http://172.16.16.153/dimension/api/swagger-ui.html 通过nginx代理去dimension服务,nginx配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 80;

location / {
alias /opt/parse/web/dimension/;
}

location /dimension/api/ {
proxy_pass http://127.0.0.1:8601/;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}

可通过curl来排查是否是dimension服务出现问题:

1
2
3
[root@aiidc-sf-028 conf.d]# curl http://127.0.0.1:8601/
{"errorCode":10001,"message":"未登录","systemId":"aiidc_parse","data":null}
[root@aiidc-sf-028 conf.d]#

如果请求过去dimension服务没有返回相应的结果值,说明是服务出现问题;否则即是nginx没有将浏览器请求代理过去。
即可定位到问题出现在nginx上。
再通过修改系统配置:将SELINUX=enforcing 修改为 SELINUX=disabled 状态即解决问题。

ubuntu端口与防火墙

发表于 2020-04-24 | 分类于 ubuntu

ubuntu官网地址

ubuntu安装教程:
VMware Tools (ubuntu系统)安装详细过程与使用
VMware Ubuntu安装详细过程
ubuntu-19.04-live-server-amd64虚拟机系统安装
ubnut安装Tool教程

1. ubuntu切换到root用户

如果在使用su root命令,去切换到root权限,此时会提示输入密码,但怎么也输不对,提示"Authentication failure",此时有两种情况一个是真的是密码错了,另一种就是刚安装好的Linux系统,没有给root设置密码。
打开Ubuntu,输入命令:

1
su root

回车提示输入密码,怎么输入都不对。
给root用户设置密码:

1
sudo passwd root

输入密码,并确认密码。
重新输入命令:

1
su root

然后输入密码,发现可以切换到root权限了。

2. Ubuntu查看端口使用情况,使用netstat命令

查看已经连接的服务端口(ESTABLISHED):

1
netstat -a

查看所有的服务端口(LISTEN,ESTABLISHED):

1
netstat -ap

查看指定端口,可以结合grep命令:

1
netstat -ap | grep 8080

也可以使用lsof命令:

1
lsof -i:8888 

查看本地端口开启情况(ubuntu下执行):

1
ufw status.

打开80端口(ubuntu下执行):

1
ufw allow 80

测试服务器的端口是否开启:

1
telnet 192.168.13.128 80

3.ubuntu防火墙

ubuntu的防火墙名称为ufw,而centos服务器的防火墙名称为firewall

查看防火墙状态:

1
systemctl status ufw

或

1
sudo ufw status

inactive 状态是防火墙关闭状态
active 是开启状态。

开启防火墙(ubuntu下执行):

1
ufw enable

关闭防火墙:

1
systemctl stop ufw

或

1
ufw disable

Nginx代理入门

发表于 2020-04-09 | 分类于 Nginx

1. nginx代理简单模型

在nginx.conf文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
http {
#这里配置的是负载均衡的情况,即请求到了后会自动分配到81和82服务上(默认两个服务处理请求数量是1:1),可通过设置权重来实现每个服务处理不同数量的请求
upstream qinyin.com {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}

server{
#监听8900 端口
listen 8900;
#监听地址,即监听域名
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8081;
}

#如果有请求:localhost:8900/qinyin ,则会自动代理到:http://127.0.0.1:8082/qinyin 路径下,有四种情况:
#① 【/qinyin】+【8082】 = http://127.0.0.1:8082/qinyin/
# location /qinyin {
# proxy_pass http://127.0.0.1:8082;
# }

#② 【/qinyin】+【8082/】 = http://127.0.0.1:8082
# location /qinyin {
# proxy_pass http://127.0.0.1:8082/;
# }

#③【/qinyin/】+【8082】= http://127.0.0.1:8082/qinyin/
# location /qinyin/ {
# proxy_pass http://127.0.0.1:8082;
# }

#④ 【/qinyin/】+【8082/】= http://127.0.0.1:8082 。即proxy_pass 路径后有/ ,代理后就不会出现追加;
location /qinyin/ {
proxy_pass http://127.0.0.1:8082/;
}

#请求调整到负载均衡,即会nginx会自动将请求分配给不同的服务来处理
location /test/ {
proxy_pass http://qinyin.com/;
}
}
}

参考文章:window 下实现nginx 反向代理

2. nginx前后端一次代理

2.1 nginx后端代理

后端代理,只需要匹配到关键词,然后代理到指定路径上即可,比如配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
listen 443;
server_name sf.aiidc.com.cn;
ssl on;
ssl_certificate /opt/xa/https/2593723_sf.aiidc.com.cn.pem;
ssl_certificate_key /opt/xa/https/2593723_sf.aiidc.com.cn.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
root /opt/xa/pcWeb;

location /api/wszz/ {
proxy_pass http://127.0.0.1:8083/;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 300m;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}

   上面的配置意思为:监听域名sf.aiidc.com.cn的443端口的/api/wszz/路径,即监听http://sf.aiidc.com.cn:443/api/wszz/ 请求,然后将请求代理到http://127.0.0.1:8083/
即本机(127.0.0.1 IP表示本机)的8083端口服务上。即http://sf.aiidc.com.cn:443/api/wszz/file-note/getFileNote(浏览器发起请求) == http://127.0.0.1:8083/file-note/getFileNote(服务器处理请求)

2.2 nginx前端代理

前端代理,既要匹配到关键词,还要部署到相应的目录里面才行,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
listen 443;
server_name sf.aiidc.com.cn;
ssl on;
ssl_certificate /opt/xa/https/2593723_sf.aiidc.com.cn.pem;
ssl_certificate_key /opt/xa/https/2593723_sf.aiidc.com.cn.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
root /opt/xa/pcWeb;

location /api/wainao/ {
proxy_pass http://127.0.0.1:8082/;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}

   上面的配置意思为:监听域名http://sf.aiidc.com.cn的443端口的/api/wainao/路径, 即监听http://sf.aiidc.com.cn:443/api/wainao/index.html 请求,然后将请求代理到/opt/xa/pcWeb这个目录下面的index.html文件。
   而前端代理根本不需要ssl_xxxx这些Https配置,同时也不需要location,因为后端已经有了代理,而前端的请求会自动被后端的代理监听并处理,所以前端不需要指定location等配置。

3. nginx前后端两次代理

   场景:153服务器无法通过外网连接,只有局域网内的服务器(比如231)可以连通,那么项目部署就需要通过nginx代理过去。
   实现原理:将项目前后端在153服务器上部署好,并启动成功。然后通过用户请求231服务器,231服务器将请求代理到153上。
153服务器的nginx配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
listen 8600;
root /opt/parse/web/dimension/;

location /dimension/api/ {
proxy_pass http://127.0.0.1:8601/;
proxy_set_header X-Forwarded-Prefix /dimension/api;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}

231服务器上的nginx配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 8600;
root /opt/parse/web/dimension/;

#前端配置,前端请求(http://172.16.16.231:8600/dimension/api/user/login)后代理153服务器的根目录上,在通过153的root定位index.html页面
location / {
proxy_pass http://172.16.16.153:8600/;
}

#后端配置,请求过来后跳转到153的后端监听项(/dimension/api/),定位到153的后端服务
location /dimension/api/ {
proxy_pass http://172.16.16.153:8600/dimension/api/;
proxy_set_header X-Forwarded-Prefix /dimension/api;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}

总结

①只有前端代理才需要考虑目录问题,后端代理不需要考虑目录,即部署的位置问题;
②在代理的时候,listen监听的端口需要开放并没有被其他程序使用,否则此代理文件不会生效。

<123>
YouQiang

YouQiang

技术总结

25 日志
18 分类
35 标签
GitHub
© 2020 YouQiang