精华内容
下载资源
问答
  • 介绍Mycat启动脚本及其脚本配置文件

    最近生产环境发现Mycat(version 1.5.1) hung住2分钟,然后应用就叫了!最后发现这个hung的时间由Mycat脚本配置文件wrapper.conf里面的某个参数控制,虽然hung住的原因还没有分析到,趋向于猜测为Mycat内部的bug引起。

    基于上面的背景,需要充分理解Mycat启动的原理,守护进程原理和hung住检测的原理,以及wrapper.conf配置选项,所以写下以下文章,作为记录:

    Mycat启动脚本

    我们知道,可通过源码编译打包方式得到mycat软件包,目录结构大致如下:

    /bin
    /catlet
    /conf
    /lib
    /logs

    其中bin目录下包含了启动mycat的脚本,默认脚本命名为mycat。这个脚本可以将mycat以后台程序的方式运行,并且具有守护进程的作用,能够在mycat应用程序发生异常,如crash,jvm hung,deadlock之后将mycat应用重启,最大化地保证mycat服务高可靠

    这个功能实际上是Java Service Wrapper(JSW)提供的, 包括bin里面的启动脚本,也是JSW写好提供给我们用的

    注意mycat使用的JSW版本为: Version 3.2.3,目前这个版本已经偏低了

    我们知道mycat源码使用maven构建,build的依赖里面引入appassembler-maven-plugin插件来辅助构建,正是这个插件引入了JSW

    关于JSW的介绍和原理,请参考另外一篇文章:Java Service Wrapper 详解

    通过启动脚本,调用JSW守护进程启动,然后带动我们的mycat程序启动,守护进程实时检测mycat服务的状态,发生异常及时抢救。通过ps -ef | grep wrapper可以看到wrapper守护进程与mycat进程之间的关系:

    mysql      3467      1  0 Jun15 ?        00:12:19 /dba/app/mycat/mycat/bin/./wrapper-linux-x86-64 /dba/app/mycat/mycat/conf/shivatds_wrapper.conf wrapper.syslog.ident=shivatds wrapper.pidfile=/dba/app/mycat/mycat/logs/shivatds.pid wrapper.daemonize=TRUE
    mysql      3469   3467  1 Jun15 ?        03:04:03 java -DMYCAT_HOME=. -server -XX:MaxPermSize=64M -XX:+AggressiveOpts -XX:MaxDirectMemorySize=2G -XX:+UseParallelGC -Xss512K -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1984 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx4G -Xms2G -Djava.library.path=lib -classpath lib/wrapper.jar:conf:lib/slf4j-log4j12-1.7.12.jar:lib/minlog-1.2.jar:lib/libwrapper-linux-ppc-64.so:lib/libwrapper-linux-x86-32.so:lib/json-20151123.jar:lib/univocity-parsers-1.5.4.jar:lib/ehcache-core-2.6.11.jar:lib/log4j-1.2.17.jar:lib/mapdb-1.0.7.jar:lib/curator-client-2.9.0.jar:lib/leveldb-api-0.7.jar:lib/dom4j-1.6.1.jar:lib/sequoiadb-driver-1.12.jar:lib/leveldb-0.7.jar:lib/objenesis-1.2.jar:lib/zookeeper-3.4.6.jar:lib/fastjson-1.2.7.jar:lib/jsr305-2.0.3.jar:lib/druid-1.0.14.jar:lib/jline-0.9.94.jar:lib/asm-4.0.jar:lib/snakeyaml-1.16.jar:lib/hamcrest-library-1.3.jar:lib/h2-1.4.192.jar:lib/guava-18.0.jar:lib/netty-3.7.0.Final.jar:lib/xml-apis-1.0.b2.jar:lib/wrapper.jar:lib/libwrapper-linux-x86-64.so:lib/hamcrest-core-1.3.jar:lib/kryo-2.10.jar:lib/mongo-java-driver-2.11.4.jar:lib/slf4j-api-1.7.12.jar:lib/jtar-2.3.jar:lib/reflectasm-1.03.jar:lib/Mycat-server-1.5.3.0-RELEASE.jar:lib/curator-framework-2.9.0.jar -Dwrapper.key=loiVbopWE6KVjsik -Dwrapper.port=32000 -Dwrapper.jvm.port.min=31000 -Dwrapper.jvm.port.max=31999 -Dwrapper.pid=3467 -Dwrapper.version=3.2.3 -Dwrapper.native_library=wrapper -Dwrapper.service=TRUE -Dwrapper.cpu.timeout=10 -Dwrapper.jvmid=1 org.tanukisoftware.wrapper.WrapperSimpleApp org.opencloudb.MycatStartup start

    脚本配置文件wrapper.conf详解

    JSW有一个比较重要的配置文件,默认叫做wrapper.conf。通过这个配置文件,配置JSW守护进程和wrapper的一些行为,并且,还可以控制mycat jvm的一些启动参数(如-Xms和-Xmx这些)。

    这个文件默认放到/conf目录下

    下面我们将重点放在这个文件的配置选项里面:

    贴上mycat编译打包后默认生成的wrapper.conf(位于conf子目录下),然后对每个配置参数作出解释,如下所示:

    #********************************************************************
    # Wrapper Properties
    #********************************************************************
    # Java执行命令,默认即可
    wrapper.java.command=java
    # 用于定位wrapper程序目录,默认即可
    wrapper.working.dir=..
    
    # JSW wrapper类,JSW将使用这个类来包装Mycat启动类(MycatStartup.java),并控制Mycat的执行,
    # 即在WrapperSimpleApp的main方法里面加入一些控制逻辑,
    # 然后执行MycatStartup的main方法,从而跑其Mycat
    wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
    
    # 设置环境变量,参考https://wrapper.tanukisoftware.com/doc/english/props-envvars.html
    # 在后面的配置wrapper.java.classpath.3被使用
    set.default.REPO_DIR=lib
    # 不知道哪里会用到这个环境变量
    set.APP_BASE=.
    
    # Java Classpath (include wrapper.jar)  Add class path elements as
    #  needed starting from 1
    # 配置Java应用的classpath,必须要包含wrapper.jar,参数下标从1开始
    wrapper.java.classpath.1=lib/wrapper.jar
    wrapper.java.classpath.2=conf
    wrapper.java.classpath.3=%REPO_DIR%/*
    
    # Java Library Path (location of Wrapper.DLL or libwrapper.so)
    # 默认参数,不用修改
    wrapper.java.library.path.1=lib
    
    # 配置Java启动参数,参数下标从1开始,包括一系列Java环境变量设定以及JVM参数配置
    #wrapper.java.additional.1=
    wrapper.java.additional.1=-DMYCAT_HOME=.
    wrapper.java.additional.2=-server
    wrapper.java.additional.3=-XX:MaxPermSize=64M
    wrapper.java.additional.4=-XX:+AggressiveOpts
    wrapper.java.additional.5=-XX:MaxDirectMemorySize=8G
    wrapper.java.additional.6=-XX:+UseParallelGC
    wrapper.java.additional.7=-Xss512K
    wrapper.java.additional.8=-Dcom.sun.management.jmxremote
    wrapper.java.additional.9=-Dcom.sun.management.jmxremote.port=1984
    wrapper.java.additional.10=-Dcom.sun.management.jmxremote.authenticate=false
    wrapper.java.additional.11=-Dcom.sun.management.jmxremote.ssl=false
    wrapper.java.additional.12=-Xmx4G
    wrapper.java.additional.13=-Xms4G
    
    # Initial Java Heap Size (in MB) 等价于 -Xms3M
    #wrapper.java.initmemory=3
    
    # Maximum Java Heap Size (in MB) 等价于 -Xmx64M
    #wrapper.java.maxmemory=64
    
    # 程序启动参数,下标从1开始,第1个参数指定wrapper需要包装的Java应用主程序入口,
    # 对于Mycat而言,这里指定为MycatStartup,默认即可,不需要修改
    wrapper.app.parameter.1=org.opencloudb.MycatStartup
    # 默认即可,不需要修改
    wrapper.app.parameter.2=start
    
    #********************************************************************
    # Wrapper Logging Properties
    #********************************************************************
    # wrapper 控制台日志输出格式 
    # 仅当使用mycat console启动时候,会将log输出到控制台,这个参数是控制这个时候log的输出格式
    # 格式详见: https://wrapper.tanukisoftware.com/doc/english/prop-console-format.html
    wrapper.console.format=PM
    
    # wrapper 控制台输出日志级别
    # 仅当使用mycat console启动时候,会将log输出到控制台,这个参数是控制这个时候log的级别, 默认为INFO即可
    wrapper.console.loglevel=INFO
    
    # wrapper 输出日志文件 
    # 仅当使用mycat start启动时,会将log输出到这个指定的文件里
    wrapper.logfile=logs/wrapper.log
    
    # wrapper 输出到log文件的日志输出格式 
    # 控制当使用mycat start启动方式下log输出格式
    # 格式参考: https://wrapper.tanukisoftware.com/doc/english/prop-logfile-format.html
    wrapper.logfile.format=LPTM
    
    # wrapper 输出到log文件的日志级别 
    # 控制当使用mycat start启动方式下log输出级别
    wrapper.logfile.loglevel=INFO
    
    # 配置滚动日志大小,默认为0,表示不支持滚动日志,即日志都往一个日志文件里面写,并且不限制文件大小
    # May abbreviate with the 'k' (kb) or 'm' (mb) suffix.  For example: 10m = 10 megabytes.
    wrapper.logfile.maxsize=0
    
    
    # 配置滚动日志最大文件个数,默认为0表示不限制个数
    wrapper.logfile.maxfiles=0
    
    # 输出到sys/event log的日志级别,默认为NONE表示不输出到sys/event log
    wrapper.syslog.loglevel=NONE
    
    #********************************************************************
    #********************************************************************
    # Title to use when running as a console
    wrapper.console.title=Mycat-server
    
    # 以下这些参数在Windows平台下起作用,一般应用都部署在Linux平台,可忽略这些配置
    #********************************************************************
    # Wrapper Windows NT/2000/XP Service Properties
    #********************************************************************
    # WARNING - Do not modify any of these properties when an application
    #  using this configuration file has been installed as a service.
    #  Please uninstall the service before modifying this section.  The
    #  service can then be reinstalled.
    
    # Name of the service
    wrapper.ntservice.name=mycat
    
    # Display name of the service
    wrapper.ntservice.displayname=Mycat-server
    
    # Description of the service
    wrapper.ntservice.description=The project of Mycat-server
    
    # Service dependencies.  Add dependencies as needed starting from 1
    wrapper.ntservice.dependency.1=
    
    # Mode in which the service is installed.  AUTO_START or DEMAND_START
    wrapper.ntservice.starttype=AUTO_START
    
    # Allow the service to interact with the desktop.
    wrapper.ntservice.interactive=false
    
    # 重要参数,控制wrapper ping Mycat hung住的超时时间,单位是s,120s = 2min
    wrapper.ping.timeout=120
    # JSW官网上目前找不到这个参数!
    configuration.directory.in.classpath.first=conf

    注意最后面这个wrapper.ping.timeout参数(wrapper默认这个参数配置为30s,不知道mycat为何把这个参数调得这么高),可控制wrapper对于Mycat hung住的判定时间,这里配置为2min,表示2min内没有收到Mycat的ping响应,即认为Mycat hung住,这时候wrpper将会把Mycat重起,观察到wrapper.log里面的日志,如下所示:

    INFO   | jvm 1    | 2017/06/16 00:16:02 | log4j 2017-06-16 00:16:02 [./conf/log4j.xml] load completed.
    INFO   | jvm 1    | 2017/06/16 00:16:03 | MyCAT Server startup successfully. see logs in logs/mycat.log
    ERROR  | wrapper  | 2017/06/21 17:43:21 | JVM appears hung: Timed out waiting for signal from JVM.
    ERROR  | wrapper  | 2017/06/21 17:43:21 | JVM did not exit on request, terminated
    INFO   | wrapper  | 2017/06/21 17:43:21 | JVM exited on its own while waiting to kill the application.
    STATUS | wrapper  | 2017/06/21 17:43:21 | JVM exited in response to signal SIGKILL (9).
    STATUS | wrapper  | 2017/06/21 17:43:25 | Launching a JVM...
    INFO   | jvm 2    | 2017/06/21 17:43:25 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
    INFO   | jvm 2    | 2017/06/21 17:43:25 |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
    INFO   | jvm 2    | 2017/06/21 17:43:25 | 
    INFO   | jvm 2    | 2017/06/21 17:43:26 | log4j 2017-06-21 17:43:26 [./conf/log4j.xml] load completed.
    INFO   | jvm 2    | 2017/06/21 17:45:27 | MyCAT Server startup successfully. see logs in logs/mycat.log

    其中部分参数是由mycat中pom.xml的appassembler-maven-plugin配置带入的,如下所示:

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>appassembler-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
            <configurationDirectory>conf</configurationDirectory>
            <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
            <repositoryLayout>flat</repositoryLayout>
            <useWildcardClassPath>true</useWildcardClassPath>
            <daemons>
                <daemon>
                    <id>mycat</id>
                    <mainClass>org.opencloudb.MycatStartup</mainClass>
                    <commandLineArguments>
                        <commandLineArgument>start</commandLineArgument>
                    </commandLineArguments>
                    <platforms>
                        <platform>jsw</platform>
                    </platforms>
                    <jvmSettings>
                        <!-- 启动内存配置 -->
                        <maxStackSize>128</maxStackSize>
                        <systemProperties>
                            <systemProperty>MYCAT_HOME=.</systemProperty>
                        </systemProperties>
                        <extraArguments>
                            <extraArgument>-server </extraArgument>
                            <extraArgument>-XX:MaxPermSize=64M</extraArgument>
                            <extraArgument>-XX:+AggressiveOpts</extraArgument>
                            <extraArgument>-XX:MaxDirectMemorySize=2G</extraArgument>
                            <extraArgument>-XX:+UseParallelGC</extraArgument>
                            <extraArgument>-Xss512K</extraArgument>
                            <!-- 远程JMX -->
                            <extraArgument>-Dcom.sun.management.jmxremote </extraArgument>
                            <extraArgument>-Dcom.sun.management.jmxremote.port=1984</extraArgument>
                            <extraArgument>-Dcom.sun.management.jmxremote.authenticate=false </extraArgument>
                            <extraArgument>-Dcom.sun.management.jmxremote.ssl=false </extraArgument>
                            <extraArgument>-Xmx4G</extraArgument>
                            <extraArgument>-Xms1G</extraArgument>
                        </extraArguments>
                    </jvmSettings>
                    <generatorConfigurations>
                        <generatorConfiguration>
                            <generator>jsw</generator>
                            <includes>
                                <include>aix-ppc-32</include>
                                <include>aix-ppc-64</include>
                                <include>hpux-parisc-64</include>
                                <include>linux-x86-32</include>
                                <include>linux-x86-64</include>
                                <include>linux-ppc-64</include>
                                <include>macosx-ppc-32</include>
                                <include>macosx-x86-universal-32</include>
                                <include>macosx-universal-32</include>
                                <include>macosx-universal-64</include>
                                <include>solaris-sparc-32</include>
                                <include>solaris-sparc-64</include>
                                <include>solaris-x86-32</include>
                                <include>windows-x86-32</include>
                                <include>windows-x86-64</include>
                            </includes>
    
                            <configuration>
                                <property>
                                    <name>configuration.directory.in.classpath.first</name>
                                    <value>conf</value>
                                </property>
                                <property>
                                    <name>wrapper.ping.timeout</name>
                                    <value>120</value>
                                </property>
                                <property>
                                    <name>set.default.REPO_DIR</name>
                                    <value>lib</value>
                                </property>
                                <property>
                                    <name>wrapper.logfile</name>
                                    <value>logs/wrapper.log</value>
                                </property>
                            </configuration>
    
                        </generatorConfiguration>
                    </generatorConfigurations>
                </daemon>
    
            </daemons>
        </configuration>
        <executions>
            <execution>
                <id>generate-jsw</id>
                <phase>package</phase>
                <goals>
                    <goal>generate-daemons</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    展开全文
  • 嵌入式Linux启动配置文件脚本

    千次阅读 2011-02-23 14:50:00
    使用Busybox制作根文件系统时,/etc目录非常重要,它包含了嵌入式Linux启动所需的配置文件脚本.由于init进程,或者说linuxrc程序会解析inittab文件,因此就从/etc/inittab文件开始说起. (1)文件/etc/inittab...
        使用Busybox制作根文件系统时,/etc目录非常重要,它包含了嵌入式Linux启动所需的配置文件及脚本.由于init进程,或者说linuxrc程序会解析inittab文件,因此就从/etc/inittab文件开始说起.
    (1)文件/etc/inittab
       该文件是init进程需要解析的文件,它的每个条目都是一个脚本或可执行程序,详见博客"inittab文件".

         ::sysinit:/etc/init.d/rcS
         ::respawn:-/bin/login
         ::ctrlaltdel:/bin/umount -a -r

    (2)文件/etc/init.d/rcS
       该文件的功能主要有两个,一个是将不同的文件系统挂载到根文件系统下的某个目录内;二是新建kernel所需的目录,这些目录都是kernel运行过程中所必须的.

            #! /bin/sh

            /bin/mount -n -t ramfs ramfs /var #在不同的目录内挂载不同的文件系统
            /bin/mount -n -t ramfs ramfs /tmp
            /bin/mount -n -t sysfs none /sys
            /bin/mount -n -t ramfs none /dev
                                              #在不同的目录内新建文件夹
            /bin/mkdir /var/tmp
            /bin/mkdir /var/modules
            /bin/mkdir /var/run
            /bin/mkdir /var/log
                                              #在不同的目录内递归新建文件夹
            /bin/mkdir -p /dev/pts
            /bin/mkdir -p /dev/shm

            /sbin/mdev -s
            /bin/mount -a                     #当执行命令"mount -a"时,系统会自动读取配置文件fstab.
            echo /sbin/mdev > /proc/sys/kernel/hotplug

    (3)文件/etc/fstab
       在文件/etc/init.d/rcS中执行mount –a时,就会按照文件/etc/fstab内容挂载相应的文件系统.

            proc        /proc       proc      defaults   0 0
            none        /dev/pts    devpts    mode=0622  0 0
            tmpfs       /dev/shm    tmpfs     defaults   0 0

    <1>fstab文件的格式:
       device Mount Point filesystem parameters dump fsck
        proc    /proc      proc    defaults   0    0
    <2>文件/etc/fstab就是使用mount将设备载入到系统的某个载入点所需执行的命令内容,将这些内容都写到/etc/fstab里,使得系统一启动就主动载入.
    <3>参数dump的值表示是否允许使用dump命令进行系统备份.dump命令会根据对/etc/fstab的设置值,去选择是否要将该分区进行备份.0表示不要dump备份,1或2表示要进行dump备份.
    <4>参数fsck的值表示是否允许以fsck检验分区内的文件系统是否完整.其中,根文件系统必须进行检验,其它文件系统可以不需要检验.0表示不要检验,1或2表示要进行检验.

    (4)文件/etc/passwd
       当用户以telnet或ssh登录主机时,系统会出现一login画面来输入账号,此时输入账号和密码后,Linux会执行以下动作:
    <1>先找/etc/passwd内是否有该账号,如果有,则将该账号与对应的UID(user ID)和GID(Group ID)读出,并将该账号的家目录与shell设置也一起读出.
    <2>核对密码表,此时Linux会进入/etc/shadow中查找对应的账号与UID,然后核对已输入的密码与里面的密码是否一致.
    <3>若一切相符,就进入shell控制阶段.
       下面就来分别简述这两个文件的含义.
    <1>/etc/passwd

    root:x:0:0:root:/root:/bin/sh

       该文件的构造如上所示,每一行都表示一个账号,有几行就表示系统中有几个账号.注意,里面的很多账号都是系统必须使用的,称作系统账号.在每个Linux系统中都会有第一行,就是root系统管理员行,每行有7个部分,用":"隔开.
       1、账号名称:root表示默认的系统管理员的账号名称.
       2、密码:x表示密码已经移动到shadow这个加密后的文件中了.
       3、UID:当UID=0时,表示root
       4、GID:与/etc/group有关,用于规范用户组.
       5、用户信息说明栏:用于解释该账号的意义.
       6、家目录:用户的家目录.root用户的家目录就是/root.
       7、Shell:默认使用/bin/bash来执行命令.
    <2>/etc/shadow

    root:$1$HNeU8jpc$RyzTN856sZiO.LCN2BZuZ0:14880:0:99999:7:::

       该文件属于加密文件,每个账号的密码均在该文件中,这里不再赘述.
     
    (5)/etc/profle

        echo
        echo -n "Processing /etc/profile... "
        # no-op
        echo "Done"
        echo
        PATH=/bin:/sbin:/usr/bin:/usr/sbin
        export LD_LIBRARY_PATH=/lib:/usr/lib

     

    展开全文
  • shell脚本实现多进程

    千次阅读 2019-05-27 00:25:09
    从事Linux主机建设和运维的同事们在工作中应该经常会遇到批量修改配置信息或部署应用环境的需求,需要根据需求依次登录目标主机执行一些命令或脚本,使用shell脚本的循环语句是实现这一需求最直观方式。但是普通的...

    从事Linux主机建设和运维的同事们在工作中应该经常会遇到批量修改配置信息或部署应用环境的需求,需要根据需求依次登录目标主机执行一些命令或脚本,使用shell脚本的循环语句是实现这一需求最直观方式。但是普通的for或do while循环都是串行执行的,脚本耗时每个循环耗时*循环次数,在较大规模实施或者目标语句耗时较长的情况下,串行方式的循环脚本执行时间也不容忽视。

     

    要减少执行串行循环的耗时,自然要考虑如何用并行方式解决。在shell之外有一些现成的管理部署工具如parallel、ansible、puppet、saltstack都能解决并发执行多任务的问题,但生产系统一般不允许随意安装新软件,因而我们这里只讨论不借助工具,只使用shell脚本如何实现并发执行多任务。

     

    串行执行循环时,脚本中每一次循环对应的子进程都是脚本执行所处shell的前台进程,同一时间一个shell只能有一个前台进程,要做到并行执行多个进程,意味着脚本中的循环要放到执行环境shell的后台,作为后台进程去执行。

     

    直接使用后台执行 

    先来看下循环串行执行的情况。

    脚本的循环内容以sleep为例,下同。 

    vim fork-0.sh

    #!/bin/bash

    job=10    #任务总数

    for ((i=0; i<$job; i++)); do

    {

              echo  "progress $i is sleeping for 3 seconds zzz...…"

              sleep  3

    }

    done

    echo -e "time-consuming: $SECONDS    seconds"    #显示脚本执行耗时

    运行结果如下图所示:

    可以看到脚本执行时间30秒与预期10轮*3秒一致。

    如果打开另一个窗口watch sleep进程的话,可以看到同一时刻只有1个sleep进程在跑:

     

    修改脚本,采用循环并行执行的方式。

    vim fork-1.sh

    #!/bin/bash

    job=10

    for ((i=0; i<$Njob; i++)); do

    {

              echo  "progress $i is sleeping for 3 seconds zzz...…"

              sleep  3 &       #循环内容放到后台执行

    }

    done

    wait      #等待循环结束再执行wait后面的内容

    echo -e "time-consuming: $SECONDS    seconds"    #显示脚本执行耗时

    可以看到脚本执行耗时为3秒,与预期1轮*3秒一致。

    watch sleep进程,可以看到同一时刻有10个PPID相同的sleep进程在跑:

     

    这种方式从功能上实现了使用shell脚本并行执行多个循环进程,但是它缺乏控制机制。

     

    for设置了Njob次循环,同一时间Linux就触发Njob个进程一起执行。假设for里面执行的是scp,在没有pam_limits和cgroup限制的情况下,很有可能同一时刻过多的scp任务会耗尽系统的磁盘IO、连接数、带宽等资源,导致正常的业务受到影响。

     

    一个应对办法是在for循环里面再嵌套一层循环,这样同一时间,系统最多只会执行内嵌循环限制值的个数的进程。不过还有一个问题,for后面的wait命令以循环中最慢的进程结束为结束(水桶效应)。如果嵌套循环中有某一个进程执行过程较慢,那么整体这一轮内嵌循环的执行时间就等于这个“慢”进程的执行时间,整体下来脚本的执行效率还是受到影响的。

     

    2使用模拟队列来控制进程数量

     

    要控制后台同一时刻的进程数量,需要在原有循环的基础上增加管理机制。

     

    一个方法是以for循环的子进程PID做为队列元素,模拟一个限定最大进程数的队列(只是一个长度固定的数组,并不是真实的队列)。队列的初始长度为0,循环每创建一个进程,就让队列长度+1。当队列长度到达设置的并发进程限制数之后,每隔一段时间检查队列,如果队列长度还是等于限制值,那么不做操作,继续轮询;如果检测到有并发进程执行结束了,那么队列长度-1,轮询检测到队列长度小于限制值后,会启动下一个待执行的进程,直至所有等待执行的并发进程全部执行完。

     

    vim para-2.sh

    #!/bin/bash 

    Njob=15 #任务总数 

    Nproc=5 #最大并发进程数  

    function PushQue {      #将PID值追加到队列中 

               Que="$Que $1" 

               Nrun=$(($Nrun+1)) 

    }

     

    function GenQue {       #更新队列信息,先清空队列信息,然后检索生成新的队列信息 

               OldQue=$Que 

               Que=""; Nrun=0 

               for PID in $OldQue; do 

                     if [[ -d /proc/$PID ]]; then 

                            PushQue $PID 

                     fi 

               done 

    }

     

    function ChkQue {       #检查队列信息,如果有已经结束了的进程的PID,那么更新队列信息 

               OldQue=$Que 

               for PID in $OldQue; do 

                     if [[ ! -d /proc/$PID ]];   then 

                     GenQue; break 

                     fi 

               done 

     

    for ((i=1; i<=$Njob; i++)); do 

               echo "progress $i is sleeping for 3 seconds zzz…" 

               sleep 3 & 

               PID=$! 

               PushQue $PID 

               while [[ $Nrun -ge $Nproc ]]; do          # 如果Nrun大于Nproc,就一直ChkQue 

                     ChkQue 

                     sleep 0.1 

               done 

    done 

    wait

     

    echo -e "time-consuming: $SECONDS   seconds"    #显示脚本执行耗时#!/bin/bash

    运行结果如下图所示:

     

     

    可以看到脚本执行时间9秒与预期3轮*3秒一致。

     

    watch sleep进程,可以看到同一时刻只有5个sleep进程在跑,与我们限制的数量相符:

     

     

    这种使用队列模型管理进程的方式在控制了后台进程数量的情况下,还能避免个别“慢”进程影响整体耗时的问题:

     

     

     

    3使用fifo管道特性来控制进程数量

     

    管道是内核中的一个单向的数据通道,同时也是一个数据队列。具有一个读取端与一个写入端,每一端对应着一个文件描述符。 

    命名管道即FIFO文件,通过命名管道可以在不相关的进程之间交换数据。FIFO有路径名与之相关联,以一种特殊设备文件形式存在于文件系统中。

     

    FIFO有两种用途: 

    • FIFO由shell使用以便数据从一条管道线传输到另一条,为此无需创建临时文件,常见的操作cat file|grepkeyword就是这种使用方式; 

    • FIFO用于客户进程-服务器进程程序中,已在客户进程与服务器进程之间传送数据,下面的例子将使用这种方式。

     

    根据FIFO文件的读规则,如果有进程写打开FIFO,且当前FIFO内没有数据,对于设置了阻塞标志的读操作来说,将一直阻塞状态。

     

    利用这一特性可以实现一个令牌机制。设置一个行数等于限定最大进程数Nproc的fifo文件,在for循环中设置创建一个进程时先read一次fifo文件,进程结束时再write一次fifo文件。如果当前子进程数达到限定最大进程数Nproc,则fifo文件为空,后续执行的并发进程被读fifo命令阻塞,循环内容被没有触发,直至有某一个并发进程执行结果并做写操作(相当于将令牌还给池子)。

     

    需要注意的是,当并发数较大时,多个并发进程即使在使用sleep相同秒数模拟时,也会存在进程调度的顺序问题,因而并不是按启动顺序结束的,可能会后启动的进程先结束。

     

    vim para-3.sh

    #!/bin/bash

    Njob=15 #任务总数

    Nproc=5 #最大并发进程数

    mkfifo ./fifo.$$ && exec   777<>  ./fifo.$$ && rm -f ./fifo.$$     #通过文件描述符777访问fifo文件

    for ((i=0; i<$Nproc; i++)); do  #向fifo文件先填充等于Nproc值的行数

              echo  "init time add $i" >&777

    done

     

    for ((i=0; i<$Njob; i++)); do

    {

              read  -u  777             #从fifo文件读一行

              echo  "progress $i is sleeping for 3 seconds zzz…"

              sleep  3

              echo  "real time add $(($i+$Nproc))"  1>&777 #sleep完成后,向fifo文件重新写入一行

    } &

    done

    wait

    echo -e "time-consuming: $SECONDS    seconds"

    运行结果如下图所示:

     

     

    可以看到脚本执行时间9秒与预期3轮*3秒一致。

    watch sleep进程,同样可以看到同一时刻只有5个sleep进程。

     

    4总结

     

    并行多进程的循环语句能提高脚本执行效率。

     

    例1这种没有控制机制,同一时间可能触发大量并发进程的脚本在生产环境中尽量避免使用,嵌套循环也尽量少用。

     

    例2例3分别使用数组元素模拟队列和利用fifo读写阻塞性两种方式实现了后台进程数量的控制,适宜作为批量操作的shell脚本模版。

     

    5后记

     

    关于执行顺序的问题,把例2采用队列方式的例子中的动作 sleep 3修改成sleep$[$RANDOM/10000*5],执行结果仍然是顺序的。虽然例3的方式其执行过程是乱序的,考虑到如果使用脚本只是查询统计信息,可以利用Excel中的lookup、match、indirect函数进行信息整理,也是行得通的

    展开全文
  • php脚本守护进程设计

    千次阅读 2016-09-06 18:48:18
    思路: while 循环,若当前没有数据要操作可以休眠; crontab 脚本每隔固定时间段执行该脚本,执行时先检测是否已在执行,若无 执行,有则 跳过。

    思路:

    while 循环,若当前没有数据要操作可以休眠;
    crontab 脚本每隔固定时间段执行该脚本,执行时先检测是否已在执行,若无 执行,有则 跳过。
    nohup  后台执行
    flock -xn  加锁
    2>&1 表示不仅命令行正常的输出保存到xx.log中,产生错误信息的输出也保存到xx.log文件中;

    实例:
    要执行代码:index.php

    <?php
    set_time_limit(0);
    //死循环
    while(1) {
        $message = '1111111' . "\n";
        error_log($message);
        sleep(5);
    }
    
    #/tmp/lock/test1.lock 为当前进程要锁定的文件,不同的进程配置不同的锁文件,该文件会自动创建
    * * * * * flock -xn /tmp/lock/test1.lock -c 'nohup php index.php >> /php/test.log 2>&1 &'
    
    * * * * * flock -xn /tmp/mytest.lock -c 'php /home/fdipzone/php/test.php >> /home/fdipzone/php/test.log'  

    在写好的php脚本。为防止守护进程内存溢出,建议定期检测内存占用。
    将以下代码放到业务脚本中:

    if(memory_get_usage()>100*1024*1024){
        exit('内存溢出');//大于100M内存退出程序,防止内存泄漏被系统杀死导致任务终端
    }

    注意:
    nohup 任务查看与关闭方法:
    关闭:

    //方法一:
    ps -e | grep commend
    kill -9 pid
    //方法二:
    fg %n   //n为jobs命令查看的进程号

    查看:

    //查看后台进程
    jobs    

    原理:

    使用linux flock 文件锁实现任务锁定,解决冲突

    格式:
    flock [-sxun][-w #] fd#
    flock [-sxon][-w #] file [-c] command
    选项
    [plain] view plain copy
    -s, --shared:    获得一个共享锁  
    -x, --exclusive: 获得一个独占锁  
    -u, --unlock:    移除一个锁,通常是不需要的,脚本执行完会自动丢弃锁  
    -n, --nonblock:  如果没有立即获得锁,直接失败而不是等待  
    -w, --timeout:   如果没有立即获得锁,等待指定时间  
    -o, --close:     在运行命令前关闭文件的描述符号。用于如果命令产生子进程时会不受锁的管控  
    -c, --command:   在shell中运行一个单独的命令  
    -h, --help       显示帮助  
    -V, --version:   显示版本  

    运行一个php文件,文件锁使用独占锁,如果锁定则失败不等待。参数为-xn

    * * * * * flock -xn /tmp/mytest.lock -c 'php /home/fdipzone/php/test.php >> /home/fdipzone/php/test.log'  

    这样当任务未执行完成,下一任务判断到/tmp/mytest.lock被锁定,则结束当前的任务,下一周期再判断。

    展开全文
  • CentOS 定时运行脚本配置

    万次阅读 2016-01-22 16:30:30
    很多时候我们有希望服务器定时去运行一个脚本来触发一个操作,比如使用七牛的工具上传,如果同步文件里面有新增加一个文件,这个时候我们可以提供定时脚本去完成我们需要的同步命令(七牛的qrsbox工具是自动会同步的...
  • 背景: 需要一个shell 脚本去remote服务器拷贝文件(scp command),环境有SIT,UAT,PROD三个。 问题描述: 三种环境对应的remote server不一样,但是shell只需要提供一个。...创建一个配置文件:test_jason.cfg
  • mutt发送邮件配置:路径:/usr/...相关文件下载链接安装以及配置脚本:install.sh运行install.sh即可,邮件配置都在install.sh中,Mail_USER发送方邮箱名,Mail_PWD发送方邮箱密码。(运行中会有问题:no curses libr
  • 开发环境tomcat下经常重新部署,需要关闭tomcat进程,判断是否关闭成功,配置文件替换,图片备份,再启动tomcat. 通过ps和awk命令,可以把关闭和启动tomcat命令都集成到一个脚本中,一键部署更新. 以下是一个真实列子:is ...
  • #根据系统所识别到的网卡个数,决定修改ifcfg-eth$x文件,在修改这个网卡配置文件之前首先确定这个文件是否存在。 #如果存在,则把系统识别到的所有网卡的MAC地址写入该文件作为注释,便于记录和检查。 #在处理...
  • 文章目录一、Hadoop集群启停脚本 myhadoop.sh1、编写脚本2、脚本解读3、测试二、查看三台服务器Java进程脚本 jpsall1、编写脚本2、脚本解读3、测试三、脚本分发 在配置两个脚本之前,需要配置好ssh免密登陆 一、...
  • 概要 目前在做个发布项目,...最后决定使用Systemctl守护进程来做,一方面是因为Crontab最小粒度只支持到一分钟,也就是1分钟执行1次,而这个脚本需要的实时性较高,7、8秒一次,另一方面,使用守护进程来做的话,...
  • Linux Service配置文件的编写

    千次阅读 2020-10-11 15:04:39
    通过编写Service配置文件,可以使用Linux的 systemctl 命令来达到管理服务的启动、自启动、停止 特定脚本进程。 编写方法: 文件命名:xxxx.service [Unit] Description=Frp Server Service #服务的描述信息 ...
  • CentOS定时执行shell脚本配置

    千次阅读 2017-06-19 13:55:05
    使用shell脚本设置redis的snapshotting持久化,并备份
  • tomcat 监控功能共需要两个脚本,如下: initMonitor.sh#!/bin/sh #初始化监控脚本相关变量 export tomcat_name=apache-tomcat-8.5.6 export tomcat_home=/usr/local/apache-tomcat-8.5.6 #测试接口访问地址 expor
  • Hadoop配置文件

    万次阅读 2014-08-19 12:48:03
     Hadoop有三个重要的配置文件:core-site.xml,hdfs-site.xml,mapred-site.xml,但这三个文件默认情况下均为空,其默认值保存在core-default.xml,hdfs-default.xml,mapred-default.xml中。这三个默
  • 基本实现思路是,编写一个监控脚本,然后在系统的crontab中将该脚本配置为定期自动执行(例如可以配置为每5分钟执行一次),监控脚本通过监控服务进程的端口或日志文件的修改时间等来判断服务进程是否已异常终止或不...
  • supervisor+shell脚本管理进程(redis demo)

    千次阅读 2018-12-05 22:33:00
    ​ 使用shell脚本封装supervisor 支持start stop status restart。能够使用 control redis start|stop|status|restart 管理redis进程 并且在redis意外退出时重启(用kill命令模拟) ​ 其中redis可被替换为其他二进制...
  • Zabbix 使用自定义脚本监控进程内存和 CPU 使用情况 首先,用脚本利用 ps 命令的反馈信息查看进程的 Cpu 及内存使用情况: ######################################################################### # File Name...
  • python写个进程监控的脚本

    千次阅读 2015-05-21 13:26:09
    废话不多说了,直接贴代码,大家配置文件都是喜欢用xml我不太喜欢,下面这个是自定义配置文件: class_config.py #!/usr/bin/env python #coding:utf-8 '''此处定义邮件的相关参数''' class Mail_conf(): sender ...
  • [喵咪Liunx(1)]计划任务队列脚本后台进程Supervisor帮你搞定前言哈喽大家好啊,好久不见啊(都快一个月了),要问为什么没有更新博客呢只应为最近在录制PhalApi的视频教程时间比较少,作为弥补那么为大家带来一点干货...
  • Jenkins安装及部署脚本配置教程

    万次阅读 2018-09-01 16:28:02
    配置文件 JENKINS_HOME目录 jenkins日志文件 /usr/lib/jenkins/jenkins.war /etc/sysconfig/jenkins /var/lib/jenkins /var/log/...
  • linux配置文件详解

    千次阅读 2013-05-22 09:30:30
    每个 Linux 程序都是一个可执行文件,它含有操作... 几乎每个程序的行为都可以通过修改其配置文件来按照您的偏好或需要去定制。   一句话,没有。不熟悉 Linux 的用户(一定)会感到沮丧,因为每个配置文件看起来都
  • supervisor开机自动重启脚本 #! /bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin PROGNAME=supervisord DAEMON=/usr/bin/$PROGNAME CONFIG=/etc/$PROGNAME.conf PIDFILE=/tmp/$PROGNAME.pid DESC="supervisord daemon...
  • inux下定时执行任务的方法: ...cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间。 cron的配置文件称为“crontab”,是“cron table”的简写。 cron在3个地方查找配置文件: 1、/va
  • 上面原理仅供参考 2.3 脚本演示 启动脚本(参考脚本使用先写好shell脚本),将会进入等待 修改nginx.conf文件然后保存,然后可以看到配置文件重新加载 然后刷新浏览器看看,可以看到已经刷新 2.4 shell脚本 只需要...
  • XenServer关键的配置文件

    千次阅读 2016-05-31 16:32:21
    XenServer在启动的时候,会根据提前准备好的脚本以及XAPI程序去检查一系列的关键配置文件,确认这个关键的配置文件都处于正确的配置状态,并读取相应的参数和配置才能正常启动。如果稍微有关键的配置文件出现损坏...
  • 初学Tomcat,记录整理Tomcat的简介和配置文件信息
  • Hadoop重要配置文件

    万次阅读 2018-05-22 14:42:56
    l Hadoop的配置文件 1. Hadoop-site.xml, *-default.xml,*-site.xml,2. Core-default.xml: 默认的核心hadoop属性文件。该配置文件位于下面JAR文件中:Hadoop-common-2.2.0.jar3. Hdfs-default.xml : 默认的HDFS...
  • Apache主配置文件httpd.conf 详解

    万次阅读 2017-10-11 08:01:08
    Apache的主配置文件:/etc/httpd/conf/httpd.conf 默认站点主目录:/var/www/html/ Apache服务器的配置信息全部存储在主配置文件/etc/httpd/conf/httpd.conf中,这个文件中的内容非常多,用wc命令统计一共有1009行...
  • monit配置文件命令学习

    千次阅读 2013-07-28 11:49:47
    monit可以用来监视unix进程,程序,文件,目录,文件系统等(processes,programs, files, directories and filesystems)比如时间戳,校验和,或者大小发生改变都能...终于明白为什么为什么有两个monitrc配置文件了,

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 276,443
精华内容 110,577
关键字:

脚本、配置文件、进程