WordPress 使用 wp_count_posts() 函数快速获取文章数量

还记得之前想要获取 WordPress 站点的所有文章总数统计网上的教程,以及子凡在某些地方的使用也都是直接使用 SQL 语句直接查询数据来做总数统计,现在相信还真的是费时费力,原因就是不知道 WordPress 还有 wp_count_posts()这样一个函数,具体是哪个版本出来就懒得去看了,反正随时都保持 WordPress 最新版。

未分类

其实在很多的 WordPress 主题上都会有一个统计或者文章归档的页面,就需要统计一些 WordPress 站点上已经发布多少文章了,以此来展示自己的站点或者给自己一个统计,当然我们在开发某些特别的功能或者逻辑计算时也可能会用到,子凡昨天就开发一个插件的时候就多次用到了,不想再去写 SQL 来统计,费时费力并且 WordPress 本身就有的功能为什么就不好好利用呢,果断就想起了 wp_count_posts 函数。

wp_count_posts 函数是在 WordPress 中用来统计文章数量的函数,可以统计的类型有文章(post)和页面(page)。并且能够直接统计出文章各个不同状态的数据,使用起来非常的便捷,两行代码即可搞定。

//获取文章数量
$postcount = wp_count_posts();
//获取页面数量
$pagecount = wp_count_posts('page');

默认是获取的 post 文章类型的,当然如果是自定义类型应该也是可以支持的,这个子凡目前没有测试,不过相信 WordPress 是绝对考虑到了兼容性的,值得注意的是,子凡上面说过了是两行代码,所以上面的例子并不能直接输出,因为 wp_count_posts 函数返回的是一个对象数据,如下。

// WordPress wp_count_posts 函数返回值
stdClass Object
(
    [publish] => 11 //已发布
    [future] => 0   //定时发布
    [draft] => 0    //草稿
    [pending] => 0  //待审
    [private] => 0  //私有
    [trash] => 0    //垃圾箱
    [auto-draft] => 34  //自动草稿
    [inherit] => 0  //修订版本
    [request-pending] => 0
    [request-confirmed] => 0
    [request-failed] => 0
    [request-completed] => 0
)

所以,获取已发布状态文章的完整统计代码如下:

//WordPress 已发布文章数量
$count_posts = wp_count_posts();  
$publish_posts = $count_posts->publish;

其它的就举一反三,相信也都能看得懂了,子凡就不再过多的赘述。最后在补充一点,有时候我们可能喜欢代码的简单性,所以在写法上面就比较大胆,没有怎么考虑兼容性,一行代码就能搞定,所以在不考虑兼容性的情况下还有以下的一种写法:

//WordPress 已发布文章数量,不兼容 PHP5.4 以前
$publish_posts = wp_count_posts()->publish;

子凡比较喜欢用吧,不过使用这种写法请一定保证你的 PHP 版本在 5.4 以上即可正常运行。

Tomcat单机多实例部署及管理

未分类

单台机器部署多个 Tomcat, 每个Tomcat部署独立服务,Tomcat之间启停互不影响

不要问我为什么有这个需求, 复制粘贴就是干

0x00 单机多实例概述

未分类

大概的目录结构:

  • CATALINA_HOME 为Tomcat应用程序运行程序及所需依赖
  • CATALINA_BASE 即我们即将部署的程序

手动更改如下工作目录:

这是我自己个儿整的初始目录结构 download

war_apps                #手动创建用来存放下载好的war包文件
tomcat                  #CATALINA_HOME
├── bin
├── INIT_APPS_FILE      #CATALINA_BASE
│   ├── conf
│   ├── logs
│   ├── temp
│   ├── webapps
│   └── work
└── lib

然后呢正常的思路就是配置每个APP的server.xml端口:

- Server Port:该端口用于监听关闭tomcat的shutdown命令,默认为8005
- Connector Port:该端口用于监听HTTP的请求,默认为8080
- AJP Port:该端口用于监听AJP( Apache JServ Protocol )协议上的请求,通常用于整合Apache Server等其他HTTP服务器,默认为8009
- Redirect Port:重定向端口,出现在Connector配置中,如果该Connector仅支持非SSL的普通http请求,那么该端口会把 https 的请求转发到这个Redirect Port指定的端口,默认为8443;

应用太多你难道要一个个手动改? no no no! 上脚本

0x01 自动部署管理配置

需要把应用war包传到可下载位置,来用于应用分发,我这里是直接传到了阿里云的oss桶里

1.添加tomcat更新启停控制脚本

需要安装unzip yum -y install unzip

manage.sh需要放在这里,也可以自定义改代码

war_apps                #手动创建用来存放下载好的war包文件
tomcat                  #CATALINA_HOME
├── bin
├── manage.sh
├── INIT_APPS_FILE      #CATALINA_BASE
│   ├── conf
│   ├── logs
│   ├── temp
│   ├── webapps
│   └── work
└── lib

蓝色块需要根据实际情况自定义, 应用名称, 和war包下载地址不需要写,后面的python总控制台会自动分配

manage.sh

#!/bin/sh
# Author: Kionf
# description: 启动tomcat多实例.
# PATH=/opt/op/java/jdk1.8.0_172/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 应用名称
app=
# war包下载地址
war_url=
soft_dir="/opt/op"
download_war_file="${soft_dir}/war_apps/${app}.war"
export CATALINA_BASE="${soft_dir}/tomcat/$app"
export CATALINA_HOME="${soft_dir}/tomcat"
export JVM_OPTIONS="-Xms528m -Xmx812m -Xmn328m"
check(){
    PID=`ps aux|grep java|grep -w ${CATALINA_BASE}|awk '{print $2}'`
    if [ -n "$PID" ];then
        echo -e "33[94m $app is running PID:$PID"
        running=`netstat -ntlp|grep $PID|grep 127.0.0.1`
        if [ -n "$running" ];then
            echo -e "33[92m $app is provide services33[0m "
        else
            echo -e "33[93m $app is running but not provide services33[0m"
        fi
        return 0
    else
        echo -e "33[91m $app is dead33[0m "
        return 1
    fi
}
start() {
    check
    if [ $? -eq 1 ];then
        echo -e "33[94m Start $app 33[0m"
        $CATALINA_HOME/bin/startup.sh >/dev/null 2>&1
    fi
}
stop() {
    check
    if [ $? -eq 0 ];then
        echo -e "33[94m Stop $app33[0m"
        $CATALINA_HOME/bin/shutdown.sh >/dev/null 2>&1
        kill -9 $PID
    fi
}
update() {
    echo "下载文件"
    wget ${war_url} -O ${download_war_file} > /dev/null 2>&1
    if [ $? -eq 0 ];then
        cd ${CATALINA_BASE}/webapps/*/; unzip -q -o ${download_war_file} >/dev/null 2>&1
    fi
}
log() {
    tailf ${CATALINA_BASE}/logs/catalina.out
}
if [ $# != "0" ];then
    case "$1" in
        start)
            start
            ;;
        stop)
            stop
            ;;
        restart)
            stop
            start 
            ;;
        status)
            check
            ;;
        upgrade)
            stop
            update
            start
            ;;
        log)
            log
            ;;
        *)
            echo $"Usage: $0 {start|stop|restart|status|upgrade|log}"
            exit 1
            ;;
    esac
else
    start
    log
fi

2.添加总控制台脚本

我就放在了/usr/local/bin下, chmod +x /usr/local/bin/tomcat_manager 蓝色部分需要根据自己需求更改 (支持python2)

/usr/local/bin/tomcat_manager

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/5/23 15:18
# @Author  : Kionf
# @FileName: tomcat_manager.py
#
#   初始配置并管理单例tomcat多应用
#
import os
import subprocess
import sys
import shutil
# PATH = os.getcwd()
PATH = "/opt/op/tomcat"         #Tomcat目录
shell_script = os.path.join(PATH, "manage.sh")          #更新启停管理脚本
INIT_FILES = os.path.join(PATH, "INIT_APPS_FILE")
bucket = "https://oss.aliyuncs.com/tomcat_app/"         # webapp下载地址
config_data = {
    # 应用名: [ServerPort, ConnectPort, AJPPort, RedirectPort, ]
    'Application': ['8201', '8101', '8301', '8401', 'BaseApplication.war'],
    'BaseNotify_Service': ['8202', '8102', '8302', '8402', 'BaseNotify_Service.war'],
    'BaseUserCenter_Service': ['8203', '8103', '8303', '8403', 'BaseUserCenter_Service.war'],
}
def customize_print(msg, stat=0):
    if stat == 1:
        print("33[91m [ERROR]:  %s 33[0m" % msg)
    elif stat == 0:
        print("33[92m [INFO]:  %s 33[0m" % msg)
    elif stat == 2:
        print("33[93m [DEBUG]:  %s 33[0m" % msg)
class TomcatAppsManage:
    def __init__(self, webapp):
        self.name = webapp
        self.app_config = config_data[self.name]
        self.manage_shell_file = os.path.join(PATH, self.name, self.name)
        self.server_port, self.conn_port, self.ajp_port, self.redirect_port, self.app_war_name = self.app_config
        self.app_download_url = bucket + self.app_war_name
        self.config_file = os.path.join(PATH, self.name, 'conf/server.xml')
        self.webapp_dir = os.path.join(PATH, self.name)
    def create_app(self):
        """
        创建app
        :return:
        """
        if not os.path.exists(self.webapp_dir):
            customize_print("创建APP: %s" % self.name)
            shutil.copytree(INIT_FILES, self.webapp_dir)
            os.mkdir(os.path.join(self.webapp_dir, "webapps", self.name.lower()))
    def config_app_port(self):
        customize_print("正在修改APP:%s 配置" % self.name)
        change_port = {
            'ServerPort': "sed -i s'#Server port="[0-9]*"#Server port="" + self.server_port + ""#'g " + self.config_file,
            'ConnPort': "sed -i s'#Connector port="[0-9]*" protocol="HTTP/1.1"#Connector port="" + self.conn_port + "" protocol="HTTP/1.1"#'g " + self.config_file,
            'RedirectPort': "sed -i s'#redirectPort="[0-9]*"#redirectPort="" + self.redirect_port + ""#'g " + self.config_file,
            'AjpPort': "sed -i s'#Connector port="[0-9]*" protocol="AJP/1.3"#Connector port="" + self.ajp_port + "" protocol="AJP/1.3"#'g " + self.config_file,
        }
        for port in change_port.keys():
            # customize_print("修改 %s 端口" % port)
            os.system(change_port[port])
    def config_app_manage_shell(self):
        customize_print("%s 添加管理脚本" % self.name)
        copy_shell_script = 'cp -f ' + shell_script + ' ' + self.manage_shell_file
        os.system(copy_shell_script)
        config_script_app_name = "sed -i 's/app=/app="" + self.name + ""/' " + self.manage_shell_file
        os.system(config_script_app_name)
        config_script_war_url = "sed -i 's#war_url=#war_url="" + self.app_download_url + ""#' " + self.manage_shell_file
        os.system(config_script_war_url)
    def status_app(self):
        """
        :return: 0提供服务,1停止,2未提供服务
        """
        try:
            result = subprocess.check_output(['sh', self.manage_shell_file, 'status'])
        except subprocess.CalledProcessError as e:
            result = e.output
        if 'run' in result:
            if 'is provide services' in result:
                customize_print("应用 %s 成功启动并提供服务" % self.name)
                return 0
            elif 'but' in result:
                customize_print("应用 %s 进程存在但未提供服务" % self.name, 2)
                return 2
        else:
            customize_print("应用 %s 以停止" % self.name, 1)
            return 1
    def manage(self, operate):
        os.system('sh %s %s' % (self.manage_shell_file, operate))

    def init(self):
        self.create_app()
        self.config_app_port()
        self.config_app_manage_shell()
        self.manage("upgrade")
        self.manage("stop")
    def restart(self):
        self.manage("stop")
        self.manage("start")
    def start(self):
        self.manage("start")
    def stop(self):
        self.manage("stop")
    def log(self):
        self.manage("log")
    def upgrade(self):
        self.lock_config_file()
        self.manage("upgrade")
    def lock_config_file(self):
        cmd = 'find ' + self.webapp_dir + ' -name db*properties -o -name config_base_*|xargs chattr +i >/dev/null 2>&1'
        customize_print("锁配置文件", 2)
        os.system(cmd)
    def unlock_config_file(self):
        cmd = 'find ' + self.webapp_dir + ' -name db*properties -o -name config_base_*|xargs chattr -i >/dev/null 2>&1'
        customize_print("解锁配置文件", 2)
        os.system(cmd)
def dash_board(apps, operate):
    """
    主管理程序,调用
    :param operate: 应用操作
    :param apps: apps 为list
    """
    for app in apps:
        app_obj = TomcatAppsManage(app)
        main_dict = {
            "init": app_obj.init,
            "shell": app_obj.config_app_manage_shell,
            "status": app_obj.status_app,
            "start": app_obj.start,
            "stop": app_obj.stop,
            "restart": app_obj.restart,
            "upgrade": app_obj.upgrade,
            "log": app_obj.log,
            "lock": app_obj.lock_config_file,
            "unlock": app_obj.unlock_config_file,
        }
        try:
            main_dict[operate]()
        except KeyError as e:
            customize_print(help_msg)
help_msg = """
使用方法:
    1 log
    all status
    管理应用编号 操作
操作:
    lock        锁配置文件
    unlock      解锁配置文件
    init        配置tomcat监听端口
    shell       配置webapp控制脚本
    status,start,restart, log,upgrade,stop 应用操作
"""
def main():
    app_list = []
    for index, app_name in enumerate(config_data, 1):
        print "33[94m %s:  %s 33[0m" % (index, app_name)
        app_list.append(app_name)
    choice = raw_input("输入要管理的服务:  ")
    try:
        app_index = choice.split()[0]
        operate = choice.split()[1]
        if app_index.isdigit():
            app_index = int(app_index)
            if len(app_list) >= app_index > 0:
                app_name = app_list[app_index - 1]
                dash_board(app_name.split(), operate)
        elif app_index == "all":
            dash_board(app_list, operate)
    except ValueError and IndexError:
        customize_print("参数输入错误", 1)
        customize_print(help_msg)
if __name__ == '__main__':
    try:
        dash_board(sys.argv[1].split(), sys.argv[2])
    except IndexError:
        try:
            while True:
                main()
        except KeyboardInterrupt:
            customize_print("Bye!")

0x02 开始初始化部署

执行tomcat_manager

未分类

all init 自动初始化部署所有项目, 其他具体使用方法见帮助信息

Tomcat 部署项目的三种方法

1、下载 Tomcat 服务器

①、官网下载地址:http://tomcat.apache.org/

②、tomcat 8.0 64位百度云下载地址:http://pan.baidu.com/s/1slbKPsx 密码:ewui

③、tomcat 8.0 32位百度云下载地址:http://pan.baidu.com/s/1o8G28rS 密码:k11n

2、启动并部署 Tomcat 服务器

①、解压 tomcat 安装包到一个非中文目录下
②、配置环境变量。JAVA_HOME(指向 JDK 安装的根目录)
③、双击 apache-tomcat-6.0.16bin 目录下的 startup.bat,启动服务器(如果一闪而过,那就是没有配置 JAVA_HOME 的环境变量)
④、在浏览器中输入 http://localhost:8080

注意:Tomcat 启动不了的时候注意配置 JAVA_HOME:C:Program FilesJavajdk1.6.0_43这是安装 JDK的根目录

3、Tomcat 的目录结构

未分类

4、部署项目的第一种方法(项目直接放入 webapps 目录中)

1、将编写并编译好的web项目(注意要是编译好的,如果是 eclipse,可以将项目打成 war 包放入),放入到 webapps 中

未分类

2、启动tomcat服务器(双击 apache-tomcat-6.0.16bin 目录下的 startup.bat,启动服务器)

未分类

3、在浏览器输入:http://localhost:8080/项目名/访问的文件名

未分类   

5、部署项目的第二种方法(修改 conf/server.xml 文件 )

①、打开tomcat下conf/server.xml,在 标签之间输入项目配置信息

<Context path="/WebProject" docBase="D:/WebProject" reloadable="true" />

path:浏览器访问时的路径名

docBase:web项目的WebRoot所在的路径,注意是WebRoot的路径,不是项目的路径。其实也就是编译后的项目

reloadble:设定项目有改动时,tomcat是否重新加载该项目

②、双击 startup.bat,启动 tomcat 服务器,然后在浏览器输入访问的项目名称路径

未分类  

注意:如果你配置的 path=”/xx”,那么访问的时候就是这样:

未分类

6、部署项目的第三种方法(apache-tomcat-7.0.52confCatalinalocalhost )

①、进入到 apache-tomcat-7.0.52confCatalinalocalhost 目录,新建一个 项目名.xml 文件

未分类

②、在 那个新建的 xml 文件中,增加下面配置语句(和上面的是一样的,但是不需要 path 配置,加上也没什么用)

<Context  docBase="D:/WebProject" reloadable="true" />

未分类

③、在浏览器输入路径:localhost:8080/xml文件名/访问的文件名

未分类

总结:

①、第一种方法比较普通,但是我们需要将编译好的项目重新 copy 到 webapps 目录下,多出了两步操作

②、第二种方法直接在 server.xml 文件中配置,但是从 tomcat5.0版本开始后,server.xml 文件作为 tomcat 启动的主要配置文件,一旦 tomcat 启动后,便不会再读取这个文件,因此无法再 tomcat 服务启动后发布 web 项目

③、第三种方法是最好的,每个项目分开配置,tomcat 将以confCatalinalocalhost 目录下的 xml 文件的文件名作为 web 应用的上下文路径,而不再理会 中配置的 path 路径,因此在配置的时候,可以不写 path。

通常我们使用第三种方法

tomcat与jvm的关系分析

首先,我们来看几个概念:

1. 什么是jvm

我们从操作系统的层面来理解,jvm其实就是操作系统中的一个进程。既然是一个进程,那么我们很容易的可以通过任务管理器来查看。假设此时我们启动myeclipse(myeclipse其实就是用java语言编写的一个软件,他的运行必然会启动一个jvm,我们可以把myeclipse理解成我们自己写的一个简单的java版的helloworld程序)。查看任务管理器的截图如下:

未分类

2. 什么是tomcat

tomcat其实是一个用java语言开发的免费开源的web服务器(因为是java语言开发,这就是为什么使用tomcat前要配置好jdk,因为jdk里面有jvm,而运行java应用需要jvm)。此时再次查看任务管理器会发现多了一个javaw.exe

看了两者之间的概念之后,相信我们都清楚了两者之间的关系。

现在还有一个问题:

同一个tomcat下的java ee项目使用的是不是同一个jvm?答案是是的。(使用的都是启动tomcat的jvm)这个可以通过启动不同的web应用来自己判断。

如果运行的是普通的java se程序,使用的是不是同一个jvm呢?答案是否。这个可以自己运行程序判断。(可以写一个很简单的while死循环,便于查看)。

tcpdump在Ubuntu和CentOS下的安装和使用

tcpdump安装

在ubuntu下安装

sudo apt-get install tcpdump

在CentOS下安装

yum install tcpdump

tcpdump使用

安装好以后,运行tcpdump -help查看帮助如下所示:

未分类

1、监视指定网络接口的数据包(本机网卡名为ens33)

tcpdump -i ens33

2、监视指定主机的数据包,例如:抓取所有192.168.1.11主机发送和接收的数据包

tcpdump -i ens33 host 192.168.1.11

3、抓取192.168.1.11主机发送的数据包

tcpdump -i ens33 src host 192.168.1.11

4、抓取192.168.1.11主机接收到的数据包

tcpdump -i ens33 dst 192.168.1.11

5、抓取指定端口的数据包:

tcpdump -i ens33 udp port 12345

6、抓取回环网口的包:

tcpdump -i ens33 -i lo

CentOS 7设置Samba共享目录

一、安装Samba服务

yum -y install samba
# 查看yum源中Samba版本
yum list | grep samba
# 查看samba的安装情况
rpm -qa | grep samba

Samba服务器安装完之后, 会生成配置文件目录/etc/samba, /etc/samba/smb.conf是samba的核心配置文件.

二、启动Samba服务

Samba服务安装完成之后有两种方法启动:

service smb start/stop/restart/status
# 或者
systemctl start/stop/restart/status smb.service

# 设置smb服务开机启动
systemctl enable smb.service

三、开放Samba服务使用到的端口号

Samba服务会用到如下的一些端口号:

  • 137(UDP): NetBIOS名字服务
  • 138(UDP): NetBIOS数据报服务
  • 139(TCP): 文件和打印共享
  • 389(TCP): 用于LDAP
  • 445(TCP): NetBIOS服务在windows 2000及以后使用此端口
  • 901(TCP): 用于SWAT, 网页管理Samba

如果不想关闭防火墙的话, 就要在CentOS中放开Samba使用到的TCP端口号

firewall-cmd --zone=public -add-port=139/tcp --permanent
firewall-cmd --zone=public -add-port=389/tcp --permanent
firewall-cmd --zone=public -add-port=445/tcp --permanent
firewall-cmd --zone=public -add-port=901/tcp --permanent

firewall-cmd --reload

# 查看已经放开的端口号
firewall-cmd --list-all

四、配置Samba服务

1、配置匿名访问, 任何人都可以访问的共享目录

1) 创建共享目录

mkdir /opt/shares

# 因为需要设置匿名用户可以上传下载文件, 所以需要给shares目录授予nobody权限
chown -R nobody:nobody /opt/shares

2) 修改/etc/samba/smb.conf文件

cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
vi /etc/samba/smb.conf

修改配置如下:

# See smb.conf.example for a more detailed config file or
# read the smb.conf manpage.
# Run 'testparm' to verify the config is correct after
# you modified it.

[global]
        workgroup = SAMBA
        security = user
        map to guest = Bad User
        log file = /var/log/samba/log.%m


[public]
        comment = Public Stuff
        path = /opt/shares
        public = yes
        read only = No

其中 path就是上边设置的共享目录, read only 表示是否有写权限

3) 修改完配置文件之后重启samba服务

systemctl restart smb.service

4) 测试smb.conf配置是否正确

# 使用testparm命令
testparm

5) 至此就配置完成, 可以从Windows下访问samba的共享目录.

2、配置指定用户可以访问的共享目录

设置共享目录, 只允许指定用户组的用户访问

1) 添加工作组cnki和用户share

groupadd cnki
# useradd -g 组名 用户名
useradd -g cnki share
# 设置用户share的密码
passwd share

#删除用户
userdel -r 用户名

2) 把要访问的账户添加到samba的账户中

光添加系统账户还不够, 需要把已经存在的系统账户添加到samba中才可以访问共享目录

# smbpasswd 参数: -a: 添加 -x: 删除 -d: 禁用 -e: 启用
smbpasswd -a share

3) 创建共享目录

mkdir /opt/shares1

# chown -R 用户名:组名 目录
chown -R share:cnki /opt/shares1

4) 设置samba服务

修改配置文件/etc/samba/smb.conf如下

# See smb.conf.example for a more detailed config file or
# read the smb.conf manpage.
# Run 'testparm' to verify the config is correct after
# you modified it.

[global]
        workgroup = SAMBA
        security = user
        map to guest = Bad User
        log file = /var/log/samba/log.%m

[shares]
        comment = CNKI
        path = /opt/shares1
        # 表示用户组
        valid users = @cnki
        read only = No

5) 重启smb服务

systemctl restart smb.service
# 检查smb.conf文件是否配置正确
testparm

6) 至此配置完成, 可以在Windows平台下通过用户名share/share来访问共享目录了.

inotify+rsync实战演练

试验目的:

演练rsync结合inotify实现服务端目录内文件有变动(包括修改,删除,创建)时,自动立即同步到客户端

试验环境:

centos6.5 192.168.10.89 —–角色:文件同步服务器.原始文件服务器.rsync客户端,inotify服务器
centos 6.5 192.168.10.103—–角色:文件同步客户端,由文件服务器自动向客户端同步

关于rsync和inotify介绍和具体用法.请参考其他笔记内容

实战步骤

一.在inotify服务器安装inotify-tools工具

下载链接https://sourceforge.net/projects/inotify-tools/?source=typ_redirect

安装过程简单:

tar zxvf inotify-tools-3.13.tar.gz
cd inotify-tools-3.13
./configure --prefix=/usr/local/inotify
make && make install 

vim /etc/profile
在结尾处加上:
export PATH=$PATH:/usr/local/inotify/bin

应用profile文件:
source /etc/profile

二.演示inotify使用方法:

执行命令:

inotifywait -rm --format '%Xe %w%f' -e modify,create,delete,attrib /tmp/data

命令输出:

[root@oracle inotify-tools-3.13]# inotifywait -rm --format '%Xe %w%f' -e modify,create,delete,attrib /tmp/data
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.

解析:

inotifywait : 持续监控文件的状态变化

-r : 递归监控目录下的所有文件,包括子目录.

Note:如果要监控的目录中文件数量巨大,则通常需要修改/proc/sys/fs/inotify/max_users_watchs内核参数,因为其默认值为8192.

-m: 实现持续监控

–format 显示格式.

  • %X—-事件以”X”分隔.
  • %e—-显示事件(比如CREATE,MODIFY等),
  • %w—-显示文件名
  • %f—–显示目录
  • -e: 表示检测哪些事件

/tmp/data——-监测的目录路径

再开启一个终端,然后在/tmp/data目录下新建一些文件:

[root@localhost data]# touch {x,y,z,u,v,w}.txt
inotify输出如下:

检测到了文件变化.第一列是事件类型.有CREATE,ATTRIB. 第二列是文件的完整路径

[root@oracle inotify-tools-3.13]# inotifywait -rm –format ‘%Xe %w%f’ -e modify,create,delete,attrib /tmp/data
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
CREATE /tmp/data/x.txt
ATTRIB /tmp/data/x.txt
CREATE /tmp/data/y.txt
ATTRIB /tmp/data/y.txt
CREATE /tmp/data/z.txt
ATTRIB /tmp/data/z.txt
CREATE /tmp/data/u.txt
ATTRIB /tmp/data/u.txt
CREATE /tmp/data/v.txt
ATTRIB /tmp/data/v.txt
CREATE /tmp/data/w.txt
ATTRIB /tmp/data/w.txt


再试着删除所有文件:

[root@localhost data]# rm -rf {x,y,z,u,v,w}.txt
inotify检测到DELETE事件:

DELETE /tmp/data/x.txt
DELETE /tmp/data/y.txt
DELETE /tmp/data/z.txt
DELETE /tmp/data/u.txt
DELETE /tmp/data/v.txt
DELETE /tmp/data/w.txt

试试创建和删除目录检测到CREATE和DELETE的目录事件:

CREATEXISDIR /tmp/data/test

试试修改文件内容

[root@localhost data]# echo "haha" > 1.txt

检测到MODIFY事件:

CREATE /tmp/data/1.txt
MODIFY /tmp/data/1.txt

基本用法就介绍到这里.下面实战演练inotify+rsync结合做目录文件同步

在inotify编写脚本文件:

以下是工作在相对路径下

[root@localhost ~]# vim inotify_rsync.sh
#!/bin/bash
src=/tmp/data
des="/" #由于工作在相对路径下,会同步目录名.所以目的路径为/根
ip=192.168.10.103
user=root
cd $src #切换进工作目录
#inotify监测目录下文件是否有改动.主要监测:文件名或者目录修改,创建,删除,移动,文件内容修改.(这里我没有监测文件权限属性发送变化).
#将监测到的文件重定向到while循环.
inotifywait -mr --format '%Xe %w%f' -e modify,create,delete,close_write,move $src | while read file;do
   #获取Inotify的监测事件.有CREATE,MODIFY,DELETE等
   ino_event=$(echo $file | awk '{print $1}')
   #获取inotify监测到的变化文件
   ino_file=$(echo $file | awk '{print $2}')
   echo $file
   #if的正则匹配.如果ino_event变量的内容匹配CREATE开头.那么就条件为true.其实就等于 $ino_event == "CREATE*"
   if [[ $ino_event =~ "CREATE" ]] || [[ $ino_event =~ "MODIFY" ]] || [[ $ino_event =~ "CLOSE_WRITE" ]] || [[ $ino_event =~ "MOVED_TO" ]];then
         echo "CREATE or MODIFY or CLOSE_WRITE or MOVED_TO"
         #如果是文件有变化,则利用rsync同步该文件的父目录到远程主机相关目录下.这里使用了ssh协议.需要提前复制本机公钥到目的主机
         echo $(dirname $ino_file)
         /usr/bin/rsync -avzR -e ssh $(dirname $ino_file) $user@$ip:$des
   elif [[ $ino_event =~ "DELETE" ]] || [[ $ino_event =~ "MOVED_FROM" ]];then
         echo "Delete or Moved_From"
        #如果是文件删除,或者移动到其他地方.则利用rsync删除远程主机上的该文件
        /usr/bin/rsync -avzR --delete $(dirname $ino_file) $user@$ip:$des
   fi
done
以下是工作在绝对路径下:

[root@localhost ~]# vim inotify_rsync.sh
#!/bin/bash
src=/tmp/data
des=/tmp  #由于会同步/tmp/data目录.所以目的路径只需要指定/tmp目录
ip=192.168.10.103
user=root
#inotify监测目录下文件是否有改动.主要监测:文件名或者目录修改,创建,删除,移动,文件内容修改.(这里我没有监测文件权限属性发送变化).
#将监测到的文件重定向到while循环.
inotifywait -mr --format '%Xe %w%f' -e modify,create,delete,close_write,move $src | while read file;do
   #获取Inotify的监测事件.有CREATE,MODIFY,DELETE等
   ino_event=$(echo $file | awk '{print $1}')
   #获取inotify监测到的变化文件
   ino_file=$(echo $file | awk '{print $2}')
   echo $file
   #if的正则匹配.如果ino_event变量的内容匹配CREATE开头.那么就条件为true.其实就等于 $ino_event == "CREATE*"
   if [[ $ino_event =~ "CREATE" ]] || [[ $ino_event =~ "MODIFY" ]] || [[ $ino_event =~ "CLOSE_WRITE" ]] || [[ $ino_event =~ "MOVED_TO" ]];then
         echo "CREATE or MODIFY or CLOSE_WRITE or MOVED_TO"
         #如果是文件有变化,则利用rsync同步该文件的父目录到远程主机相关目录下.这里使用了ssh协议.需要提前复制本机公钥到目的主机
         /usr/bin/rsync -avz -e ssh $ino_file $user@$ip:$des
   elif [[ $ino_event =~ "DELETE" ]] || [[ $ino_event =~ "MOVED_FROM" ]];then
         echo "Delete or Moved_From"
        #如果是文件删除,或者移动到其他地方.则利用rsync删除远程主机上的该文件
        /usr/bin/rsync -avz --delete $ino_file $user@$ip:$des
   fi
done

Note:此脚本中的rsync使用的是ssh协议传输.而不是守护模式.所以需要实现传输本地的公钥到远程主机相关用户下

运行脚本:

[root@localhost ~]# ./inotify_rsync.sh

在/tmp/data目录内创建文件:

[root@localhost data]# touch {1,2,3,4,5,6}.txt

脚本输出:

[root@oracle ~]# ./inotify_rsync.sh
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
CLOSE_WRITEXCLOSE /tmp/data/1.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list
/tmp/
/tmp/data/
/tmp/data/1.txt
/tmp/data/2.txt
/tmp/data/3.txt
/tmp/data/4.txt
/tmp/data/5.txt
/tmp/data/6.txt
/tmp/data/test/

sent 388 bytes  received 138 bytes  350.67 bytes/sec
total size is 5  speedup is 0.01
CREATE /tmp/data/2.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03
CLOSE_WRITEXCLOSE /tmp/data/2.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03
CREATE /tmp/data/3.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  112.67 bytes/sec
total size is 5  speedup is 0.03
CLOSE_WRITEXCLOSE /tmp/data/3.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03
CREATE /tmp/data/4.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  112.67 bytes/sec
total size is 5  speedup is 0.03
CLOSE_WRITEXCLOSE /tmp/data/4.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03
CREATE /tmp/data/5.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03
CLOSE_WRITEXCLOSE /tmp/data/5.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  112.67 bytes/sec
total size is 5  speedup is 0.03
CREATE /tmp/data/6.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03
CLOSE_WRITEXCLOSE /tmp/data/6.txt
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 154 bytes  received 15 bytes  338.00 bytes/sec
total size is 5  speedup is 0.03

在172.16.1.120客户端的/tmp/data目录下查看文件: 文件已成功复制:

[root@www ~]$ll /tmp/data
total 8
-rw-r--r--. 1 root root    5 Jun 24 13:27 1.txt
-rw-r--r--. 1 root root    0 Jun 24 13:27 2.txt
-rw-r--r--. 1 root root    0 Jun 24 13:27 3.txt
-rw-r--r--. 1 root root    0 Jun 24 13:27 4.txt
-rw-r--r--. 1 root root    0 Jun 24 13:27 5.txt
-rw-r--r--. 1 root root    0 Jun 24 13:27 6.txt

演示在Inotify服务上删除刚创建的文件: 监测到文件删除

[root@oracle ~]# ./inotify_rsync.sh
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
DELETE /tmp/data/1.txt
Delete or Moved_From
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list
/tmp/data/
deleting tmp/data/6.txt
deleting tmp/data/5.txt
deleting tmp/data/4.txt
deleting tmp/data/3.txt
deleting tmp/data/2.txt
deleting tmp/data/1.txt

sent 87 bytes  received 18 bytes  70.00 bytes/sec
total size is 0  speedup is 0.00
DELETE /tmp/data/2.txt
Delete or Moved_From
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 84 bytes  received 15 bytes  198.00 bytes/sec
total size is 0  speedup is 0.00
DELETE /tmp/data/3.txt
Delete or Moved_From
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 84 bytes  received 15 bytes  66.00 bytes/sec
total size is 0  speedup is 0.00
DELETE /tmp/data/4.txt
Delete or Moved_From
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 84 bytes  received 15 bytes  198.00 bytes/sec
total size is 0  speedup is 0.00
DELETE /tmp/data/5.txt
Delete or Moved_From
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 84 bytes  received 15 bytes  198.00 bytes/sec
total size is 0  speedup is 0.00
DELETE /tmp/data/6.txt
Delete or Moved_From
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list

sent 84 bytes  received 15 bytes  66.00 bytes/sec
total size is 0  speedup is 0.00

在172.16.1.120服务器上查看/tmp/data目录.下面没有任何文件

[root@www ~]$ll /tmp/data
total 4
drwxr-xr-x. 2 root root 4096 Jun 24 13:17 test

演示:新建一个目录.且在该目录下创建内容 脚本输出:

CREATEXISDIR /tmp/data/haha
CREATE or MODIFY or CLOSE_WRITE or MOVED_TO
/tmp/data
Nasty PTR record "172.16.1.120" is set up for 172.16.1.120, ignoring
sending incremental file list
/tmp/data/
/tmp/data/haha/

sent 100 bytes  received 22 bytes  244.00 bytes/sec
total size is 0  speedup is 0.00

目录已经被同步

[root@www ~]$ll /tmp/data
total 8
drwxr-xr-x. 2 root root 4096 Jun 24 13:33 haha
drwxr-xr-x. 2 root root 4096 Jun 24 13:17 test

rsync实战演练

rsync是一个远程数据同步工具,可以快速同步多台主机的文件,且只同步有差异的部分.非常强大的工具

实战环境:

  • 服务端:192.168.10.89
  • 客户端:192.168.10.103

rsync不需要安装,默认就自带.

关于rsync的命令想法,可以参考其他笔记.

note: 以下教程都是讲述客户端从远程服务器同步数据到本地.类似于下载行为. 如果需要将本地的文件同步到远程服务器.有点类似于上传行为.则需要改变命令.

下列命令表示了上传和下载的使用区别.

note:在使用rsyn同步前必须要千万小心.因为如果命令搞反.可能会出现意外的严重后果.例如将对方的文件同步到本地数据目录

1.下列的命令将对方(192.168.10.89)的/var/www/abc目录同步到本地的/root/rsync目录下:

rsync -avz --progress -e ssh [email protected]:/var/www/abc /root/rsync

2.下列命令表示将本地的/tmp/backups目录同步到对方(192.168.10.89)的/var/www/abc目录下

rsync -avz --progress /tmp/backups -e ssh [email protected]:/var/www/abc

3.另外.如果远程服务器的ssh不是默认22端口.则需要改成:

rsync -avz --progress /root/rsync -e "ssh -p 端口 " [email protected]:/var/www/abc

Rync的使用方法介绍:

一、以服务端的方式启动rsync进程

1.编辑/etc/rsyncd.conf配置文件——-这个文件默认没有,需要自己写入

vim /etc/rsyncd.conf
#全局参数.所有模块生效配置#
uid = nobody
gid = nobody
use chroot = no
max connections = 4
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log
#模块参数.一个模块代表一个路径#
[www]
path = /var/www/abc/   #路径目录,注意必须是一个/结尾的目录
ignore errors          #忽略错误信息
read only = yes       #服务端只读,客户端只能和服务端同步,不能上传文件
list = no          #是否允许客户端列出服务端此路径下的文件
hosts allow = 192.168.10.0/24  #允许哪个网络上的客户端同步
auth users = backup    #认证用户名
secrets file = /etc/rsync_server.pas #指定一个密码文件路径.此文件内容为username:password. 而且此文件必须和启动rsync的用户是同一个用户.且权限为600

2.编辑密码文件:

[root@localhost ~]# cat /etc/rsync_server.pas
backup:jesse
[root@localhost ~]# ll /etc/rsync_server.pas
-rw------- 1 root root 13 Dec 27 16:46 /etc/rsync_server.pas

Note:此文件必须为600权限.且和rsync进程的用户相同.比如如果是root启动的rsync服务.则此文件属主也必须是root

3.启动rsync服务,以daemon方式启动

rsync --daemon

rsync –daemon默认监控在873端口

默认监控在873端口:
[root@localhost ~]# netstat -tulnp | grep rsync
tcp        0      0 0.0.0.0:873                 0.0.0.0:*                   LISTEN      2034/rsync
tcp        0      0 :::873                      :::*                        LISTEN      2034/rsync

4.在/var/www/abc目录下写入一个测试文件夹

[root@localhost ~]# cat /var/www/abc/rsync.test
haha
this is for test rsync
the nginx02 is rsync server.the nginx 01 (ip:192.168.10.103) is a client
I am going to see whether this file will be sync to the client or not!

5.客户端同步文件 先定义密码.改成600权限

[root@localhost ~]# cat /etc/rsync_server.pas
jesse
[root@localhost ~]# ll /etc/rsync_server.pas
-rw------- 1 root root 6 Dec 27 16:47 /etc/rsync_server.pas

Note:我在这里踩到一个大坑.客户端的密码文件只需要包含密码.不能像服务端一样指定username:password.不然会提示验证失败

6.执行rsync命令

/usr/bin/rsync -avz  --progress [email protected]::www /var/www/abc/ --password-file=/etc/rsync_server.pas

-a ----保持文件权限
-v ----详细显示
-z -----启用压缩
--progress --显示备份过程
backup@ ----表示用backup用户认证
::www  --------注意这里有2个冒号.表示同步服务器上的www模块
/var/www/abc ---表示同步到本地这个目录下
--password-file ---表示用这个文件内的密码去认证

可是遇到和上面一样的坑:

[root@localhost ~]# /usr/bin/rsync -avz  --progress [email protected]::www /var/www/abc/ --password-file=/etc/rsync_server.pas
@ERROR: auth failed on module www

这个坑,至少坑了我5个小时.反复的确认selinux是否关闭,配置文件是否错误,密码文件和密码文件权限等最后才发现,原来配置文件的配置语句不能用注释

注释内容只能单独一行存在.修改配置文件:

[root@localhost ~]# vim /etc/rsyncd.conf
#全局参数.所有模块生效配置#
uid = nobody
gid = nobody
use chroot = no
max connections = 4
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log
#模块参数.一个模块代表一个路径#
[www]
path = /var/www/abc/
ignore errors
read only = yes
list = no
hosts allow = 192.168.10.0/24
auth users = backup
secrets file = /etc/rsync.secrets

客户端重新执行命令:

[root@localhost ~]# /usr/bin/rsync -avz  --progress [email protected]::www /var/www/abc/ --password-file=/etc/rsync_server.pas
receiving incremental file list
./
index.html
          91 100%   88.87kB/s    0:00:00 (xfer#1, to-check=2/4)
rsync.test
         173 100%  168.95kB/s    0:00:00 (xfer#2, to-check=1/4)
test.jpg
      185883 100%   25.32MB/s    0:00:00 (xfer#3, to-check=0/4)
sent 115 bytes  received 186303 bytes  372836.00 bytes/sec
total size is 186147  speedup is 1.00
[root@localhost ~]#
可以看到同步了rsync.test文件过来了.另外其他2个文件也一并同步过来

演示: 服务端文件名不修改.往文件内新增文件.观察rsync是否能实行增量同步

1.在rsync服务端内的/var/www/abc/index.html文件新增一行内容:

[root@rabbitmqnode0 abc]# vim index.html
hello.This is nginx server for www.abc.com
hello world!
add a new line to test rsync   #新增一行

2.客户端在原有同步后的基础上再次执行命令:可以看见.只同步了Index.html文件.其他文件并没有复制

[root@rabbitmqnode1 ~]# /usr/bin/rsync -avz  --progress [email protected]::www /var/www/abc/ --password-file=/etc/rsync_server.pas
receiving incremental file list
./
index.html
          85 100%   83.01kB/s    0:00:00 (xfer#1, to-check=1/3)
sent 83 bytes  received 251 bytes  668.00 bytes/sec
total size is 106558  speedup is 319.04

查看文件:

[root@rabbitmqnode1 ~]# cat /var/www/abc/index.html
hello.This is nginx server for www.abc.com
hello world!
add a new line to test rsync

可见.即便文件名一致.只要文件内容有变化,仍然会同步到客户端.

二、以ssh方式同步文件

1.关掉服务端的rsync进程

ps -ef | grep rsync
root       2014      1  0 21:28 ?        00:00:00 rsync --daemon
root       6334   2588  0 22:37 pts/1    00:00:00 grep rsync
[root@localhost ~]# kill -9 2014
[root@localhost ~]# rm -rf /var/run/rsyncd.pid

2.客户端直接执行命令:

[root@localhost ~]# rsync -avz --progress -e ssh [email protected]:/var/www/abc /root
[email protected]'s password:
receiving incremental file list
abc/
abc/index.html
          91 100%   88.87kB/s    0:00:00 (xfer#1, to-check=2/4)
abc/rsync.test
         173 100%  168.95kB/s    0:00:00 (xfer#2, to-check=1/4)
abc/test.jpg
      185883 100%   25.32MB/s    0:00:00 (xfer#3, to-check=0/4)
sent 72 bytes  received 186254 bytes  53236.00 bytes/sec
total size is 186147  speedup is 1.00
[root@localhost ~]#

-e 表示 使用ssh协议root@ 表示服务器的本地用户(注意,这里是服务器本地真实用户)..这里的用法和普通的scp命令一致

可以看到文件已经同步过来了.且权限保持一致

[root@localhost ~]# ll /root/abc
total 192
-rw-r--r-- 1 root root     91 Dec 26 19:21 index.html
-rw-r--r-- 1 root root    173 Dec 27 15:07 rsync.test
-rw-r--r-- 1 root root 185883 Dec 26 19:21 test.jpg

注意:ssh模式不能像rsync daemon模式那样指定一个密码文件.如果想不输入密码.只能复制本机的公钥到rsync服务端相关用户下.

Note:

1.一般在生产中 在客户端同步的时候还需要加入个 –delete参数.表示如果本机相关目录下有某个文件.而这个文件在服务端上没有.那么就删除.这是为了保持和服务端完全同步

2.一般需要写一个crontab定时任务,每5分钟同步一次

/5 * /usr/bin/rsync -avz –progress [email protected]::www /var/www/abc/ –password-file=/etc/rsync_server.pas > /dev/null 2>&1

Tomcat调优指南

摘要: Tomcat安装:wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.31/bin/apache-tomcat-8.5.31.tar.gz 解压缩后直接在apache/bin目录下./startup.sh 启动小技巧:当出现Tomcat一直卡在启动页面时,可以是因为Java.security配置文件里写的是/dev/random,/dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流。

Tomcat安装:

wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.31/bin/apache-tomcat-8.5.31.tar.gz

未分类

解压缩后直接在apache/bin目录下./startup.sh

启动小技巧:
当出现Tomcat一直卡在启动页面时,可以是因为Java.security配置文件里写的是/dev/random,/dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流。很多解密程序与安全应用程序(如SSH Keys,SSL Keys等)需要它们提供的随机数据流。当使用/dev/random因为需要生成随机数如果没有完成这个随机数的创建就会一直卡在启动页面。建议找到jdk1.x.x_xx/jre/lib/security/Java.security文件,在文件中找到securerandom.source这个设置项,将其改为:
securerandom.source=file:/dev/unrandom

在 apache/conf/server.xml目录下 tomcat默认参数设置:

  • maxThreads:tomcat可用于请求处理的最大线程数,默认是200 —-连接数
  • minSpareThreads:tomcat初始线程数,即最小空闲线程数 == minProcessors相同
  • maxSpareThreads:tomcat最大空闲线程数,超过的会被关闭==maxThreads==maxProcessors
  • acceptCount:当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理.默认100— 最大排队数

  • minProcessors:最小连接线程数,用于提高系统处理性能,默认值为10

  • maxProcessors:最大连接线程数,即:并发处理的最大请求数,默认值为75
  • enableLookups:是否反查域名,取值为:true或false。为了提高处理能力,应设置为false
  • connectionTimeout:网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒。

其中和最大连接数相关的参数为maxProcessors和acceptCount。如果要加大并发连接数,应同时加大这两个参数。

最大连接数 maxThreads
tomcat同时处理的线程数。

配置依据:

(1)、部署的程序偏计算型,主要利用cpu资源,应该将该参数设置小一点,减小同一时间抢占cpu资源的线程个数。
(2)、部署的程序对io、数据库占用时间较长,线程处于等待的时间较长,应该将该参数调大一点,增加处理个数。
最大排队数 acceptCount
当tomcat的线程数达到maxThreads后,新的请求就会排队等待,超过排队数的请求会被拒绝。
我一般设置和maxThreads相同。

“maxPostSize”该参数限制了post方式上传文件的大小,当maxPostSize<=0时,POST方式上传的文件大小不会被限制,maxPostSize参数只有当request的Content-Type为“application/x-www-form-urlencoded”时起作用。
“maxHttpHeaderSize”来自于客户端请求的Request和Response的HTTP,http请求头信息的最大程度,超过此长度的部分不予处理,一般8K。
“maxThreads”客户请求最大线程数,Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数。
“minSpareThreads”最小空闲线程数,Tomcat初始化时创建的 socket 线程数.
“maxSpareThreads”最大连接线程数,即:并发处理的最大请求数,默认值为75,一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。
“minProcessors”最小空闲连接线程数,用于提高系统处理性能,默认值为 10。
“acceptCount”允许的最大连接数,应大于等于 maxProcessors ,默认值为 100。
“enableLookups”若设为true, 则支持域名解析,可把 ip 地址解析为主机名,为了提高处理能力,应设置为false。
“compression”打开压缩功能。
“compressionMinSize “启用压缩的输出内容大小,这里面默认为2KB
“compressableMimeType”压缩类型。
“connectionTimeout”网络连接超时,单位:毫秒。设置为 0 表示永不超时,这样设置有隐患的。通常可设置为 30000 毫秒。
“URIEncoding”URL统一编码 。
“redirectPort”这里系统默认的,它指定转发端口,如果当前只支持non-SSL请求,在需要安全通信的场所,将把客户请求转发至SSL的redirectPort端口。
“disableUploadTimeout”上传时是否使用超时机制,如果不指定,该属性为“false”。

上述配置读者可通过实际业务需求进行调整,达到tomcat性能最优,关于更多tomcat详细部署读者可参考笔者的该篇文章,希望能有所帮助。

vultr云主机ssh连接异常分析

vultr云主机突发莫名其妙的连接异常,ssh无法登陆,通过tcpdump抓包进行分析,特记录之。

实验准备

  • vultr云主机
  • ssh客户端
  • tcpdump抓包工具

实验步骤

客户端发起ssh连接

未分类

服务端抓包

未分类

实验分析

客户端发起TCP连接,服务端收到了三次握手的seq 1966603666包
服务器端把seq +1 返回ack 1966603667包
重点在于客户端没有收到服务器的ack确认,又重发了Flags [S], seq 1966603666
循环往复,直至SSH连接超时

那么问题来了,ACK包为啥会丢失呢?或许有一个神秘的东方力量在起作用

奇怪的是在境外的服务器可以实现SSH登录vultr主机

未分类

只有先Across the great firewall,你才能Reach every corner in the world.

后续

最初出现问题,本来计划提交工单,要求vultr解决。经过理性分析之后,放弃了这个做法,因为这个问题不是vultr能解决的。最后通过迁移主机更换IP恢复了访问。