<?xml version="1.0" encoding="utf-8"?>
<search>
  <entry>
    <title><![CDATA[关于LNMP 环境open_basedir restriction in effect报错问题]]></title>
    <url>%2F2018%2F04%2F19%2Flnmpopen_basedir%2F</url>
    <content type="text"><![CDATA[关于LNMP 环境open_basedir restriction in effect报错问题 解决方法nginx1fastcgi_param PHP_ADMIN_VALUE "open_basedir=document_root/:/tmp/:/proc/"; 修改为1fastcgi_param PHP_ADMIN_VALUE "open_basedir=/data/log/walle/:$document_root/:/tmp/:/proc/"; php打开注视添加你要访问的文件夹路径1open_basedir = /data/log/walle/:/tmp/:/proc/]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>lnmp</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[加快ssh连接速度]]></title>
    <url>%2F2018%2F04%2F19%2F%E5%8A%A0%E5%BF%ABssh%E8%BF%9E%E6%8E%A5%E9%80%9F%E5%BA%A6%2F</url>
    <content type="text"><![CDATA[加快ssh连接速度 客户端设置 ssh客户端打开如下注释 /etc/ssh/ssh_config 123Host * GSSAPIAuthentication no GSSAPIDelegateCredentials no 重启ssh服务 1/etc/init.d/sshd restart 服务端设置 /etc/ssh/sshd_config12UseDNS noGSSAPIAuthentication no 2.重启ssh1service sshd restart]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>ssh</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[shell脚本结合zabbix玩转故障自愈]]></title>
    <url>%2F2018%2F01%2F19%2Fshell%E8%84%9A%E6%9C%AC%E7%BB%93%E5%90%88zabbix%E7%8E%A9%E8%BD%AC%E6%95%85%E9%9A%9C%E8%87%AA%E6%84%88%2F</url>
    <content type="text"><![CDATA[shell脚本结合zabbix玩转故障自愈 收到zabbix故障报警,匹配相应的规则触发不同的自愈机制.当然这个脚本功能不仅仅如此. [TOC] 脚本作用 利用zabbix实现故障自愈 http监控自愈 tcp端口监控自愈 微信/邮件消息通知 多方式远程批量执行 …… 实现逻辑(Zabbix故障自愈) 脚本内容1234567[root@blueking policeRecover]# tree -L 1.├── common.config #全局配置文件├── policeRecover.sh #核心执行脚本├── rule.config #规则配置文件 └── temp #临时存储文件 1 directory, 3 files 使用示例zabbix添加告警自愈脚本和相应参数1. Actions设置 对Actions进行特殊设置,Default subject / Default message ,消息内容是规则判断的主要依据。 图1图2图3 Default subject 1&#123;EVENT.ID&#125;_1#故障:&#123;HOSTNAME1&#125;:&#123;TRIGGER.NAME&#125; Default message 1triggervalue|&#123;TRIGGER.VALUE&#125;#hostname|&#123;HOSTNAME1&#125;#ipaddress|&#123;IPADDRESS&#125;#hostgroup|&#123;TRIGGER.HOSTGROUP.NAME&#125;#triggernseverity|&#123;TRIGGER.NSEVERITY&#125;#triggername|&#123;TRIGGER.NAME&#125;#triggerkey|&#123;TRIGGER.KEY1&#125;#triggeritems|&#123;ITEM.NAME&#125;#itemvalue|&#123;ITEM.VALUE&#125;#eventid|&#123;EVENT.ID&#125; Recovery operations Default subject 1&#123;EVENT.ID&#125;_0#已恢复:&#123;HOSTNAME1&#125;:&#123;TRIGGER.NAME&#125; Default message 1triggervalue|&#123;TRIGGER.VALUE&#125;#hostname|&#123;HOSTNAME1&#125;#ipaddress|&#123;IPADDRESS&#125;#hostgroup|&#123;TRIGGER.HOSTGROUP.NAME&#125;#triggernseverity|&#123;TRIGGER.NSEVERITY&#125;#triggername|&#123;TRIGGER.NAME&#125;#triggerkey|&#123;TRIGGER.KEY1&#125;#triggeritems|&#123;ITEM.NAME&#125;#itemvalue|&#123;ITEM.VALUE&#125;#eventid|&#123;EVENT.ID&#125; 2. Media types设置 3. Users 设置 Users需要关联该报警自愈的媒介 4. 上传脚本 将policeRecover上传到Zabbix服务器的alertscripts目录,并修改为可执行权限 12[root@localhost policeRecover]# ls common.config policeRecover.sh rule.config temp 磁盘空间不足,匹配规则配置后自动恢复1. 配置磁盘空间不足自愈规则(rule.config)1serial:2||env:dev||isactive:1||triggervalue:&#123;=,1&#125;||ipaddress:&#123;like,192.168.3%&#125;||triggername:&#123;like,Free disk space is less than%&#125;||triggerkey:&#123;=,vfs.fs.size[/var,pfree]&#125;||itemvalue:&#123;lt,20&#125;||cmd:echo '' &amp;&amp; echo 删除前/var大小&amp;&amp; du -sh /var &amp;&amp; find /var/log/logcenter/ -type f -mtime +10 -exec rm -f &#123;&#125; \\; &amp;&amp; echo 10天前的文件删除成功 &amp;&amp; echo 删除后/var大小&amp;&amp; du -sh /var||ischeck:1||returncode:0||returnreqiure:&#123;like,%成功%&#125;||returntimeout:60||runlevel:5 2. 自愈 模拟触发报警 zabbix收到报警 触发自愈规则 成功或失败发送微信或邮件消息 应用端口不存在时,匹配规则配置后自动恢复1. 配置端口不存在自愈规则(rule.config)1serial:1||env:dev||isactive:1||triggervalue:&#123;=,1&#125;||ipaddress:&#123;=,192.168.3.85&#125;||triggername:&#123;like,8080 service is down on%&#125;||triggerkey:&#123;=,net.tcp.port[,8080]||itemvalue:&#123;=,0&#125;||cmd:/bin/bash /usr/local/tomcat/bin/startup.sh ||ischeck:1||returncode:200||returnreqiure:&#123;like,%started%&#125;||returntimeout:60||runlevel:1 2. 自愈 模拟端口不存在 2.触发报警和规则 3.自愈成功 4.失败的情况 比如如果你的cmd配置错误 接口返回异常时,匹配规则配置后自动恢复1. 配置web监控(具体细节自行谷歌) 监控url,校验返回码和require 2. 设置接口自愈规则1serial:3||env:dev||isactive:1||triggervalue:&#123;=,1&#125;||ipaddress:&#123;=,192.168.3.102&#125;||triggername:&#123;like,首页200监控%&#125;||triggerkey:&#123;=,web.test.rspcode[3.102首页,首页]||itemvalue:&#123;=,404&#125;||cmd:/etc/init.d/nginx restart||ischeck:1||returncode:200||returnreqiure:&#123;like,%success%&#125;||returntimeout:60 3. 模拟网页404访问前模拟故障后 4. 触发报警和规则 5. 自愈 自定义规则,执行相应的恢复操作 其他自定义规则,可以根据相应的返回KEY，做相应的自愈操作。一切你想要自愈的操作都可以做到。需要注意如果是salt-api/ansible等远程执行传参数的时候，如果传特殊符号需要转义，ansible也不支持管道等符号 功能说明配置文件全局配置文件:common.config123456789101112131415161718192021222324252627282930313233343536373839404142434445#!/bin/bash#基础配置文件#1.0 规则配置相关#skipRuleParams:规则配置中跳过校验的字段#2.0 微信消息相关#CropID:微信企业号CropID,后台可查#Secret:微信企业号Secret,后台可查#AppID:企业号中的应用id#PartyID:企业号中的部门id,多个部门用‘|’分隔#isSendAll:0(只发送给个人) 1(发送给部门所有人)#sendUsers:部门成员id(微信号) 当isSendAll为0时发送给$&#123;sendUsers&#125;,多个用户用空格间隔#3.0 发送邮件相关(telnet发送无需安装mutt等组件)#smtp:邮件发送主机#smtpDomain:邮件发送后缀域名,比如test@abc.com,则配置为abc.com#from:邮件发送者#usernameBase64:邮件用户名base64#passwordBase64:邮件密码base64#toEmail:发送给谁,多个收件人用空格间隔#4.0 不同环境下的基础配置项#*Conf为不同环境下的配置项目,规则配置中将会用到#devConf开发环境配置#testConf测试环境配置#zzbConf准生产环境配置(预生产环境)#comConf生产环境配置#4.1 自愈远程执行方式一: 自定义api远程执行#api:自定义api sync:是否同步(true或false默认异步) async:是否异步(true或false默认异步) #rex_env:执行环境(默认local,即本地环境) auth_type:认证类型(可选:password,key,config) 、#user:用户名 password:密码 salt_env:api的执行环境(默认saltapi-com,可选saltapi-dev)#returncode:全局默认http返回码/bash执行返回码 returntimeout:全局默认http超时时间/bash连接超时时间#4.2 自愈远程执行方式二: salt-api远程执行#saltUrl:salt-api的url地址 saltUsername:salt-api的用户名 saltPassword:salt-api的密码 #4.3 自愈远程执行方式三: ssh expect &amp;&amp; 自愈远程执行方式四: sshpass #sshUsername:全局ssh用户名(如规则配置不存在取全局) sshPassword:全局ssh密码(如规则配置不存在取全局)#4.4 自愈远程执行方式五: ssh免秘钥执行 &amp;&amp; 自愈远程执行方式六: ansible#5.0 全局执行级别#runlevel:当规则配置项不存在取全局默认执行方式#runlevel:0(自定义api) 1(salt-api) 2(免秘钥ssh执行) 3(ssh expect函数执行) 4(ansible远程执行) 5(sshpass) 规则配置文件:rule.config123456789101112131415161718192021222324252627282930313233343536#!/bin/bash#规则库配置#一行代表1条规则配置,排除全局配置中配置的$&#123;skipRuleParams&#125;中要跳过校验的字段以外,其他字段都是必须校验的字段,以||为间隔#1.0 非规则库校验的字段#skipRuleParams#serial:序号(唯一) env:执行环境 dev:读取全局配置devConf test:读取全局配置testConf 52zzb:读取全局配置zzbConf com:读取全局配置comConf #isactive:0(不启用该条规则) 1(启用该条规则) #cmd:自愈执行命令 #1.1 自愈执行后校验返回结果#ischeck: 0(不校验返回结果) 1(校验返回结果)#returncode(http返回码/执行返回值) returnreqiure(返回内容判断) returntimeout(返回超时时间/连接超时时间,单位秒)#2.0 规则配置中远程执行方式#runlevel:0(自定义api) 1(salt-api) 2(免秘钥ssh执行) 3(ssh expect函数执行) 4(ansible远程执行) 5(sshpass) 不存在时:取全局的runlevel#3.0 规则库配置#除了skipRuleParams中排除的字段,其他字段为zabbix返回要校验的字段,可以为1个或多个字段(无限制,根据你的zabbix内容设置)#解释我使用到几个关键字段#3.1 举例#triggervalue:&#123;=,1&#125; 条件1: triggervalued=1时,也即故障报警时#ipaddress:&#123;=,192.168.3.102&#125; 条件2: 故障主机为192.168.3.102#triggername:&#123;like,Free disk space is less than%&#125; 条件3: 故障名称为Free disk space is less than开头时#triggerkey:&#123;=,vfs.fs.size[/var,pfree]&#125; 条件4: 故障报警的key,这里指的/var空间不足时#itemvalue:&#123;lt,20&#125; 条件5: 故障报警key的值,这里指的是/var的空间不足20%时#以上条件为并且条件,只有都成立时才会触发cmd自愈.也可以只有2个条件或者更多的条件比如条件4和条件2,看你的报警需求#3.2 规则库的规则格式#||zabbix设置的key:&#123;条件,预期值&#125;||#3.3 规则库的支持条件#数值比较(支持浮点数) gt:大于 lt:小于 ge:大于等于 le:小于等于 eq:等于#字符串相等 ＝#模糊匹配 string%: 以string开头 ％string: 以string结尾 ％string％: 中间包含string 日志 其他功能告警收敛 将收集到数据保存到redis或mongodb中,进行报警数据聚合和分析,分析出有价值的信息。后续在补充这个功能 脚本复用1. 邮件消息发送 邮件发送 123# main "$1" "$2"source $&#123;commonConf&#125;sendMail "邮件的主体" "邮件的内容" 发送给某个传参过来的用户 1234# main "$1" "$2"source $&#123;commonConf&#125;toEmail=$1sendMail "邮件的主体" "邮件的内容" 2. 微信消息发送 微信消息 123# main "$1" "$2"source $&#123;commonConf&#125;sendWeixin "微信消息" 发送给某个传参过来的用户 1234# main "$1" "$2"source $&#123;commonConf&#125;sendUsers=$1sendWeixin "微信消息" 发送整个部门 1234# main "$1" "$2"source $&#123;commonConf&#125;isSendAll=0sendWeixin "微信消息" 发送个某个部门 12345# main "$1" "$2"source $&#123;commonConf&#125;isSendAll=0PartyID=$1sendWeixin "微信消息" 3. 远程执行 salt-API接口 1234# main "$1" "$2"source $&#123;commonConf&#125;getsaltToken "[saltUrl]" "[saltUsername]" "[saltPassword]"runsaltTask "[执行主机]" "[执行命令]" "[超时时间]" "[临时文件]" "[锁文件]" 免秘钥ssh执行 123# main "$1" "$2"source $&#123;commonConf&#125;keyLessRun "[ssh用户名]" "[执行主机]" "[执行命令]" "[超时时间]" "[临时文件]" "[锁文件]" [expect]ssh执行 123# main "$1" "$2"source $&#123;commonConf&#125;sshExpectRun "[ssh用户名]" "[执行主机]" "[执行命令]" "[超时时间]" "[临时文件]" "[锁文件]" "[ssh密码]" ansible远程执行 123# main "$1" "$2"source $&#123;commonConf&#125;ansibleRun "[执行主机]" "[执行命令]" "[超时时间]" "[临时文件]" "[锁文件]" sshpass远程执行 123# main "$1" "$2"source $&#123;commonConf&#125;sshPassRun "[ssh用户名]" "[执行主机]" "[执行命令]" "[超时时间]" "[临时文件]" "[锁文件]" "[ssh密码]" 4. 监控url返回码,不正常时重启应用1234code=$(curl -m 8 -o /dev/null -s -w %&#123;http_code&#125; $&#123;url&#125;)if [[ $code != "200" ]];then#执行上面的远程指令fi zabbix_server=>start: zabbix服务端触发告警脚本 self_recover=>operation: zabbix服务端告警(自愈脚本) analysis_alert_content=>operation: 分析告警内容以及参数 match_rule=>condition: 判断是否满足自愈规则 exit_action=>end: 退出操作 rule_cmd_run=>operation: 根据规则配置执行自愈操作 check_result=>condition: 根据规则配置校验自愈结果(是否成功) run_cmd_fail=>end: 退出并触发微信和邮件报警 rule_center=>subroutine: 规则配置库 zabbix_server->self_recover->analysis_alert_content->rule_center->match_rule match_rule(no)->exit_action match_rule(yes)->rule_cmd_run->check_result check_result(no)->run_cmd_fail{"scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12} var code = document.getElementById("flowchart-0-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-0-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-0", options);]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>zabbix自愈</tag>
        <tag>故障自愈</tag>
        <tag>多方式远程批量执行</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[mac添加路由]]></title>
    <url>%2F2018%2F01%2F19%2F%E7%AC%AC3%E5%91%A8%20mac%E6%B7%BB%E5%8A%A0%E8%B7%AF%E7%94%B1%2F</url>
    <content type="text"><![CDATA[mac添加路由查看路由1netstat -r 添加缺省路由1route -n add defalut 10.13.31.1 添加路由1route -n add -net 10.0.0.0/8 10.13.31.1 删除路由1route -n delete defalut 10.13.31.1]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>mac添加路由</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[关于服务启动按钮页面的优化]]></title>
    <url>%2F2018%2F01%2F19%2F%E7%AC%AC4%E5%91%A8%20%E5%85%B3%E4%BA%8E%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%8C%89%E9%92%AE%E9%A1%B5%E9%9D%A2%E7%9A%84%E4%BC%98%E5%8C%96%2F</url>
    <content type="text"><![CDATA[关于服务启动按钮页面的优化 原则 同一个服务器只允许启动一个按钮,也就是只能触发一个启动/关闭/重启的功能。不同的服务器是可以同时异步触发的。 启动或关闭是异步进行的。 启动或关闭的时候，同一个服务器的上按钮变灰色，并且不能点击。 问题由于妹子ui的模态框在数据传输存在bug,详情撮: http://amazeui.org/javascript/modal所以在多个异步并发执行的时候出现各种Bug. 123456789101112131415161718$(function() &#123; $('#doc-modal-list').find('.am-icon-close').add('#doc-confirm-toggle'). on('click', function() &#123; $('#my-confirm').modal(&#123; relatedTarget: this, onConfirm: function(options) &#123; var $link = $(this.relatedTarget).prev('a'); var msg = $link.length ? '你要删除的链接 ID 为 ' + $link.data('id') : '确定了，但不知道要整哪样'; alert(msg); &#125;, // closeOnConfirm: false, onCancel: function() &#123; alert('算求，不弄了'); &#125; &#125;); &#125;);&#125;); 通过 relatedTarget 这个钩子获取数据，如上面的演示，以该元素为桥梁获取想要的数据（2.1 开始支持）； 最初代码的引用1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162$('#my-confirm').modal(&#123; relatedTarget: this, onConfirm: function(options) &#123; if (start_store != undefined) &#123; $("#msgtips").html('[服务器名称:' + start_store.alias + '] 正在启动,请等待启动完成或使用批量启动.'); $('#my-alert').modal('open'); return; &#125;else&#123; store.set('start_store', &#123; code: '1', alias: dename &#125;) &#125;; my_this = this.relatedTarget; $.ajax(&#123; type: "POST", async:true, url: "/api/service", cache: false, data: data, dataType: "json", success: function(res)&#123; var alias = res.data.data[0].alias; var code = res.data.data[0].code; var reskey = res.data.data[0].key; var msg = res.data.data[0].msg; var resnetwork_ip = res.data.data[0].network_ip; console.log(res); if ( code == 1 ) &#123; $("#msgtips").html('[服务器名称:'+alias+'启动成功!'); $('#my-alert').modal('open'); closeloading(my_this); &#125;else&#123; $("#msgtips").html('[服务器名称:'+alias+']启动失败,'+msg+'!'); $('#my-alert').modal('open'); closeloading(my_this); &#125; store.remove('start_store'); closeloading(my_this); &#125;, error:function()&#123; $("#msgtips").html('[服务器名称:'+$(my_this).attr("dename")+'] 请求失败,请联系管理员!'); $('#my-alert').modal('open'); closeloading(my_this); store.remove('start_store'); &#125; &#125;); &#125;, onCancel: function() &#123; my_this = this.relatedTarget; closeloading(my_this); // var store = $.AMUI.store; store.remove('start_store'); &#125; &#125;); 改进后代码的引用1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586$('#my-confirm').modal(&#123; relatedTarget: this, onConfirm: function(options) &#123; var my_this ; my_this = this.relatedTarget; if (start_store != undefined) &#123; $("#msgtips").html('[服务器名称:' + start_store.alias + '] 正在启动,请等待启动完成或使用批量启动.'); $('#my-alert').modal('open'); closeloading(my_this); return; &#125;else&#123; store.set('run_service_allow_one', &#123; code: '1', alias: dename &#125;) &#125;; data = store.get('data'); $.ajax(&#123; type: "POST", async:true, url: "/api/service", cache: false, data: data, dataType: "json", success: function(res)&#123; console.log('get res result:'); console.log(res); // var code = res.data.data[0].code; console.log(code); if (code == 10020) &#123; $("#msgtips").html('[服务器名称:'+res.get_status.data.data[0].related_servername+']'+res.msg + '&lt;br/&gt; 最后时间: '+ res.get_status.data.data[0].updated_time + '&lt;br/&gt; 动作: '+ res.get_status.data.data[0].action + ' 操作人: '+ res.get_status.data.data[0].operation ); $('#my-alert').modal('open'); closeloading(my_this); &#125; else if (code == 10041)&#123; $("#msgtips").html('[服务器名称:'+res.get_status.data.data[0].related_servername+']'+res.msg + '&lt;br/&gt; 最后时间: '+ res.get_status.data.data[0].updated_time + '&lt;br/&gt; 动作: '+ res.get_status.data.data[0].action + ' 操作人: '+ res.get_status.data.data[0].operation ); $('#my-alert').modal('open'); closeloading(my_this); &#125;else if (code == 10042)&#123; $("#msgtips").html('[服务器名称:'+res.get_status.data.data[0].related_servername+']'+res.msg + '&lt;br/&gt; 最后时间: '+ res.get_status.data.data[0].updated_time + '&lt;br/&gt; 动作: '+ res.get_status.data.data[0].action + ' 操作人: '+ res.get_status.data.data[0].operation ); $('#my-alert').modal('open'); closeloading(my_this); &#125;else if (code == 1 )&#123; var alias = res.data.data[0].alias; var reskey = res.data.data[0].key; var msg = res.data.data[0].msg; var resnetwork_ip = res.data.data[0].network_ip; $("#msgtips").html('[服务器名称:'+alias+'启动成功!'); $('#my-alert').modal('open'); closeloading(my_this); &#125;else&#123; var alias = res.data.data[0].alias; var reskey = res.data.data[0].key; var msg = res.data.data[0].msg; var resnetwork_ip = res.data.data[0].network_ip; console.log(my_this); $("#msgtips").html('[服务器名称:'+alias+']启动失败,'+msg+'!'); $('#my-alert').modal('open'); closeloading(my_this); &#125; store.remove('run_service_allow_one'); closeloading(my_this); &#125;, error:function()&#123; $("#msgtips").html('[服务器名称:'+$(my_this).attr("dename")+'] 请求失败,请联系管理员!'); $('#my-alert').modal('open'); closeloading(my_this); store.remove('run_service_allow_one'); &#125; &#125;); &#125;, onCancel: function() &#123; var my_this ; my_this = this.relatedTarget; closeloading(my_this); // var store = $.AMUI.store; store.remove('run_service_allow_one'); &#125; &#125;); 我这边的主要的问题现象: 同一个页面点击启动，再次点击启动或关闭，还是上一次的post传参。 正在启动中或者关闭中的那个提示在点击多次时后面不能正常返回。比如我同时点击了启动和关闭，然后页面显示启动中和关闭中，然后返回数据后，启动中按钮变回启动，但是关闭中一直没返回。 解决针对以上的问题后面的代码已经解决，主要是妹子ui模态框传参的Bug问题，调用多次模态框模块框只会保存第一次运行时的数据。 第1个问题: 通过store存储传参，每点击一次覆盖前一次的参数。(可能存在的问题: 如果启用无缝浏览则无法传data参数，如果点击过快参数赋值就会错乱，但是这种情况应该很少，参数赋值那块也就微妙级别，人的手工基本不会达到那种地步) 还有种方法就是通过relatedTarget钩子重新获取数据。推荐这个方法。 第2个问题: 其实使用了relatedTarget钩子，但变量初始化的时候存在问题，之前没有var 定义局部变量，导致后面点击有可能获取全局变量的数据，导致my_this对象串了。重新初始化变量就OK了。 上图:]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>服务控制</tag>
        <tag>启动构思</tag>
        <tag>思路优化</tag>
        <tag>前端</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[应用的日志分析、对比以及实践]]></title>
    <url>%2F2018%2F01%2F19%2F%E7%AC%AC5%E5%91%A8%20%E5%BA%94%E7%94%A8%E7%9A%84%E6%97%A5%E5%BF%97%E5%88%86%E6%9E%90%E3%80%81%E5%AF%B9%E6%AF%94%E4%BB%A5%E5%8F%8A%E5%AE%9E%E8%B7%B5%2F</url>
    <content type="text"><![CDATA[应用的日志分析、对比以及实践前言 随着业务量的增长，服务器的增长，同时应用日志的数量也是呈现几何的速度增长。大部分人的认为日志数据对业务来说只是开发人员排除故障的依据，除此以外对业务而言是没有任何的意义的。我相信，对很多人的认知来说日志也就那么点的作用。不可或缺，但是也是很鸡肋。需要它的时候，迫不及待，不需要它的时候弃之如敝履。 作用 常见作用: 排问题，查日志（点） 日志记录代码的执行记录，记录异常信息，排查代码的隐藏bug 记录业务逻辑，查询业务上的问题或者追踪相关信息 非常见作用: 数据分析（面） 根据错误日志的错误处，统计错误率，针对性的对代码进行优化 根据时间轨迹，可以统计出业务的集中时间和接口调用次数等统计 统计用户业务轨迹 …….更多的数据价值待挖掘，比如从日志中统计用户类型、用户访问习惯、用户停留时间、用户的等待时间等等各个方面，针对性的优化应用，提升用户的访问体验。 变化到目前为止，参照我们系统( 某上市互联网保险中介 )应用，就日志而言，我们经历了以下几个时间段的变化，也经历很多方面的尝试。就目前我们的应用日志系统经历了以下的变化: 原生时代 描述: 早期的终端原生时代，由于业务和服务器的规模不是很大，针对应用的日志并没有做相应的的处理和优化。都只是应用容器本身的日志处理，开发需要看日志就去对应的服务器上看相应的日志。比如tomcat下自由log4j下的catalina.out等等。 特点: 方便，对开发相对友好，因为在自己的PC开发环境中，开发更加习惯在文本或者终端查看日志。但是在linux平台下查看应用日志，需要具体的一定的Linux日志命令的相关基础知识，如tail、awk等 nfs共享 描述: 随着业务规模的增加，服务器的数量增长，应用日志的数量也在增加。通常一个业务还有7到8个集群节点的日志，这时候如果还是采用的原生时代的日志查看方式会显得的很费力。查一个日志可能要登陆10多个终端在日志当中去排除问题。所以在这时候的我们考虑将日志归集到一起，这样就避免了开多个服务器去看日志的问题。 特点: 相对于原生时代来说，其实没有发生了什么变化。只是不需要登陆多个服务器，只登陆一台服务器就能看到所有服务器的日志。 splunk 描述: 这是一款商业的日志系统，集合日志收集、处理、分析等一体的日志解决方案。当日志文件超过500M就要收费的。但就它的功能而言，各方面的表现都非常不错的。web可视化，日志异常，资源占用率等很不错。唯一的是，基于当时的业务情况并不适合在日志收集去投入额外的资产支出，所以后续就放弃了。 特点: 采用CS结构，各方面的都比较优秀。 log.io日志系统 描述: 这是一款开源的实时日志系统，它只实时显示日志，并不对日志做存储。也是C/S结构，采用node的语言编写而成。 特点: 采用CS结构，小巧易于使用。 elk 描述: 这是一款开源的集中式日志系统，也是目前很多互联网公司主推的开源日志系统。ELK 其实并不是一款软件，而是一整套解决方案，是三个软件产品的首字母缩写，Elasticsearch，Logstash 和 Kibana。从日志收集、聚合、全文搜索、展现等拥有一套完整的解决方案。社区和文档也比较完善，可以进行自定义二次开发。 特点: 采用CS结构，功能强大。 flume 描述: 这是一款开源的日志收集的解决方案，并不对日志进行分析，flume是一个高可用的，高可靠的，分布式的海量日志采集、聚合和传输的系统。通过与kafka等结合做日志解决方案。特点: 采用CS结构，可扩展性强，存储丰富比如HDFS. 自研平台 描述: 综合业务等个方面的特点自定义的开发日志系统。特点: 自主性强、适合业务的可持续性扩展。 使用对比 调研 前置环境: 服务器数量: 40 +应用容器类型: tomcat/resin/php等日志大小: 500M &gt; size &lt; 5G环境: 集群环境 需求调研 方便开发人员查询日志，排除故障 不占用系统资源，一般日志系统采用C/S结构，客户端的资源占用率必须保障在3%以下 扩展性强，易于进行二次开发 总结目前在行业内日志处理方案，有开源的，也有商业级别，也可以自行开发。至于你要选择什么解决方案，完全要依赖于你的业务需求和环境，如果你有更加高的要求的日志要求，且对费用没什么担心，商业版本的日志解决方案无疑是最佳的解决方案。如果你的资产投入有限，或者想自定义日志的系统，开源或者自研也是可以的。选择最合适业务，然后去调研、测试，来最贴近你的业务需求。 st=>start: 原生时代 e=>end: 自研平台 op=>operation: syslog-ng op1=>operation: nfs共享 op2=>operation: splunk op3=>operation: log.io日志系统 op4=>operation: elk op5=>operation: flume st->op->op1->op2->op3->op4->op5->e{"scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12} var code = document.getElementById("flowchart-0-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-0-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-0", options);]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>日志系统对比和分析</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[windows自定义程序开机启动]]></title>
    <url>%2F2017%2F06%2F18%2F%E7%AC%AC2%E5%91%A8%20windows%E8%87%AA%E5%AE%9A%E4%B9%89%E7%A8%8B%E5%BA%8F%E5%BC%80%E6%9C%BA%E5%90%AF%E5%8A%A8%2F</url>
    <content type="text"><![CDATA[windows自定义程序开机启动前言 每次开机之后要手工启动各种服务，有一些程序是自带了添加服务项，添加到开机启动，有一些则没有。昨天刚装完机器，什么开机启动需要自己添加，所以整理了一下开机启动的相关技巧。 windows开启开机启动方法 服务启动 服务启动是电脑启动时，用户登陆之前启动，有系统服务程序控制。 启动项启动 启动项是用户登陆之后启动的。 服务启动添加服务启动启动example sc create 服务名 binPath= &quot;路径&quot; start= auto type= share1sc create Frpc binPath= "C:/frpc/windows/start.bat" start= auto type= share cmd添加服务存在问题 通过sc创建的服务在启动的报错: 服务没有响应控制功能但是！不是所有程序都可以作为服务的方式运行，因为作为服务运行需要能返回运行情况等信息，所以有的程序添加后会出现以下提示：Windows无法启动 XXX 服务（位于 本地计算机上）。错误1053:服务没有及时响应启动或者控制请求。解决方法:既然知道了原因，就有了解决办法，微软有一个srvany.exe可以解决此问题，首先创建一个服务，但是执行文件要选择srvany.exe，然后在另外的属性里面加入要执行的文件信息就可以了。（提前下载srvany.exe到C:\Windows目录下,不要放System32文件夹，因为64位系统会出现兼容性问题）Srvany.exe下载地址 http://u.x2009.net/q 123456sc create ServiceName binPath= "C:\Windows\srvany.exe" start= auto#加入要执行的文件的信息reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ServiceName\Parameters /v Application /t REG_SZ /d "这里填入你要作为服务运行的程序地址比如c:\xxx.exe" /freg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ServiceName\Parameters /v AppParameters /t REG_SZ /d "如果程序需要参数则填在这里，如果不需要，清空这段文字或者整行" /freg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ServiceName\Parameters /v Application /t REG_SZ /d "这里填入程序运行时所在文件夹（作为环境变量），如果不填，则清除这段内容或者直接删除本行" /f然后启动服务即可。(其中一条命令即可) 12sc start ServiceNamenet start ServiceName 因为操作较为复杂，所以有人写了一款软件，叫SrvanyUI，集成了了srvany.exe，新建服务较为简单（打开软件，点增加服务，选自建服务即可达到相同效果）。SrvanyUI下载地址 http://u.x2009.net/l注意:以上所有命令都需要管理员权限才能运行，如果是Windows 8/8.1/10，需要SYSTEM权限才行（在开始菜单里找到命令行提示符，右键里面有使用管理员身份运行） 删除服务启动删除example sc delete 服务名1sc delete Frpc 启动项启动直接将启动文件丢在以下目录中: C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup windows后台执行 有时候定制cmd的会一直显示console的终端，以下为定制后台执行的方法。start.vbe:12set ws=wscript.createobject("wscript.shell")ws.run "C:/frpc/windows/start.bat /start",0 注意如果开了360软件请将加入可信。]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>运维笔记</tag>
        <tag>windows服务</tag>
        <tag>开机启动</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[运维归档的起始]]></title>
    <url>%2F2017%2F06%2F09%2F%E7%AC%AC1%E5%91%A8%20%E8%BF%90%E7%BB%B4%E5%BD%92%E6%A1%A3%E7%9A%84%E8%B5%B7%E5%A7%8B%2F</url>
    <content type="text"><![CDATA[第1周 运维归档的起始运维归档的前言 很早之前就想对自己这几年的运维经验作为一个全面的总结，然后由于各种原因(借口)一直没有行动起来。最近才下定决心开始的运维总结和归纳之旅,其实之前也一直做笔记和归纳，看了下我的印象笔记和文档总结，不下于2000篇笔记和文档，精华性的文档总结预计在200篇左右。从14年开通了开源中国的博客，断断续续的写了90多篇博客文章，推荐博客也有上10篇。截止目前的访问量: 17万 总结和归纳的意义 加深自己对知识的理解 强迫症患者 (在印象笔记 || 收藏的标签 || 收集的一些资料中,记录了很多的小技巧和知识点,但是这些点很凌乱,看起来的不是很规整,很想将这些知识点重整化为一个整体) 传道者 不觉得的自己技术能力有多牛掰，但是还是希望能在运维知识的价值传播上做作出自己的一点贡献 开源精神无处不在开源精神，分享快乐 就定一个小目标 1周至少一篇总结和归纳 分享的内容不做限制，可以是技术、生活经验、工作总结、管理和沟通等方面 分享方式 个人博客 [首发] 开源博客 微信公众号 公众号还在紧急筹备当中… 近期在做的事 从年初开始一直到现在一直在做运维平台化的工作,也即是devops的筹备和开展工作。为什么要做运维平台化？怎么开展运维平台化的工作？运维平台化的工作中遇到什么了什么样的问题？针对中小企业如何去推动运维平台化和价值化的发展？带着这些问题我后续会单独在一个篇幅中去介绍和分享 开源项目 自动化发布系统基于Rex开发的一个自动化发布平台，基于终端的发布版本。后来其实一直做了很多BUG改进和改版，但是一些原因一直没有发布，打算在7月底在放一个更全面的可视化的自动发布系统版本,敬请期待。 关于我 2012年大学毕业 2012-至今 某上市互联网保险中介 运维经理 专长领域: 脚本编程、开源工具党、自动化运维、自动化部署、运维价值化、全栈工程师 经验简述: 早期参与IDC机房的建设，设计大数据的容灾系统，以及主导和规划IDC上公有云和金融云，从无到有开发了基于运维的自动化发布系统，目前致力于自动化运维和价值化运维的研究。]]></content>
      <categories>
        <category>运维归档</category>
      </categories>
      <tags>
        <tag>运维笔记|运维价值|前言</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[svn 钩子开启]]></title>
    <url>%2F2017%2F04%2F24%2F1%2F</url>
    <content type="text"><![CDATA[svn 钩子开启 背景:公司的Svn很多人在用，有不少人在作修改后不添加注释，所以需要强制用户填写注释。操作：1.重命名svn主目录中hooks的pre-commit.tmpl文件为pre-commit，并添加可执行权限12mv pre-commit.tmpl pre-commitchmod u+x pre-commit 编辑pre-commit文件 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071export LANG="zh_CN.UTF-8"REPOS="$1"TXN="$2"# Make sure that the log message contains some text.SVNLOOK=/usr/bin/svnlook#$SVNLOOK log -t "$TXN" "$REPOS" | \# grep "[a-zA-Z0-9]" &gt; /dev/null || exit 1commit_type=$(svnlook changed -t "$TXN" "$REPOS")#以下后缀可以不填写注释except_list=".txt,.docx,.doc,.xls,.xlsx,.ppt,/"num=0for i in $(echo -e "$except_list" |sed "s/,/\n/g")do sum=$(echo -e "$commit_type" |grep "$i$" |wc -l) if test[ $sum -ne 0 ];then num=$(expr $num + 1 ) fidonetotal=$(echo -e "$commit_type" |wc -l)if test[ $num -eq $total ];then exit 0fi$SVNLOOK log -t "$TXN" "$REPOS" &gt; /tmp/aaa.txt#强制用户提交注释,注释格式要求:bug/task+数字(任务数字编号)+注释(大于10)TEMP_LENGTH=`$SVNLOOK log -t "$TXN" "$REPOS"|sed 's/\s*$//g'|sed 's/^\s*//g'| wc --chars` # 获取字符数量(包括换行符)TEMP_LINE=`$SVNLOOK log -t "$TXN" "$REPOS"| wc --lines` # 统计换行符LOGMSG_LENGTH=`expr $TEMP_LENGTH - $TEMP_LINE` # 真实字符数量task=$( $SVNLOOK log -t "$TXN" "$REPOS" |grep "^task\-[0-9]*[0-9]\-" |wc -l )bug=$( $SVNLOOK log -t "$TXN" "$REPOS" |grep "^bug\-[0-9]*[0-9]\-" |wc -l )emrg=$( $SVNLOOK log -t "$TXN" "$REPOS" |grep "^emrg\-[0-9]*[0-9]\-" |wc -l )getlaststring=$($SVNLOOK log -t "$TXN" "$REPOS"|grep -o "^task\-[0-9]*[0-9]\-\|^bug\-[0-9]*[0-9]\-\|^emrg\-[0-9]*[0-9]\-")content=$($SVNLOOK log -t "$TXN" "$REPOS"|sed 's/\s*$//g'|sed 's/^\s*//g')if test[ $LOGMSG_LENGTH -eq 0 ];then echo "【注释】$content" 1&gt;&amp;2 echo "【注意】注释不能为空,请重新填写注释!!!" 1&gt;&amp;2 echo "【格式】:bug/task/emrg-数字任务编号-注释(大于10)" 1&gt;&amp;2 exit 1fiif test[ $task -eq 0 &amp;&amp; $bug -eq 0 &amp;&amp; $emrg -eq 0 ];then echo "【注释】$content" 1&gt;&amp;2 echo "【注意】注释必须以bug或者task开头,后面加-和数字编号,请重新填写注释!!!" 1&gt;&amp;2 echo "【格式】:bug/task/emrg-数字任务编号-注释(大于10)" 1&gt;&amp;2 exit 1ficommemt=$($SVNLOOK log -t "$TXN" "$REPOS"|sed 's/\s*$//g'|sed 's/^\s*//g'|sed "s/^$getlaststring//g"| wc --chars)commemt_line=$($SVNLOOK log -t "$TXN" "$REPOS" |sed "s/^$getlaststring//g"|wc --lines)commemt_length=$( expr $commemt - $commemt_line)if test "$commemt_length" -lt 10 ;then echo "【注释】$content" 1&gt;&amp;2 echo "【注意】注释必须超过10个字符,请重新填写注释!!!" 1&gt;&amp;2 echo "【格式】:bug/task/emrg-数字任务编号-注释(大于10)" 1&gt;&amp;2 exit 1fi# Check that the author of this commit has the rights to perform# the commit on the files and directories being modified.#commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1# All checks passed, so allow the commit.exit 一、问题 * pre-commit等钩子有做一些检查，如果有问题就echo错误信息，但出错信息是中文的，svn客户端无法显示，提示如下 Error output could not be translated from the native locale to UTF-8. 我们尝试过以下方法，但都没有解决 修改pre-commit的编码，修改LANG export LANG=zh_CN.UTF-8 export LC_ALL=zh_CN.UTF-8 修改Apache的编码 AddDefaultCharset UTF-8 采用http发布，而不是https 结论：网上的解决方案只对svn://这种直接用svnserve发布出来的仓库才有效 二、 解决方案 Subversion 1.8特性 SVNUseUTF8 On 它的作用就是使得Apache的mod_dav_svn模块，在和pre-commit等钩子通讯的时候，使用utf-8编码，可以参考mod_dav_svn 升级 我们系统是CentOS 6.2，比较简单，有个第三方，走了Subversion1.8的rpm包，yum即可，主要是更新了2个rpm包 * subversion-1.8.15-1.x86_64 * mod_dav_svn-1.8.15-1.x86_64 具体升级操作 cat &gt; /etc/yum.repos.d/wandisco-svn.repo &lt;&lt;EOF [WandiscoSVN] name=Wandisco SVN Repo baseurl=http://opensource.wandisco.com/centos/6/svn-1.8/RPMS/\$basearch/ enabled=1 gpgcheck=0 EOF yum install subversion -y 修改httpd.conf并重启httpd &lt;IfModule mod_dav_fs.c&gt; # Location of the WebDAV lock database. DAVLockDB /var/lib/dav/lockdb SVNUseUTF8 On &lt;/IfModule&gt; /etc/init.d/httpd graceful 升级后的测试 需要做些测试，确保升级后不会有问题，测试列表如下 * commit * update * log * merge * copy签出版本 注意问题: 服务器版本是1.8，如果客户端是1.6，则只能checkout，不能update，1.7没有问题，建议客户端至少1.8]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[nginx 反向代理问题小结]]></title>
    <url>%2F2016%2F10%2F27%2F2%2F</url>
    <content type="text"><![CDATA[nginx 反向代理问题小结 location /Autops { proxy\_pass http://a.test.com; } ① 循环跳转，nginx条件判断跳出 在nginx中配置好，死活都无法跳转。 通过F12查看,其实已经跳转过去了,但是接口在认证的地方循环在跳转。 {width=”554”height=”115”} 应该是登陆接口路由有问题，由于我请求的对方接口是直接访问，无需路由。所以的添加条件判断，请求完接口之后,直接退出。(此处应该去检查登陆路由，由于时间关系，直接采取回避的方法。) 匹配到/Autops/api接口下的任何请求，请求完毕之后直接break,不往下请求。 location /Autops/api/{ if (-e \$document\_root/Autops/api/dbuser/\$request\_uri) { rewrite \^/(.\*)\$ /Autops/api/dbuser/\$1 break; break; } } location / { try\_files \$uri \$uri/ /Autops/web/index.php?\$args; } 顺便了解下 try_files 的作用: 按照顺序请求如上地址,如果不存在或匹配不到会访问最后一个参数。也即是改写参数。 ② 请求跳转是不跳转非index文件 原服务器地址: http://b.test.com/Autops/api/dbuser/dbuser.php 实际跳转的是:http://a.test.com/Autops/api/dbuser/dbuser.php 实际的结果是 怎么都无法跳转，但是实际的访问接口是可以访问到。通过查看access日志,根本没有跳转过去，当你不加文件的时候是可以正常跳转过去的，也就是 原服务器地址: http://b.test.com/Autops/api/dbuser/ 实际跳转的是:http://a.test.com/Autops/api/dbuser/ 可以正常跳转，也就是当你直接访问接口的文件，即使你加上了反向代理，也是不会跳转的，而是直接访问当前服务器的应用。(低级错误！！！！)]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Perl与数据库DBI快速入门]]></title>
    <url>%2F2016%2F08%2F15%2F3%2F</url>
    <content type="text"><![CDATA[Perl与数据库DBI快速入门上次的文章Perl无废话入门指南中，简单的介绍了Perl的开发环境。为了完成提到的任务，还需要做几个知识点。无论是写脚本还是做CGI，如何使用Perl来访问数据库就是很有用的一个知识。 各种语言和开发环境访问数据库有各种不同的方式，比如可以用C和数据库提供的API接口来进行访问，也可以用JDBC、ODBC、ADO等封装好的统一接口来进行访问。Perl访问数据库最常用的包是DBI，可以在www.cpan.org找到。另外还需要安装对应数据库的驱动包，例如DBD::MySQL、DBD::Oracle、DBD::Sybase或者DBD::ODBC等。具体的安装方法请参考上期文章，在此就不赘述了。 下文以常见的MySQL为例，说说如何实现对数据库的操作。 1 基本流程习惯在Windows下开发数据库、熟悉ADO、ADO.NET的朋友，一定对ADOConnection/ADODataSet/ADOTable等类耳熟能详。DBI的接口与之类似，但在操作方法上又有不同，对ADO熟悉的朋友不妨比较一下异同。一般来说，数据库操作由以下几个步骤组成一个常见的流程： 1． 建立一个数据库连接 2． 通过建立的数据库连接，执行SQL语句 3． 执行SQL后获取返回的数据集 4． 在数据集中对记录进行处理，一般是一个循环的过程 5． 处理完毕，关闭数据库连接，释放资源 下面是按照上述的流程，在Perl中访问MySQL的一段代码，以这段代码为例，详细说明DBI的使用方法。 123456789101112131415#!/usr/bin/perl -wuse strict;use DBI;my $dbh = DBI-&gt;connect("DBI:mysql:test:192.168.1.2", 'root', 'password');my $sth = $dbh-&gt;prepare("SELECT * FROM test1");$sth-&gt;execute();while ( my @row = $sth-&gt;fetchrow_array() )&#123; print join('\t', @row)."\n";&#125;$sth-&gt;finish();$dbh-&gt;disconnect(); 注意代码中的灰色部分就是要特别关注的数据库访问接口，这里展现的只是一部分，下面将会依次说明每一个步骤，以及其它的操作在Perl中是如何实现的。 1.1 连接数据库my $dbh = DBI-&gt;connect(&quot;DBI:mysql:test:192.168.1.2&quot;, &apos;root&apos;, &apos;password&apos;); 调用DBI的方法DBI-&gt;connect来建立一个数据库的连接，如果连接成功则返回一个数据库连接句柄，之后执行SQL等操作都要把这个连接句柄作为一个操作参数。在connect调用中，首先要提供一个数据库连接串。这个连接串用冒号分为了几个部分，请看下表 小节 说明 DBI 接口类型 mysql 数据库类型 test 数据库名称 192.168.1.2 数据库主机地址 在前面例子中的连接串中，DBI表示这是DBI接口的一个连接串；mysql表示要连接的数据库是MySQL数据库（如果要连接Oracle数据库，这里则是oracle），不同的数据库有不同的连接串定义，可以参考DBI对应的访问驱动的说明；test指明了连接到数据库主机上的数据库名称；192.168.1.2就是MySQL服务器的IP地址。这里要注意的是，连接串中的数据库类型mysql必须小写。如果省略了主机名，则缺省为localhost。connect方法的后面两个参数是连接数据库主机的用户名和密码，这个可是不可缺少的J 如果在连接过程中出现任何错误，则connect的返回值都会是undef（和C语言中的NULL是一回事）。这里为了简化而略去了错误检查，实际做项目的时候应当对这些错误和返回值的进行检查。 1.2 执行SQL语句my $sth = $dbh-&gt;prepare(&quot;SELECT * FROM test1&quot;); $sth-&gt;execute(); $dbh-&gt;do(“UPDATE test1 SET time=now()”); 连接上了数据库，获得了数据库连接句柄，就可以利用这个句柄来对数据库进行操作了。要执行一条SQL语句，为了提高性能，DBI分两个步骤来做。先把SQL语句通过prepare方法提交到数据库，数据库为该语句分配执行资源，之后调用execute方法通知数据库执行该SQL语句。注意prepare方法是通过数据库连接句柄调用的，如果成功则返回一个该SQL的句柄，之后通过该SQL语句句柄调用execute执行SQL。一般来说execute执行的都是返回数据的语句（例如SELECT语句）。反之如果执行INSERT、UPDATE、DELETE、CREATETABLE等不需要返回数据的语句，则有一个更方便、快速的方法 $dbh-&gt;do(SQL语句)，可以省去prepare的步骤。do方法返回的是受该SQL影响的记录数量。 1.2.1 技巧：对SQL进行排版常写大段SQL的朋友可能会对于SQL中的引号很头痛，每每都因为引号的问题搞的SQL语句乱成一团分辨不清。还记得上篇文章讲过的qq吗？这里正是它的好用处。由于qq中的字符串同双引号””内的字符串一样会对变量进行解释，同时qq还可以换行。因此使用它来对SQL进行排版是非常好的一个选择，例如像这样的一条SQL语句： my $res_operator = $dbhandle-&gt;prepare( qq{ SELECT o_customerid, COUNT(*) AS totalMsgNum FROM mm4fcdrs WHERE (m_date&gt;&apos;$begindate&apos;) AND (m_date&lt;&apos;enddate&apos;) GROUP BY o_customerid }); 根本无需考虑引号的问题，可以和正常情况一样的写SQL，是不是方便了很多？ 1.2.2 通过SQL语句中的参数优化查询执行效率在执行大量INSERT之类的语句的时候，反复向数据库服务器提交同样结构的一个SQL语句，在这种情况下可以利用prepare和SQL参数来优化执行效率： 1．先使用prepare提交一个SQL模板给数据库服务器，把其中值的部分用参数占位符代替。2．使用prepare让服务器为该SQL准备了执行资源后，调用execute并在该方法中传入参数实际的值执行SQL。3．之后可以反复调用execute，不需要服务器重新prepare 假设要执行这样的一个系列的SQL INSERT INTO test1 VALUES (NULL, ‘a’, ‘2005-04-01’) ... ... INSERT INTO test1 VALUES (NULL, ‘z’, ‘2005-04-01’) 其中第二个字段的值是从a到z的字母。那么可以这样来优化执行效率： my $sth = $dbh-&gt;prepare( qq{ INSERT INTO test1 VALUES (NULL, ?, ‘2005-04-01’) } ); for my $value(&apos;a&apos;..&apos;z&apos;) { $sth-&gt;execute($value); } 其中的问号就是前面说的参数占位符了，它的意思就是告诉在准备执行资源的服务器：这个SQL的这个位置会有一个值，但是现在还不知道，等下执行的时候再告诉你。prepare了之后，用一个循环产生a-z的字符给变量\$value，然后将\$value在execute方法中作为一个参数传入，服务器那里会自动用传入的值替换前面的\”?\”。需要提醒的是，传入的参数个数一定要和SQL中的占位符的数量一样。 1.3 读取记录熟悉ADO的朋友一定知道里面有一个DataReader对象，DBI中读取数据的方法和它非常的相似。简单来说，就是单向、流式的读取数据，也就是每次只能向后读一条数据直到没有数据可以读取。 文章开头的例子中，用了 $sth-&gt;fetchrow_array() 方法来读取数据。其实DBI读取数据还有几种常见的方法，这几个方法是类似的，所不同的是返回记录的形式。 1.3.1 fetchrow_array返回一个由字段的值组成的数组。该数组的第1个元素就是当前记录第1个字段的值。 while ( my @row = $sth-&gt;fetchrow_array() ) { print &quot;$row[0], $row[1], $row[2]\n&quot;; } 或者这样，不过要注意字段对应的顺序 while ( my ($id, $name, $time) = $sth-&gt;fetchrow_array() ) { print &quot;$id, $name, $time\n&quot;; } 1.3.2 fetchrow_arrayref返回由字段的值组成的数组的引用。同fetchrow_array的区别很明显，fetchrow_arrayref返回的数组的引用。 while ( my $row_ref = $sth-&gt;fetchrow_arrayref() ) { for (my $i = 0; $i &lt; @{$row_ref}; $i++) { print &quot;$row_ref-&gt;[$i]\t&quot;; } print &quot;\n&quot;; } 这里要注意的是，如果要取字段的个数，需要把这个引用转成数组的形式获得@{$row_ref} 。获取数组元素的值的时候，因为\$row_ref是引用，因此需要使用-&gt;操作符。 1.3.3 fetchrow_hashref返回一个由”字段名－字段值”这样的”键－值”对组成的HASH表。关键的不同就是，只有这个方法可以通过一个字段名获得它的值，而不必关心这个字段是第几个字段。而前者只能依靠索引来访问值。不过缺点就是，效率要比前面两个差一些。 while ( my $record = $sth-&gt;fetchrow_hashref() ) { for my $field( keys %{$record} ) { print &quot;$field: $record-&gt;{$field}\t&quot;; } print &quot;\n&quot;; } 这里需要复习一下HASH表的操作方法。keys操作符获取HASH的键(key)的数组，$record-&gt;{$field}获得HASH表中\$field对应的值。注意这里同样是引用，因此要用-&gt;操作符。 使用上面三个方法可以基本解决问题了。此外，还有两个方法fetchall_arrayref和selectall_arrayref可以直接通过SQL一次性获取整个数据集，不过使用上稍微复杂一些，要涉及到perl的scalar 操作符，这里就不赘述了。有兴趣的读者可以参考DBI的相关资料。 最后是收尾工作。 1.4 结束一个SQL会话$sth-&gt;finish(); 1.5 断开数据库连接$dbh-&gt;disconnect(); 很简单明了，就不赘述了。 Perl中利用DBI访问数据库的接口基本上就是这些了，还有一些高级的内容留给有兴趣的读者自己发掘研究了。可能有些读者会感觉没有ADO、ADO.NET操作起来方便，但是在脚本的环境下能够如此方便的操作数据库，比起用C接口来说已经方便很多了。也许在看完这片文章之后的不久，可以在cpan上发现你的Module和全世界的Perl程序员一起分享呢。 2 参考资源 《Programming the Perl DBI》 O’Reily DBI官方网站 http://dbi.perl.org/ 一个DBI编程的简短介绍]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[SVN分支的创建与合并]]></title>
    <url>%2F2016%2F07%2F05%2F5%2F</url>
    <content type="text"><![CDATA[#SVN分支的创建与合并\标准的分支目录如下：\ myproject/\ trunk/ （主分支）\ branches/ （分支）\ tags/ (标记)\现在的项目目录如下\➜ zhangzhongbao tree -L 2\.\└── cm\ ├── doc\ ├── download\ ├── out\ ├── pom.xml\ ├── src\ └── target 6 directories, 1 file\Tips由于我的项目在创建的时候,并没有trunk,现在由于项目需要重新创建分支来进行版本控制. 1.创建分支\ cd /Users/huanggaoming/Desktop/tmp/zhangzhongbao\ svn mkdir branches (由于的不存在branches目录重新创建)\ svn mkdir branches/cm \ svn commit -m \”创建分支目录\” \ svn copy https://10.211.55.3/svn/zhangzhongbao/cm https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716 -m\”7月16日的版本\” (创建分支,原则上尽量和cm平级,但是为了区分,我这里没有平级,版本+1了)\ svn update .\ ➜ zhangzhongbao tree -L 2\.\├── branches\│ └── cm\└── cm\ ├── doc\ ├── download\ ├── out\ ├── pom.xml\ ├── src\ └── target 8 directories, 1 file ➜ zhangzhongbao tree -L 3 branches\branches\└── cm\ └── v-20160716\ ├── doc\ ├── download\ ├── out\ ├── pom.xml\ ├── src\ └── target 7 directories, 1 file Tips:需要注意的是Branch和Trunk使用同一套版本号，也就是说无论在Branch还是Trunk的提交都会引起主版本号的增加。这是因为svncopy只支持同一个repository内的文件copy，并不支持跨repository的copy，所以新创建的Branch和Trunk都属于同一个repository。 2.合并分支\在分支进行一系列的操作\(1) 查看状态\svn status （没有任何的本地修改）\(2) 合并分支到主干\cd /Users/huanggaoming/Desktop/tmp/zhangzhongbao/cm\svn merge https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716 \(svn merge https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716 -r35:HEAD) 将Branch的从版本35到当前版本的所有改动都合并到Trunk中\(3) 提交保存\svn commit -m \”合并v-20160716分支\” \(4) 合并版本并将合并后的结果应用到现有的分支上 \svn -r 148:149 merge https://10.211.55.3/svn/zhangzhongbao/cm -查找到分支版本\cd /Users/huanggaoming/Desktop/tmp/zhangzhongbao/branches/cm/v-20160716\svn log –stop-on-copy (最后rid就是创建分支时的reversion)\＝\cd /Users/huanggaoming/Desktop/tmp/zhangzhongbao/cm \svn log -q –stop-on-copy https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716 -解决冲突\svn st | grep \^C # 查找合并时的冲突文件，手工解决冲突\svn resolved filename # 告知svn冲突已解决\svn commit -m \”\” # 提交合并后的版本\svn: Aborting commit: \’/path/resources/noc\’ remains in conflict\\$ svn revert resources/noc\Reverted \’resources/noc\’ 3.查看分支\svn mergeinfo https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716\➜ cm svn mergeinfo https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716\ youngest common ancestor\ | last full merge\ | | tip of branch\ | | | repository path 34 39 40\ | | |\ --| |------------ branches/cm/v-20160716\ / \\\ / \\\ ——-| |———— cm\ |\ WC 查看Branch中那些改动还未合并:\svn mergeinfo https://10.211.55.3/svn/zhangzhongbao/branches/cm/v-20160716 –show-revs eligible 4.发布－tag管理(创建分支一样)\ cd /Users/huanggaoming/Desktop/tmp/zhangzhongbao\ svn mkdir tags (由于的不存在tags目录重新创建)\ svn mkdir tags/cm \ svn commit -m \”创建tags目录\” \ svn copy https://10.211.55.3/svn/zhangzhongbao/cm https://10.211.55.3/svn/zhangzhongbao/tags/cm/v-20160716 -m\”7月16日的版本\” (创建tag,不允许开发在上面进行任何的修改)\ svn update . ➜ zhangzhongbao tree -L 2\.\├── branches\│ └── cm\├── cm\│ ├── doc\│ ├── download\│ ├── out\│ ├── pom.xml\│ ├── src\│ └── target\└── tags\ └── cm 10 directories, 1 file ➜ zhangzhongbao tree -L 2 tags/cm\tags/cm\└── v-20160716\ ├── doc\ ├── download\ ├── out\ ├── pom.xml\ ├── src\ └── target 6 directories, 1 file\5.]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[PHP超时处理全面总结]]></title>
    <url>%2F2016%2F06%2F08%2F6%2F</url>
    <content type="text"><![CDATA[概述在PHP开发中工作里非常多使用到超时处理到超时的场合，我说几个场景： 异步获取数据如果某个后端数据源获取不成功则跳过，不影响整个页面展现 为了保证Web服务器不会因为当个页面处理性能差而导致无法访问其他页面，则会对某些页面操作设置 对于某些上传或者不确定处理时间的场合，则需要对整个流程中所有超时设置为无限，否则任何一个环节设置不当，都会导致莫名执行中断 多个后端模块（MySQL、Memcached、HTTP接口），为了防止单个接口性能太差，导致整个前面获取数据太缓慢，影响页面打开速度，引起雪崩 。。。很多需要超时的场合 这些地方都需要考虑超时的设定，但是PHP中的超时都是分门别类，各个处理方式和策略都不同，为了系统的描述，我总结了PHP中常用的超时处理的总结。 Web服务器超时处理Apache一般在性能很高的情况下，缺省所有超时配置都是30秒，但是在上传文件，或者网络速度很慢的情况下，那么可能触发超时操作。 目前apachefastcgiphp-fpm模式下有三个超时设置： fastcgi超时设置： 修改httpd.conf的fastcgi连接配置，类似如下： &lt;IfModulemod_fastcgi.c&gt;FastCgiExternalServer/home/forum/apache/apache_php/cgi-bin/php-cgi-socket/home/forum/php5/etc/php-fpm.sock ScriptAlias/fcgi-bin/”/home/forum/apache/apache_php/cgi-bin/” AddHandlerphp-fastcgi.php Actionphp-fastcgi/fcgi-bin/php-cgi AddTypeapplication/x-httpd-php.php &lt;/IfModule&gt; 缺省配置是30s，如果需要定制自己的配置，需要修改配置，比如修改为100秒：(修改后重启apache)： &lt;IfModulemod_fastcgi.c&gt; FastCgiExternalServer/home/forum/apache/apache_php/cgi-bin/php-cgi-socket/home/forum/php5/etc/php-fpm.sock-idle-timeout100 ScriptAlias/fcgi-bin/”/home/forum/apache/apache_php/cgi-bin/” AddHandlerphp-fastcgi.php Actionphp-fastcgi/fcgi-bin/php-cgi AddTypeapplication/x-httpd-php.php &lt;/IfModule&gt; 如果超时会返回500错误，断开跟后端php服务的连接，同时记录一条apache错误日志： [ThuJan2718:30:152011][error][client10.81.41.110]FastCGI:commwithserver”/home/forum/apache/apache_php/cgi-bin/php-cgi”aborted:idletimeout(30sec) [ThuJan2718:30:152011][error][client10.81.41.110]FastCGI:incompleteheaders(0bytes)receivedfromserver”/home/forum/apache/apache_php/cgi-bin/php-cgi” 其他fastcgi配置参数说明： IdleTimeout发呆时限ProcessLifeTime一个进程的最长生命周期，过期之后无条件kill MaxProcessCount最大进程个数 DefaultMinClassProcessCount每个程序启动的最小进程个数 DefaultMaxClassProcessCount每个程序启动的最大进程个数 IPCConnectTimeout程序响应超时时间 IPCCommTimeout与程序通讯的最长时间，上面的错误有可能就是这个值设置过小造成的 MaxRequestsPerProcess每个进程最多完成处理个数，达成后自杀 Lighttpd配置：lighttpd.conf Lighttpd配置中，关于超时的参数有如下几个（篇幅考虑，只写读超时，写超时参数同理）： 主要涉及选项： server.max-keep-alive-idle=5 server.max-read-idle=60 server.read-timeout=0 server.max-connection-idle=360 ————————————————– #每次keep-alive的最大请求数,默认值是16 server.max-keep-alive-requests=100 #keep-alive的最长等待时间,单位是秒，默认值是5 server.max-keep-alive-idle=1200 #lighttpd的work子进程数，默认值是0，单进程运行 server.max-worker=2 #限制用户在发送请求的过程中，最大的中间停顿时间(单位是秒)， #如果用户在发送请求的过程中(没发完请求)，中间停顿的时间太长，lighttpd会主动断开连接 #默认值是60(秒) server.max-read-idle=1200 #限制用户在接收应答的过程中，最大的中间停顿时间(单位是秒)， #如果用户在接收应答的过程中(没接完)，中间停顿的时间太长，lighttpd会主动断开连接 #默认值是360(秒) server.max-write-idle=12000 #读客户端请求的超时限制，单位是秒,配为0表示不作限制 #设置小于max-read-idle时，read-timeout生效 server.read-timeout=0 #写应答页面给客户端的超时限制，单位是秒，配为0表示不作限制 #设置小于max-write-idle时，write-timeout生效 server.write-timeout=0 #请求的处理时间上限，如果用了mod_proxy_core，那就是和后端的交互时间限制,单位是秒 server.max-connection-idle=1200 ————————————————– 说明： 对于一个keep-alive连接上的连续请求，发送第一个请求内容的最大间隔由参数max-read-idle决定，从第二个请求起，发送请求内容的最大间隔由参数max-keep-alive-idle决定。请求间的间隔超时也由max-keep-alive-idle决定。发送请求内容的总时间超时由参数read-timeout决定。Lighttpd与后端交互数据的超时由max-connection-idle决定。 延伸阅读： http://www.snooda.com/read/244 Nginx配置：nginx.conf http{ #Fastcgi:(针对后端的fastcgi生效,fastcgi不属于proxy模式) fastcgi_connect_timeout5;#连接超时 fastcgi_send_timeout10; #写超时 fastcgi_read_timeout10;#读取超时 #Proxy:(针对proxy/upstreams的生效) proxy_connect_timeout15s;#连接超时 proxy_read_timeout24s;#读超时 proxy_send_timeout10s; #写超时 } 说明： Nginx的超时设置倒是非常清晰容易理解，上面超时针对不同工作模式，但是因为超时带来的问题是非常多的。 延伸阅读： http://hi.baidu.com/pibuchou/blog/item/a1e330dd71fb8a5995ee3753.html \http://hi.baidu.com/pibuchou/blog/item/7cbccff0a3b77dc60b46e024.html \http://hi.baidu.com/pibuchou/blog/item/10a549818f7e4c9df703a626.html \http://www.apoyl.com/?p=466 PHP本身超时处理PHP-fpm配置：php-fpm.conf &lt;?xmlversion=”1.0″?&gt; &lt;configuration&gt; //… Setsthelimitonthenumberofsimultaneousrequeststhatwillbeserved. EquivalenttoApacheMaxClientsdirective. EquivalenttoPHP_FCGI_CHILDRENenvironmentinoriginalphp.fcgi Usedwithanypm_style. #php-cgi的进程数量 &lt;valuename=”max_children”&gt;128&lt;/value&gt; Thetimeout(inseconds)forservingasinglerequestafterwhichtheworkerprocesswillbeterminated Shouldbeusedwhen’max_execution_time’inioptiondoesnotstopscriptexecutionforsomereason ’0s’means’off’ #php-fpm 请求执行超时时间，0s为永不超时，否则设置一个 Ns 为超时的秒数 &lt;valuename=”request_terminate_timeout”&gt;0s&lt;/value&gt; Thetimeout(inseconds)forservingofsinglerequestafterwhichaphpbacktracewillbedumpedtoslow.logfile ’0s’means’off’ &lt;valuename=”request_slowlog_timeout”&gt;0s&lt;/value&gt; &lt;/configuration&gt; 说明： 在php.ini中，有一个参数max_execution_time可以设置PHP脚本的最大执行时间，但是，在php-cgi(php-fpm)中，该参数不会起效。真正能够控制PHP脚本最大执行时： &lt;valuename=”request_terminate_timeout”&gt;0s&lt;/value&gt; 就是说如果是使用mod_php5.so的模式运行max_execution_time是会生效的，但是如果是php-fpm模式中运行时不生效的。 延伸阅读： http://blog.s135.com/file_get_contents/ PHP配置：php.ini 选项： max_execution_time=30 或者在代码里设置： ini_set(“max_execution_time”,30); set_time_limit(30); 说明： 对当前会话生效，比如设置0一直不超时，但是如果php的safe_mode打开了，这些设置都会不生效。 效果一样，但是具体内容需要参考php-fpm部分内容，如果php-fpm中设置了request_terminate_timeout的话，那么max_execution_time就不生效。 后端&amp;接口访问超时HTTP访问一般我们访问HTTP方式很多，主要是：curl,socket,file_get_contents()等方法。 如果碰到对方服务器一直没有响应的时候，我们就悲剧了，很容易把整个服务器搞死，所以在访问http的时候也需要考虑超时的问题。 CURL 访问HTTPCURL是我们常用的一种比较靠谱的访问HTTP协议接口的lib库，性能高，还有一些并发支持的功能等。 CURL: curl_setopt($ch,opt)可以设置一些超时的设置，主要包括： *(重要)CURLOPT_TIMEOUT设置cURL允许执行的最长秒数。 *(重要)CURLOPT_TIMEOUT_MS设置cURL允许执行的最长毫秒数。(在cURL7.16.2中被加入。从PHP5.2.3起可使用。) CURLOPT_CONNECTTIMEOUT在发起连接前等待的时间，如果设置为0，则无限等待。 CURLOPT_CONNECTTIMEOUT_MS尝试连接等待的时间，以毫秒为单位。如果设置为0，则无限等待。在cURL7.16.2中被加入。从PHP5.2.3开始可用。 CURLOPT_DNS_CACHE_TIMEOUT设置在内存中保存DNS信息的时间，默认为120秒。 curl普通秒级超时： $ch=curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_TIMEOUT,60);//只需要设置一个秒的数量就可以 curl_setopt($ch,CURLOPT_HTTPHEADER,$headers); curl_setopt($ch,CURLOPT_USERAGENT,$defined_vars[&apos;HTTP_USER_AGENT&apos;]); curl普通秒级超时使用： curl_setopt($ch,CURLOPT_TIMEOUT,60); curl如果需要进行毫秒超时，需要增加： curl_easy_setopt(curl,CURLOPT_NOSIGNAL,1L); 或者是： curl_setopt($ch,CURLOPT_NOSIGNAL,true);是可以支持毫秒级别超时设置的 curl一个毫秒级超时的例子： &lt;?php if(!isset($_GET[&apos;foo&apos;])){ //Client $ch=curl_init(‘http://example.com/’); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); curl_setopt($ch,CURLOPT_NOSIGNAL,1);//注意，毫秒超时一定要设置这个 curl_setopt($ch,CURLOPT_TIMEOUT_MS,200);//超时毫秒，cURL7.16.2中被加入。从PHP5.2.3起可使用 $data=curl_exec($ch); $curl_errno=curl_errno($ch); $curl_error=curl_error($ch); curl_close($ch); if($curl_errno&gt;0){ echo”cURLError($curl_errno):$curl_errorn”; }else{ echo”Datareceived:$datan”; } }else{ //Server sleep(10); echo”Done.”; } ?&gt; 其他一些技巧： 按照经验总结是：cURL版本&gt;=libcurl/7.21.0版本，毫秒级超时是一定生效的，切记。 curl_multi的毫秒级超时也有问题。。单次访问是支持ms级超时的，curl_multi并行调多个会不准 流处理方式访问HTTP除了curl，我们还经常自己使用fsockopen、或者是file操作函数来进行HTTP协议的处理，所以，我们对这块的超时处理也是必须的。 一般连接超时可以直接设置，但是流读取超时需要单独处理。 自己写代码处理: $tmCurrent=gettimeofday(); $intUSGone=($tmCurrent[&apos;sec&apos;]-$tmStart[&apos;sec&apos;])*1000000 +($tmCurrent[&apos;usec&apos;]-$tmStart[&apos;usec&apos;]); if($intUSGone&gt;$this-&gt;_intReadTimeoutUS){ returnfalse; } 或者使用内置流处理函数stream_set_timeout()和stream_get_meta_data()处理： &lt;?php//Timeoutinseconds $timeout=5; $fp=fsockopen(“example.com”,80,$errno,$errstr,$timeout); if($fp){ fwrite($fp,”GET/HTTP/1.0rn”); fwrite($fp,”Host:example.comrn”); fwrite($fp,”Connection:Closernrn”); stream_set_blocking($fp,true);//重要，设置为非阻塞模式 stream_set_timeout($fp,$timeout);//设置超时 $info=stream_get_meta_data($fp); while((!feof($fp))&amp;&amp;(!$info[&apos;timed_out&apos;])){ $data.=fgets($fp,4096); $info=stream_get_meta_data($fp); ob_flush; flush(); } if($info[&apos;timed_out&apos;]){ echo”ConnectionTimedOut!”; }else{ echo$data; } } file_get_contents超时： &lt;?php$timeout=array( ‘http’=&gt;array( ‘timeout’=&gt;5//设置一个超时时间，单位为秒 ) ); $ctx=stream_context_create($timeout); $text=file_get_contents(“http://example.com/”,0,$ctx); ?&gt; fopen超时： &lt;?php$timeout=array( ‘http’=&gt;array( ‘timeout’=&gt;5//设置一个超时时间，单位为秒 ) ); $ctx=stream_context_create($timeout); if($fp=fopen(“http://example.com/”,”r”,false,$ctx)){ while($c=fread($fp,8192)){ echo$c; } fclose($fp); } ?&gt; MySQLphp中的mysql客户端都没有设置超时的选项，mysqli和mysql都没有，但是libmysql是提供超时选项的，只是我们在php中隐藏了而已。 那么如何在PHP中使用这个操作捏，就需要我们自己定义一些MySQL操作常量，主要涉及的常量有： MYSQL_OPT_READ_TIMEOUT=11; MYSQL_OPT_WRITE_TIMEOUT=12; 这两个，定义以后，可以使用options设置相应的值。 不过有个注意点，mysql内部实现： 超时设置单位为秒，最少配置1秒 但mysql底层的read会重试两次，所以实际会是3秒 重试两次+ 自身一次=3倍超时时间，那么就是说最少超时时间是3秒，不会低于这个值，对于大部分应用来说可以接受，但是对于小部分应用需要优化。 查看一个设置访问mysql超时的php实例： &lt;?php//自己定义读写超时常量 if(!defined(‘MYSQL_OPT_READ_TIMEOUT’)){ define(‘MYSQL_OPT_READ_TIMEOUT’,11); } if(!defined(‘MYSQL_OPT_WRITE_TIMEOUT’)){ define(‘MYSQL_OPT_WRITE_TIMEOUT’,12); } //设置超时 $mysqli=mysqli_init(); $mysqli-&gt;options(MYSQL_OPT_READ_TIMEOUT,3); $mysqli-&gt;options(MYSQL_OPT_WRITE_TIMEOUT,1); //连接数据库 $mysqli-&gt;real_connect(“localhost”,”root”,”root”,”test”); if(mysqli_connect_errno()){ printf(“Connectfailed:%s/n”,mysqli_connect_error()); exit(); } //执行查询sleep1秒不超时 printf(“Hostinformation:%s/n”,$mysqli-&gt;host_info); if(!($res=$mysqli-&gt;query(‘selectsleep(1)’))){ echo”query1error:”.$mysqli-&gt;error.”/n”; }else{ echo”Query1:querysuccess/n”; } //执行查询sleep9秒会超时 if(!($res=$mysqli-&gt;query(‘selectsleep(9)’))){ echo”query2error:”.$mysqli-&gt;error.”/n”; }else{ echo”Query2:querysuccess/n”; } $mysqli-&gt;close(); echo”closemysqlconnection/n”; ?&gt; 延伸阅读： http://blog.csdn.net/heiyeshuwu/article/details/5869813 MemcachedPHP扩展php_memcache客户端： 连接超时：boolMemcache::connect(string$host[,int$port[,int$timeout]]) 在get和set的时候，都没有明确的超时设置参数。 libmemcached客户端：在php接口没有明显的超时参数。 说明：所以说，在PHP中访问Memcached是存在很多问题的，需要自己hack部分操作，或者是参考网上补丁。 C&amp;C++访问Memcached客户端：libmemcached客户端 说明：memcache超时配置可以配置小点，比如5，10个毫秒已经够用了，超过这个时间还不如从数据库查询。 下面是一个连接和读取set数据的超时的C++示例： //创建连接超时（连接到Memcached） memcached_st*MemCacheProxy::_create_handle() { memcached_st*mmc=NULL; memcached_return_tprc; if(_mpool!=NULL){//getfrompool mmc=memcached_pool_pop(_mpool,false,&amp;prc); if(mmc==NULL){ __LOG_WARNING__(“MemCacheProxy”,”gethandlefrompoolerror[%d]“,(int)prc); } returnmmc; } memcached_st*handle=memcached_create(NULL); if(handle==NULL){ __LOG_WARNING__(“MemCacheProxy”,”create_handleerror”); returnNULL; } //设置连接/读取超时 memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_HASH,MEMCACHED_HASH_DEFAULT); memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_NO_BLOCK,_noblock);//参数MEMCACHED_BEHAVIOR_NO_BLOCK为1使超时配置生效，不设置超时会不生效，关键时候会悲剧的，容易引起雪崩 memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,_connect_timeout);//连接超时 memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_RCV_TIMEOUT,_read_timeout);//读超时 memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_SND_TIMEOUT,_send_timeout);//写超时 memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_POLL_TIMEOUT,_poll_timeout); //设置一致hash //memcached_behavior_set_distribution(handle,MEMCACHED_DISTRIBUTION_CONSISTENT); memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_DISTRIBUTION,MEMCACHED_DISTRIBUTION_CONSISTENT); memcached_returnrc; for(uinti=0;i&lt;_server_count;i++){ rc=memcached_server_add(handle,_ips[i],_ports[i]); if(MEMCACHED_SUCCESS!=rc){ __LOG_WARNING__(“MemCacheProxy”,”addserver[%s:%d]failed.”,_ips[i],_ports[i]); } } _mpool=memcached_pool_create(handle,_min_connect,_max_connect); if(_mpool==NULL){ __LOG_WARNING__(“MemCacheProxy”,”create_poolerror”); returnNULL; } mmc=memcached_pool_pop(_mpool,false,&amp;prc); if(mmc==NULL){ __LOG_WARNING__(“MyMemCacheProxy”,”gethandlefrompoolerror[%d]“,(int)prc); } //__LOG_DEBUG__(“MemCacheProxy”,”gethandle[%p]“,handle); returnmmc; } //设置一个key超时（set一个数据到memcached） boolMemCacheProxy::_add(memcached_st*handle,unsignedint*key,constchar*value,intlen,unsignedinttimeout) { memcached_returnrc; chartmp[1024]; snprintf(tmp,sizeof(tmp),”%u#%u”,key[0],key[1]); //有个timeout值 rc=memcached_set(handle,tmp,strlen(tmp),(char*)value,len,timeout,0); if(MEMCACHED_SUCCESS!=rc){ returnfalse; } returntrue; } //Memcache读取数据超时(没有设置) libmemcahed源码中接口定义： LIBMEMCACHED_APIchar*memcached_get(memcached_st*ptr,constchar*key,size_tkey_length,size_t*value_length,uint32_t*flags,memcached_return_t*error); LIBMEMCACHED_APImemcached_return_tmemcached_mget(memcached_st*ptr,constchar*const*keys,constsize_t*key_length,size_tnumber_of_keys); 从接口中可以看出在读取数据的时候，是没有超时设置的。 延伸阅读： http://hi.baidu.com/chinauser/item/b30af90b23335dde73e67608 \http://libmemcached.org/libMemcached.html 如何实现超时程序中需要有超时这种功能，比如你单独访问一个后端Socket模块，Socket模块不属于我们上面描述的任何一种的时候，它的协议也是私有的，那么这个时候可能需要自己去实现一些超时处理策略，这个时候就需要一些处理代码了。 PHP中超时实现一、初级：最简单的超时实现 （秒级超时） 思路很简单：链接一个后端，然后设置为非阻塞模式，如果没有连接上就一直循环，判断当前时间和超时时间之间的差异。 phpsocket中实现原始的超时：(每次循环都当前时间去减，性能会很差，cpu占用会较高) &lt;?$host=”127.0.0.1″; $port=”80″; $timeout=15;//timeoutinseconds $socket=socket_create(AF_INET,SOCK_STREAM,SOL_TCP) ordie(“Unabletocreatesocketn”); socket_set_nonblock($socket) //务必设置为阻塞模式 ordie(“Unabletosetnonblockonsocketn”); $time=time(); //循环的时候每次都减去相应值 while(!@socket_connect($socket,$host,$port))//如果没有连接上就一直死循环 { $err=socket_last_error($socket); if($err==115||$err==114) { if((time()-$time)&gt;=$timeout)//每次都需要去判断一下是否超时了 { socket_close($socket); die(“Connectiontimedout.n”); } sleep(1); continue; } die(socket_strerror($err).”n”); } socket_set_block($this-&gt;socket)//还原阻塞模式 ordie(“Unabletosetblockonsocketn”); ?&gt; 二、升级：使用PHP自带异步IO去实现（毫秒级超时） 说明： 异步IO：异步IO的概念和同步IO相对。当一个异步过程调用发出后，调用者不能立刻得到结果。实际处理这个调用的部件在完成后，通过状态、通知和回调来通知调用者。异步IO将比特分成小组进行传送，小组可以是8位的1个字符或更长。发送方可以在任何时刻发送这些比特组，而接收方从不知道它们会在什么时候到达。 多路复用：复用模型是对多个IO操作进行检测，返回可操作集合，这样就可以对其进行操作了。这样就避免了阻塞IO不能随时处理各个IO和非阻塞占用系统资源的确定。 使用socket_select()实现超时 socket_select(…,floor($timeout),ceil($timeout*1000000)); select的特点：能够设置到微秒级别的超时！ 使用socket_select()的超时代码（需要了解一些异步IO编程的知识去理解） 编程 调用类 编程 &lt;?php $server=newServer; $client=newClient; for(;;){ foreach($select-&gt;can_read(0)as$socket){ if($socket==$client-&gt;socket){ //NewClientSocket $select-&gt;add(socket_accept($client-&gt;socket)); } else{ //there’ssomethingtoreadon$socket } } } ?&gt; 编程 异步多路复用IO &amp; 超时连接处理类 编程 &lt;?php classselect{ var$sockets; functionselect($sockets){ $this-&gt;sockets=array(); foreach($socketsas$socket){ $this-&gt;add($socket); } } functionadd($add_socket){ array_push($this-&gt;sockets,$add_socket); } functionremove($remove_socket){ $sockets=array(); foreach($this-&gt;socketsas$socket){ if($remove_socket!=$socket) $sockets[]=$socket; } $this-&gt;sockets=$sockets; } functioncan_read($timeout){ $read=$this-&gt;sockets; socket_select($read,$write=NULL,$except=NULL,$timeout); return$read; } functioncan_write($timeout){ $write=$this-&gt;sockets; socket_select($read=NULL,$write,$except=NULL,$timeout); return$write; } } ?&gt; C&amp;C++中超时实现一般在LinuxC/C++中，可以使用：alarm()设置定时器的方式实现秒级超时，或者：select()、poll()、epoll()之类的异步复用IO实现毫秒级超时。也可以使用二次封装的异步io库（libevent,libev）也能实现。 一、使用alarm中用信号实现超时 （秒级超时） 说明：Linux内核connect超时通常为75秒，我们可以设置更小的时间如10秒来提前从connect中返回。这里用使用信号处理机制，调用alarm，超时后产生SIGALRM信号（也可使用select实现） 用alarym秒级实现 connect设置超时代码示例： 全选复制放进笔记 //信号处理函数staticvoidconnect_alarm(intsigno) { debug_printf(“SignalHandler”); return; } //alarm超时连接实现 staticvoidconn_alarm() { Sigfunc*sigfunc;//现有信号处理函数 sigfunc=signal(SIGALRM,connect_alarm);//建立信号处理函数connect_alarm,(如果有)保存现有的信号处理函数 inttimeout=5; //设置闹钟 if(alarm(timeout)!=0){ //…闹钟已经设置处理 } //进行连接操作 if(connect(m_Socket,(structsockaddr*)&amp;addr,sizeof(addr))&lt;0){ if(errno==EINTR){//如果错误号设置为EINTR，说明超时中断了 debug_printf(“Timeout”);]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[图解HTTPS协议加密解密全过程]]></title>
    <url>%2F2016%2F05%2F03%2F7%2F</url>
    <content type="text"><![CDATA[我们都知道HTTPS能够加密信息，以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。 HTTPS简介 HTTPS其实是有两部分组成：HTTP + SSL /TLS，也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密，所以传输的数据都是加密后的数据。具体是如何进行加密，解密，验证的，且看下图。 1.客户端发起HTTPS请求 这个没什么好说的，就是用户在浏览器里输入一个https网址，然后连接到server的443端口。 2. 服务端的配置 采用HTTPS协议的服务器必须要有一套数字证书，可以自己制作，也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过，才可以继续访问，而使用受信任的公司申请的证书则不会弹出提示页面(startssl就是个不错的选择，有1年的免费服务)。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解，可以想象成一把钥匙和一个锁头，只是全世界只有你一个人有这把钥匙，你可以把锁头给别人，别人可以用这个锁把重要的东西锁起来，然后发给你，因为只有你一个人有这把钥匙，所以只有你才能看到被这把锁锁起来的东西。 3. 传送证书 这个证书其实就是公钥，只是包含了很多信息，如证书的颁发机构，过期时间等等。 4. 客户端解析证书 这部分工作是有客户端的TLS来完成的，首先会验证公钥是否有效，比如颁发机构，过期时间等等，如果发现异常，则会弹出一个警告框，提示证书存在问题。如果证书没有问题，那么就生成一个随机值。然后用证书对该随机值进行加密。就好像上面说的，把随机值用锁头锁起来，这样除非有钥匙，不然看不到被锁住的内容。 5. 传送加密信息 这部分传送的是用证书加密后的随机值，目的就是让服务端得到这个随机值，以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。 6. 服务段解密信息 服务端用私钥解密后，得到了客户端传过来的随机值(私钥)，然后把内容通过该值进行对称加密。所谓对称加密就是，将信息和私钥通过某种算法混合在一起，这样除非知道私钥，不然无法获取内容，而正好客户端和服务端都知道这个私钥，所以只要加密算法够彪悍，私钥够复杂，数据就够安全。 7. 传输加密后的信息 这部分信息是服务段用私钥加密后的信息，可以在客户端被还原。 8. 客户端解密信息 客户端用之前生成的私钥解密服务段传过来的信息，于是获取了解密后的内容。整个过程第三方即使监听到了数据，也束手无策。]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[bash基础]]></title>
    <url>%2F2016%2F05%2F03%2F8%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/669207]]></content>
      <categories>
        <category>HTML相关</category>
      </categories>
      <tags>
        <tag>HTML相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[CentOS 7 下使用 iptables]]></title>
    <url>%2F2016%2F04%2F21%2F9%2F</url>
    <content type="text"><![CDATA[系统升级到CentOS7后总感觉iptables怪怪的,比如不管怎么保存重启后都被初始化一下,即便我最后发大绝招启动时候加命令:\首先iptables-save &gt; /etc/iptables.rules保存当前状态。\然后再在/etc/rc.local中强制加上 [/etc/rc.local] \ +———————————–+———————————–+| | || | || \ | iptables-restore || | /etc/iptables``.rules || | || | |+———————————–+———————————–+ 重启后虽然规则生效但仔细看规则还是一些被莫名添加的额外的内容，让人很是不爽。\ 仔细一google,发现问题之所在了。RedHat在7中更改了系统软件，不再使用iptables作为系统的防火墙，而是使用了FirewallD,但是为了兼容过去的命令也可以使用iptables来设置防护规则，但启动的时候自搞了一套。 解决方法也很简单。 首先，可以考虑follow官方的想法转用FirewallD。其实查看一些官方文档也能用。\但是，个人觉得若没有显著的提升也可以继续使用原来的iptables。若打算继续使用iptables,可以继续做如下: 备份当前规则 +———————————–+———————————–+| | || | || 1 | || | || | || | || | iptables-save &gt; iptables.rules || | || | || | || | || | || | |+———————————–+———————————–+ [禁用FireWallD,安装&amp;启用iptables-services] [systemctl stop firewalld] [systemctl mask firewalld] [[yuminstall ][iptables-services-y ] [systemctlenable ] +———————————–+———————————–+| | || | || | \ || | || | |+———————————–+———————————–+ 这时候检查iptables发现规则被清空了 +———————————–+———————————–+| | || | || 1 | || | || | iptables -L -x -n || | || | || | || | |+———————————–+———————————–+ 将备份的规则还原 +———————————–+———————————–+| | || | || 1 | || | || | iptables-restore iptables.rules || | || | || | || | |+———————————–+———————————–+ 保存当前规则 +———————————–+———————————–+| | || | || 1 | || | || | /usr/libexec/iptables/iptables`` | | | .init save || | || | || | || | |+———————————–+———————————–+ 若使用minimize版本的安装，可能会出现提示 iptables: Saving firewall rules to /etc/sysconfig/iptables:/etc/init.d/iptables: line 274: restorecon: command not found 这是因为selinux没有安装的缘故，缺少一个组件。安装policycoreutils即可。 +———————————–+———————————–+| | || | || 1 | || | || | yum install || | policycoreutils -y || | || | || | || | |+———————————–+———————————–+]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[PHP JSON使用实例]]></title>
    <url>%2F2016%2F02%2F24%2F10%2F</url>
    <content type="text"><![CDATA[一、json_encode()该函数主要用来将数组和对象，转换为json格式。先看一个数组转换的例子：123 $arr = array ('a'=&gt;1,'b'=&gt;2,'c'=&gt;3,'d'=&gt;4,'e'=&gt;5); echo json_encode($arr); 结果为 {“a”:1,”b”:2,”c”:3,”d”:4,”e”:5} 再看一个对象转换的例子：123456789101112 $obj-&gt;body = 'another post'; $obj-&gt;id = 21; $obj-&gt;approved = true; $obj-&gt;favorite_count = 1; $obj-&gt;status = NULL; echo json_encode($obj); 结果为123456789101112 &#123; "body":"another post", "id":21, "approved":true, "favorite_count":1, "status":null &#125; 由于json只接受utf-8编码的字符，所以json_encode()的参数必须是utf-8编码，否则会得到空字符或者null。当中文使用GB2312编码，或者外文使用ISO-8859-1编码的时候，这一点要特别注意。二、索引数组和关联数组PHP支持两种数组，一种是只保存”值”（value）的索引数组（indexed array），另一种是保存”名值对”（name/value）的关联数组（associative array）。由于javascript不支持关联数组，所以json_encode()只将索引数组（indexed array）转为数组格式，而将关联数组（associative array）转为对象格式。比如，现在有一个索引数组1234 $arr = Array('one', 'two', 'three'); echo json_encode($arr); 结果为：12 ["one","two","three"] 如果将它改为关联数组：12345 $arr = Array('1'=&gt;'one', '2'=&gt;'two', '3'=&gt;'three'); echo json_encode($arr); 结果就变了：12 &#123;"1":"one","2":"two","3":"three"&#125; 注意，数据格式从”[]”（数组）变成了”{}”（对象）。如果你需要将”索引数组”强制转化成”对象”，可以这样写1 json_encode( (object)$arr ); 或者12 json_encode ( $arr, JSON_FORCE_OBJECT ); 三、类（class）的转换下面是一个PHP的类：1234567891011121314151617 class Foo &#123; const ERROR_CODE = '404'; public $public_ex = 'this is public'; private $private_ex = 'this is private!'; protected $protected_ex = 'this should be protected'; public function getErrorCode() &#123; return self::ERROR_CODE; &#125; &#125; 现在，对这个类的实例进行json转换：123456 $foo = new Foo; $foo_json = json_encode($foo); echo $foo_json; 输出结果是 1 &#123;"public_ex":"this is public"&#125; 可以看到，除了公开变量（public），其他东西（常量、私有变量、方法等等）都遗失了。四、json_decode()该函数用于将json文本转换为相应的PHP数据结构。下面是一个例子：123456 $json = '&#123;"foo": 12345&#125;'; $obj = json_decode($json); print $obj-&gt;&#123;'foo'&#125;; // 12345 通常情况下，json_decode()总是返回一个PHP对象，而不是数组。比如：1234 $json = '&#123;"a":1,"b":2,"c":3,"d":4,"e":5&#125;'; var_dump(json_decode($json)); 结果就是生成一个PHP对象：12345678910 object(stdClass)#1 (5) &#123; ["a"] =&gt; int(1) ["b"] =&gt; int(2) ["c"] =&gt; int(3) ["d"] =&gt; int(4) ["e"] =&gt; int(5) &#125; 如果想要强制生成PHP关联数组，json_decode()需要加一个参数true：1234 $json = '&#123;"a":1,"b":2,"c":3,"d":4,"e":5&#125;'; var_dump(json_decode($json,true)); 结果就生成了一个关联数组：12345678910 array(5) &#123; ["a"] =&gt; int(1) ["b"] =&gt; int(2) ["c"] =&gt; int(3) ["d"] =&gt; int(4) ["e"] =&gt; int(5) &#125; 五、json_decode()的常见错误下面三种json写法都是错的，你能看出错在哪里吗？123456 $bad_json = "&#123; 'bar': 'baz' &#125;"; $bad_json = '&#123; bar: "baz" &#125;'; $bad_json = '&#123; "bar": "baz", &#125;'; 对这三个字符串执行json_decode()都将返回null，并且报错。第一个的错误是，json的分隔符（delimiter）只允许使用双引号，不能使用单引号。第二个的错误是，json名值对的”名”（冒号左边的部分），任何情况下都必须使用双引号。第三个的错误是，最后一个值之后不能添加逗号（trailing comma）。 另外，json只能用来表示对象（object）和数组（array），如果对一个字符串或数值使用json_decode()，将会返回null。 1 var_dump(json_decode("Hello World")); //null]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[关于的运维平台化和价值化的思考]]></title>
    <url>%2F2016%2F02%2F17%2F11%2F</url>
    <content type="text"><![CDATA[[*[运维是什么？] [ [运维是什么？经常有人询问，运维到底是一个什么样的角色？做什么的？什么是运维？] [ 不知道身为运维同行的你们会怎么回答这个问题，借用百度百科的关于运维的定义。[运维，这里指互联网运维，通常属于技术部门，与研发、测试、系统管理同为互联网产品技术支撑的4大部门，这个划分在国内和国外以及大小公司间都会多少有一些不同。一般来讲国内的互联网运维负责软件测试交付后的发布和管理，其核心目标是将交付的业务软件和硬件基础设施高效合理的整合，转换为可持续提供高质量服务的产品，同时最大限度降低服务运行的成本，保障服务运行的安全。] [ 在大部分／开发／测试／运营等部门的眼里，运维就是一个负责发布和部署部门，当然不同规模的公司，运维团地规模以及需求和侧重点都不一样，有的公司甚至都没有开设运维工程师的这一职位，由开发人员自主的承担运维的角色。在业务规模达到一定的时候，运维一定在其中担任不可或缺的重要角色。在互联网的产品体系当中，运维的角色在很多的情况下并不是很清晰明了，甚至有很多的运维工程师都不清楚自己所处的运维的定位到底是什么？] [ 运维在互联网产品的技术支撑体系中所扮演的角色并不是那么清晰，从产品的需求设计到开发，到测试，再到上线运营的过程当中。比如开发，在整个产品形态当中，开发的角色非常的清晰，就是根据需求和设计开发相对应的功能，比如测试，根据产品的需求和设计，测试相对应的功能点。而运维在整个的产品的体系当中，它所处的角色到底又是什么呢？上线部署？线上维护？版本管理？] [在整个的技术支撑体系过程当中，运维一直在”打辅助“的角色当中，可能大家对运维的最深刻的认识就是当服务故障了，大家第一时间想到的就是运维。可是你又真正的认识到自己是有多重要么？在我看来，运维、测试、运营支持就是为产品服务的技术支持团队，每一个角色都至关重要，缺一不可。那么，作为反过来回答运维是什么，运维就是解决用户痛点，提升用户体验的技术支持部门。用户这里不是单单是指使用我们产品的用户，也同时是指运营、运维、测试等服务对象。为了用户体验，我们需要构建安全、监控、报警等多个维度的体系。] [\] [[运维的划分是怎样的？]] [ 在一般的情况下，运维会划分几个维度,[运维团队可以划分为：应用运维、系统运维、运维开发和监控运维，可能还会包含DBA团队和安全团队。] [应用运维：负责支持线上业务，各自会负责对应的业务线，主要职能是保证线上业务稳定性和同开发共同支撑对应业务，以及线上服务管理和持续优化。] [运维开发：帮助运维提升工作效率，开发方便快捷的工具，实现运维平台化自动化。] [系统运维：负责操作系统定制和优化，IDC管理和机器交付，以及跳板机和账号信息管理。] [监控运维：负责发现故障，并第一时间通知相关人员，及时处理简单故障和启动降级方案等。] [[运维的平台化和价值化]] [ 我自己的理解，运维做过的事情很多。部署、发布、监控、安全、开发工具集……，大大小小做了的事情很多，请问，付出了那么多，做了那么多事，你老板知道么？直接的价值产出在哪里？说句很实在的话就是老板根本不懂什么安装、部署、监控、什么LVS、什么高可用，什么高并发……老板又问，又要买服务器，”上个月不是刚刚花了200多万购买了一批服务器到机房么“，等等。你需要将你所做的事情升华出来，当然你一定有一定的价值真正产出。说了这么多，举个例子，为了提升运营人员的工作效率，运维开发了各种小巧的小工具，原来需要半天才能出来的数据，运维开发出工具，几分钟就出来了运营人员需要的数据，这就是的效率的提升。] [\] [[那么运维平台化和价值化的维度在在哪儿呢?]] [[\]] \ [\] [后续在分享运维平台化的具体实现方式~ ] [谢谢]]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Mac wifi 自动控制脚本]]></title>
    <url>%2F2016%2F01%2F22%2F12%2F</url>
    <content type="text"><![CDATA[1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374#!/bin/bash#author: 黄高明#date: 2016-01-22#qq: 530035210#blog: http://my.oschina.net/pwd/blog #控制mac wifi脚本 logdir=/data/log/shell #日志路径log=$logdir/log.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录ssid="Raincy"ssid_passwd="aa123456"ip_info="192.168.0.120 255.255.255.0 192.168.0.1"dnsgroup="25.25.25.1 223.5.5.5"device="Wi-Fi" datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho "[ $(datef) ] $1"fi&#125;wifi_action()&#123;case $1 in list)/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport scan;;start)networksetup -setairportpower en0 on;;stop)networksetup -setairportpower en0 off;;connect)if [[ "$ssid" == "" &amp;&amp; "$ssid_passwd" == "" ]];thennetworksetup -setairportnetwork en0 $ssid $ssid_passwdelseprint_log "ssid or password 为空."fi;;set-statics-ip)networksetup -setmanual "$device" $ip_info;;set-dhcp-ip) ipconfig set en0 DHCP;;list-devices)networksetup -listallnetworkservices;;set-dns)networksetup -setdnsservers "$device" $dnsgroupdscacheutil -flushcache ;;*)echo "usage: wifi.sh list| start| stop| connect| set-statics-ip| set-dhcp-ip| list-devices| set-dns";;esac&#125;wifi_action "$1" root权限下： usage: wifi.sh list:查看Wi-Fi列表| start 启动| stop关闭|connect连接某个ssid| set-statics-ip设置静态ip| set-dhcp-ip设置动态IP|list-devices查看网络设备| set-dns设置dns]]></content>
      <categories>
        <category>MAC小技巧</category>
      </categories>
      <tags>
        <tag>MAC小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[让Mac OS X的终端多姿多彩]]></title>
    <url>%2F2016%2F01%2F22%2F13%2F</url>
    <content type="text"><![CDATA[让Mac OS X的终端多姿多彩FEB 27TH, 2012 与Linux相比，Mac OSX的终端总是欠缺些什么。对了，是色彩，Linux的ls命令使用不同颜色区分各种文件类型，Vim编辑器也支持语法高亮，而Mac终端却总是以黑白示人。其实，只要稍微做一些工作，Mac的终端同样可以多姿多彩，请往下看。 彩色化ls的输出Mac中BSD的ls命令可以使用-G参数彩色化输出的文件列表，需要配置LSCOLORS环境变量定义颜色，具体配置方法可以输入man ls查看。 不过，我推荐安装Linux使用的GNU Coreutils替换Mac的ls命令，因为： Coreutils提供了配置工具，定义颜色代码更加方便； Coreutils包含的不仅仅是ls，同时作为Linux用户，我更习惯于使用GNU的各种shell工具。 Coreutils的安装与配置方法如下： 通过Homebrew安装Coreutils\brew install xz coreutils\注：Coreutils并不依赖于xz，但它的源码是用xz格式压缩的，安装xz才能解压。 生成颜色定义文件\gdircolors --print-database &gt; ~/.dir_colors 在~/.bash_profile配置文件中加入以下代码 \ [[if]brewlist | grep coreutils &gt; /dev/null ;[then][[ ] [[PATH][\”\$(brew–prefixcoreutils)/libexec/gnubin:\$PATH\”][ ] [[alias][\’ls-F –show-control-chars–color=auto\’][ ] [[eval][`]gdircolors-b[\$HOME] [[fi] gdircolor的作用就是设置ls命令使用的环境变量LS_COLORS（BSD是LSCOLORS），我们可以修改~/.dir_colors自定义文件的颜色，此文件中的注释已经包含各种颜色取值的说明。 看看默认颜色的显示效果。 grep高亮显示关键字这个很简单，加上--color参数就可以了，为了使用方便，可以在~/.bash_profile配置文件中加上alias定义。 [[[[alias][\’grep–color\’] [[[[alias][\’egrep–color\’] [[[[alias][\’fgrep–color\’] Vim语法高亮在Vim中输入命令:syntax on激活语法高亮，若需要Vim启动时自动激活，在~/.vimrc中添加一行syntax on即可。]]></content>
      <categories>
        <category>MAC小技巧</category>
      </categories>
      <tags>
        <tag>MAC小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Mac入门 使用brew安装软件]]></title>
    <url>%2F2016%2F01%2F22%2F14%2F</url>
    <content type="text"><![CDATA[使用brew安装软件brew 又叫Homebrew，是Mac OSX上的软件包管理工具，能在Mac中方便的安装软件或者卸载软件， 只需要一个命令， 非常方便 brew类似ubuntu系统下的apt-get的功能 &nbsp; 阅读目录 安装brew 使用brew安装软件 使用brew卸载软件 使用brew查询软件 其他brew命令 &nbsp; 安装brewbrew 的官方网站： http://brew.sh/&nbsp;&amp;nbsp; 在官方网站对brew的用法进行了详细的描述 安装方法：&nbsp; 在Mac中打开Termal:&nbsp; 输入命令： ruby&nbsp;-e&nbsp;”$(curl&nbsp;-fsSL&nbsp;https://raw.githubusercontent.com/Homebrew/install/master/install)”[object Object] &nbsp;不知道为什么， 在国内经常被屏蔽 &nbsp; 使用brew安装软件一个命令就搞定了， 比如安装git brew&nbsp;install&nbsp;git 比如安装wget brew&nbsp;install&nbsp;wget &nbsp; 使用brew卸载软件卸载更方便了 brew&nbsp;uninstall&nbsp;wget &nbsp; 使用brew查询软件有时候，你不知道你安装的软件的名字， 那么你需要先搜索下, 查到包的名字。 比如我要安装 brew&nbsp;search&nbsp;/wge*/ /wge*/是个正则表达式， 需要包含在/中 &nbsp; &nbsp; 其他brew命令brew list&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 列出已安装的软件 brew update&nbsp;&nbsp;&nbsp;&nbsp; 更新brew brew home&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用浏览器打开brew的官方网站 brew info&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显示软件信息 brew deps&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显示包依赖 &nbsp; &nbsp;]]></content>
      <categories>
        <category>MAC小技巧</category>
      </categories>
      <tags>
        <tag>MAC小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[由SecureCRT引发的思考和学习]]></title>
    <url>%2F2016%2F01%2F07%2F15%2F</url>
    <content type="text"><![CDATA[[前言] 由于业务需要，最近在云上新购买了一批centos7.0的服务器,用脚本批量添加了用户（脚本请见我之前的博客/秘钥认证用户自动控制:][）,加完秘钥之后发现,但是secureCRT抛出了一下异常。] [解决过程：] [1.初步怀疑秘钥有问题,通过命令行去探测是否可以连接,-&gt; ssh -i 秘钥文件用户名@主机，发现能正常连接，确认秘钥是OK的。] [2.可能出在secureCRT配置问题，具体操作不详解了,主要是涉及客户端一些可视化的设置,捣鼓完以后没好。] [3.根据以上报错联想，可能是这个secureCrt不支持以上的加密算法，上面已经明确的提示了，于是验证了xshell和putty，以及高版本的SecureCRT是可以连接.] [常见终端客户端的介绍请戳链接: ] [由于低版本 SecreCRT 不支持 AES-128-CBC 这个 Cipher，而 Linux 下用ssh-keygen 生成的公钥默认采用这个 Cipher的，于是对应的私钥可能会加载不了,所以登陆不上。] [思考和学习] [参考:http://blog.csdn.net/macrossdzh/article/details/5691924] [一、什么是SSH] [SSH是英文SecureShell的简写形式。通过使用SSH，你可以把所有传输的数据进行加密，这样\”中间人\”这种攻击方式就不可能实现了，而且也能够防止DNS欺骗和IP欺骗。使用SSH，还有一个额外的好处就是传输的数据是经过压缩的，所以可以加快传输的速度。SSH有很多功能，它既可以代替Telnet，又可以为FTP、Pop、甚至为PPP提供一个安全的\”通道\”。] [ssh工作原理简易介绍:] [服务器建立公钥： 每一次启动 sshd 服务时，该服务会主动去找/etc/ssh/ssh_host*的文件，若系统刚刚安装完成时，由于没有这些公钥，因此 sshd会主动去计算出这些需要的公钥，同时也会计算出服务器自己需要的私钥] [客户端主动联机请求： 若客户端想要联机到 ssh服务器，则需要使用适当的客户端程序来联机，包括 ssh, putty等客户端程序连接] [服务器传送公钥给客户端：接收到客户端的要求后，服务器便将第一个步骤取得的公钥传送给客户端使用(此时应是明码传送，反正公钥本来就是给大家使用的)] [客户端记录并比对服务器的公钥数据及随机计算自己的公私钥：若客户端第一次连接到此服务器，则会将服务器的公钥记录到客户端的用户家目录内的~/.ssh/known_hosts。若是已经记录过该服务器的公钥，则客户端会去比对此次接收到的与之前的记录是否有差异。若接受此公钥，则开始计算客户端自己的公私钥] [回传客户端的公钥到服务器端：用户将自己的公钥传送给服务器。此时服务器：具有服务器的私钥与客户端的公钥，而客户端则是：具有服务器的公钥以及客户端自己的私钥，你会看到，在此次联机的服务器与客户端的密钥系统(公钥+私钥)并不一样，所以才称为非对称加密系统] [开始双向加解密：(1)服务器到客户端：服务器传送数据时，拿用户的公钥加密后送出。客户端接收后，用自己的私钥解密(2)客户端到服务器：客户端传送数据时，拿服务器的公钥加密后送出。服务器接收后，用服务器的私钥解密，这样就能保证通信安全] [二、SSH基本框架] [SSH协议框架中最主要的部分是三个协议：] [* 传输层协议（The Transport LayerProtocol）提供服务器认证，数据机密性，信息完整性等的支持；[（TCP/IP的传输层-第3层）] [* 用户认证协议（The User Authentication Protocol）则为服务器提供客户端的身份鉴别； [（TCP/IP的应用层-第4层）] [* 连接协议（The Connection Protocol）将加密的信息隧道复用成若干个逻辑通道，提供给更高层的应用协议使用；各种高层应用协议可以相对地独立于SSH基本体系之外，并依靠这个基本框架，通过连接协议使用SSH的安全机制。 [（TCP/IP的应用层-第4层）] [同时SSH协议框架中还为许多高层的网络安全应用协议提供扩展的支持。它们之间的层次关系可以用如下图来表示：] [三、主机密钥机制] [对于SSH这样以提供安全通讯为目标的协议，其中必不可少的就是一套完备的密钥机制。由于SSH协议是面向互联网网络中主机之间的互访与信息交换，所以主机密钥成为基本的密钥机制。也就是说，SSH协议要求每一个使用本协议的主机都必须至少有一个自己的主机密钥对，服务方通过对客户方主机密钥的认证之后，才能允许其连接请求。一个主机可以使用多个密钥，针对不同的密钥算法而拥有不同的密钥，但是至少有一种是必备的，即通过DSS算法产生的密钥。关于DSS算法，请参考[FIPS-186]。] [SSH协议关于主机密钥认证的管理方案有两种，如下图所示：] [每一个主机都必须有自己的主机密钥，密钥可以有多对，每一对主机密钥对包括公开密钥和私有密钥。在实际应用过程中怎样使用这些密钥，并依赖它们来实现安全特性呢？如上图所示，SSH协议框架中提出了两种方案。] [在第一种方案中，主机将自己的公用密钥分发给相关的客户机，客户机在访问主机时则使用该主机的公开密钥来加密数据，主机则使用自己的私有密钥来解密数据，从而实现主机密钥认证，确定客户机的可靠身份。在图2（a）中可以看到，用户从主机A上发起操作，去访问，主机B和主机C，此时，A成为客户机，它必须事先配置主机B和主机C的公开密钥，在访问的时候根据主机名来查找相应的公开密钥。对于被访问主机（也就是服务器端）来说则只要保证安全地存储自己的私有密钥就可以了。] [在第二种方案中，存在一个密钥认证中心，所有系统中提供服务的主机都将自己的公开密钥提交给认证中心，而任何作为客户机的主机则只要保存一份认证中心的公开密钥就可以了。在这种模式下，客户机在访问服务器主机之前，还必须向密钥认证中心请求认证，认证之后才能够正确地连接到目的主机上。] [很显然，第一种方式比较容易实现，但是客户机关于密钥的维护却是个麻烦事，因为每次变更都必须在客户机上有所体现；第二种方式比较完美地解决管理维护问题，然而这样的模式对认证中心的要求很高，在互联网络上要实现这样的集中认证，单单是权威机构的确定就是个大麻烦，有谁能够什么都能说了算呢？但是从长远的发展来看，在企业应用和商业应用领域，采用中心认证的方案是必要的。] [另外，SSH协议框架中还允许对主机密钥的一个折中处理，那就是首次访问免认证。首次访问免认证是指，在某客户机第一次访问主机时，主机不检查主机密钥，而向该客户都发放一个公开密钥的拷贝，这样在以后的访问中则必须使用该密钥，否则会被认为非法而拒绝其访问。] [四、SSH的工作过程] [在整个通讯过程中，为实现SSH的安全连接，服务器端与客户端要经历如下五个阶段：] [ * 版本号协商阶段，SSH目前包括 SSH1和SSH2两个版本，双方通过版本协商确定使用的版本] [ * 密钥和算法协商阶段，SSH支持多种加密算法，双方根据本端和对端支持的算法，协商出最终使用的算法] [ * 认证阶段，SSH客户端向服务器端发起认证请求，服务器端对客户端进行认证] [ * 会话请求阶段，认证通过后，客户端向服务器端发送会话请求] [ * 交互会话阶段，会话请求通过后，服务器端和客户端进行信息的交互] [1 .版本号协商阶段] [ 1. 服务器打开端口22，等待客户端连接。] [ 2. 客户端向服务器端发起TCP初始连接请求，TCP连接建立后，服务器向客户端发送第一个报文，包括版本标志字符串，格式为“SSH－&lt;主协议版本号&gt;.&lt;次协议版本号&gt;－&lt;软件版本号&gt;”，协议版本号由主版本号和次版本号组成，软件版本号主要是为调试使用。] [ 3.客户端收到报文后，解析该数据包，如果服务器端的协议版本号比自己的低，且客户端能支持服务器端的低版本，就使用服务器端的低版本协议号，否则使用自己的协议版本号。] [ 4.客户端回应服务器一个报文，包含了客户端决定使用的协议版本号。服务器比较客户端发来的版本号，决定是否能同客户端一起工作。] [ 5. 如果协商成功，则进入密钥和算法协商阶段，否则服务器端断开TCP连接。] [Note：版本号协商阶段报文都是采用明文方式传输的。] [2.密钥和算法协商阶段] [ 1.服务器端和客户端分别发送算法协商报文给对端，报文中包含自己支持的公钥算法列表、加密算法列表、MAC（MessageAuthenticationCode，消息验证码）算法列表、压缩算法列表等;] [ 2.服务器端和客户端根据对端和本端支持的算法列表得出最终使用的算法。] [ 3. 服务器端和客户端利用 DH交换（Diffie-HellmanExchange）算法、主机密钥对等参数，生成会话密钥和会话ID。] [通过以上步骤，服务器端和客户端就取得了相同的会话密钥和会话ID。] [ *对于后续传输的数据，两端都会使用会话密钥进行加密和解密，保证了数据传送的安全] [ * 在认证阶段，两端会使用会话ID用于认证过程。] [Note：] [ 在协商阶段之前，服务器端已经生成 RSA或DSA密钥对，他们主要用于参与会话密钥的生成。] [3.认证阶段] [ 1.客户端向服务器端发送认证请求，认证请求中包含用户名、认证方法、与该认证方法相关的内容（如：password认证时，内容为密码）。] [ 2.服务器端对客户端进行认证，如果认证失败，则向客户端发送认证失败消息，其中包含可以再次认证的方法列表。] [ 3.客户端从认证方法列表中选取一种认证方法再次进行认证。] [ 4. 该过程反复进行， 直到认证成功或者认证次数达到上限，服务器关闭连接为止。] [SSH提供两种认证方式：] [ 1. password认证：客户端向服务器发出password认证请求，将用户名和密码加密后发送给服务器；服务器将该信息解密后得到用户名和密码的明文，与设备上保存的用户名和密码进行比较，并返回认证成功或失败的消息。] [ 2. publickey认证：采用数字签名的方法来认证客户端。目前，设备上可以利用RSA和DSA两种公共密钥算法实现数字签名。客户端发送包含用户名、公共密钥和公共密钥算法的publickey认证请求给服务器端。服务器对公钥进行合法性检查，如果不合法，则直接发送失败消息；否则，服务器利用数字签名对客户端进行认证，并返回认证成功或失败的消息] [SSH2.0还提供了 password-publickey 认证和 any认证:] [ 1. password-publickey 认证：指定该用户的认证方式为 password 和publickey认证同时满足。客户端版本为SSH1的用户只要通过其中一种认证即可登录；客户端版本为SSH2的用户必须两种认证都通过才能登录。] [ 2. any认证：指定该用户的认证方式可以是 password，也可以是publickey。] [4.会话请求阶段] [ 1.服务器等待客户端的请求；] [ 2.认证通过后，客户端向服务器发送会话请求；] [ 3. 服务器处理客户端的请求。请求被成功处理后， 服务器会向客户端回应SSH_SMSG_SUCCESS包，SSH进入交互会话阶段；否则回应SSH_SMSG_FAILURE包，表示服务器处理请求失败或者不能识别请求。] [5.交互会话阶段] [在这个模式下，数据被双向传送：] [ 1.客户端将要执行的命令加密后传给服务器;] [ 2.服务器接收到报文，解密后执行该命令,将执行的结果加密发还给客户端;] [ 3.客户端将接收到的结果解密后显示到终端上.] [[五、SSH的应用] [ [首先，SSH最常见的应用就是，用它来取代传统的Telnet、FTP等网络应用程序，通过SSH登录到远方机器执行你想进行的工作与命令。在不安全的网路通讯环境中，它提供了很强的验证（authentication）机制与非常安全的通讯环境。实际上，SSH开发者的原意是设计它来取代原UNIX系统上的rcp、rlogin、rsh等指令程序的；但经过适当包装后，发现它在功能上完全可以取代传统的Telnet、FTP等应用程序。] [ 传统 BSD 风格的 r 系列指令（如rcp，rsh，rlogin）往往都被视为不安全的，很容易就被各种网络攻击手段所破解，几乎所有找得到有关UNIX安全的书或文件，都会一而再、再而三地警告系统管理者，留心r系列指令的设定，甚至要求系统管理者将r系列指令通通关闭。] [ 而用来替代r系列指令的SSH，则在安全方面做了极大的强化，不但对通讯内容可以进行极为安全的加密保护，同时也强化了对身份验证的安全机制，它应用了在密码学（Cryptography）中已发展出来的数种安全加密机制，如Symmetric Key Cryptography，Asymmetric Key Cryptography， One-way HashFunction，Random-numberGeneration等，来加强对于身份验证与通讯内容的安全保护。通讯时资料的加密有IDEA，three-keytriple DES，DES，RC4-128，TSS，Blowfish等数种多种安全加密算法可供选择，加密的key则是通过 RSA进行交换的。资料的加密可以对抗IPspoofing，RSA这种非对称性的加密机制则可用来对抗DNS spoofing与IP routingspoofing，同时RSA也可以进行对主机身份的验证。] [ 其次，通过使用用SSH可以在本地主机和远程服务器之间设置\”加密通道\”，并且这样设置的\”加密通道\”可以跟常见的Pop应用程序、X应用程序、Linuxconf应用程序相结合，提供安全保障。] [ SSH的\”加密通道\”是通过\”端口转发\”来实现的。你可以在本地端口（没有用到的）和在远程服务器上运行的某个服务的端口之间建立\”加密通道\”。然后只要连接到本地端口。所有对本地端口的请求都被SSH加密并且转发到远程服务器的端口。当然只有远程服务器上运行SSH服务器软件的时候\”加密通道\”才能工作。] [六、SSHQ&amp;A] [ [ Q1:SSH的版本和区别。] [SSH2避免了RSA的专利问题，并修补了CRC的缺陷。SSH2用数字签名算法（DSA）和Diffie-Hellman（DH）算法代替RSA来完成对称密钥的交换，用HMAC来代替CRC。同时SSH2增加了AES和Twofish等对称加密算法。] [ A1: SSH(SecureSHell)到目前为止有两个不兼容的版本——SSH1和SSH2。SSH1又分为1.3和1.5两个版本。SSH1采用DES、3DES、Blowfish和RC4等对称加密算法保护数据安全传输，而对称加密算法的密钥是通过非对称加密算法（RSA）来完成交换的。SSH1使用循环冗余校验码（CRC）来保证数据的完整性，但是后来发现这种方法有缺陷。] [ 更多内容请参考The SSHv1 Protocol &amp; The SSHv2Protocol] [ Q2:什么是HMAC？] [ A2: HMAC(Hash Message Authentication Code)，散列消息鉴别码，基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是，用公开函数和密钥产生一个固定长度的值作为认证标识，用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块，即MAC，并将其加入到消息中，然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。] [ Q3: 什么是X11forwarding？] [ A3: sh的X11 forwarding特性可以使X client和Xserver安全地通讯。使用X11 forwarding后，从X client到XServer方向的数据先被送至ssh server，ssh server利用和sshclient的安全通道转发给ssh client，再由ssh client转发给X server，从Xserver到X client的数据流同理。这里ssh server和ssh client充当了Xclient和X server间数据的转发器，由于ssh server和X client、ssh client和Xserver一般在同一台机器上，它们之间是一种安全的进程间通讯，而sshserver和ssh client间的通讯也是安全的，所以X client和Xserver间的通讯就是安全的。] [ Q4:什么是TTY？] [ A4:终端是一种字符型设备，它有多种类型，通常使用tty来简称各种类型的终端设备。tty是Teletype的缩写。Teletype是最早出现的一种终端设备，很象电传打字机，是由Teletype公司生产的。设备名放在特殊文件目录/dev/下。] [ Q5:简单描述下SSH运行的过程？] [A5:简要过程如下：] [ *Client端向Server端发起SSH连接请求。] [ *Server端向Client端发起版本协商。] [ * 协商结束后Server端发送Host Key公钥 ServerKey公钥，随机数等信息。到这里所有通信是不加密的。] [ *Client端返回确认信息，同时附带用公钥加密过的一个随机数，用于双方计算SessionKey。] [ *进入认证阶段。从此以后所有通信均加密。] [ *认证成功后，进入交互阶段。] [补充:] [sshd配置文件详解] [vim/etc/ssh/sshd_config] [#1. SSH Server 全局设定，port ,协议……] [# Port 22 #默认端口，也可以使用多个端口] [Protocol 2#协议版本号] [# ListenAddress 0.0.0.0 #默认值是监听所有接口的 SSH要求] [# PidFile /var/run/sshd.pid #放置 SSHD 这个 PID的文件] [# LoginGraceTime 2m#2分钟之内不输入密码，自动断开] [# Compression delayed #使用压缩数据模式进行传输，登入后才将数据压缩(delayed)] [#2. 主要私有Key存放文件] [# HostKey /etc/ssh/ssh_host_key # SSH version 1使用的私钥] [# HostKey /etc/ssh/ssh_host_rsa_key # SSH version 2 使用的 RSA私钥] [# HostKey /etc/ssh/ssh_host_dsa_key # SSH version 2 使用的 DSA私钥] [#3.关于登录文件的数据与daemon的名称] [SyslogFacility AUTHPRIV#记录日志/var/log/secure] [# LogLevel INFO#日志等级] [#4.安全设置] [# PermitRootLogin yes #是否允许 root登入] [# StrictModes yes #是否让 sshd去检查用户家目录或相关文件的权限数据] [# PubkeyAuthentication yes#使用密钥登录系统] [# AuthorizedKeysFile .ssh/authorized_keys#用户登录公钥存放位置] [PasswordAuthentication yes#登录密码认证] [# PermitEmptyPasswords no#否允许以空的密码登入] [# RhostsAuthentication no #系统不使用.rhosts认证] [# IgnoreRhosts yes #是否取消使用 ~/.ssh/.rhosts来做为认证] [# RhostsRSAAuthentication no #专门给 version 1 用的，使用 rhosts文件在/etc/hosts.equiv] [# HostbasedAuthentication no #上面的项目类似，不过是给 version 2使用的] [# IgnoreUserKnownHosts no #是否忽略家目录内的~/.ssh/known_hosts] [ChallengeResponseAuthentication no#允许任何的密码认证] [UsePAM yes #利用 PAM管理使用者认证，可以记录与管理] [#5.登录后项目] [# PrintMotd yes#登入后是否显示出一些信息] [# PrintLastLog yes#显示上次登入的信息] [# TCPKeepAlive yes #当达成联机后，服务器会一直传送 TCP封包给客户端以判断对方式否一直存在联机] [UsePrivilegeSeparation yes#是否权限较低的程序来提供用户操作] [MaxStartups 10#同时允许几个尚未登入的联机画面] [DenyUsers *#设定受阻止的使用者名称] [DenyUsers test #阻止用户] [DenyGroups test#阻止组] [#6. SFTP设定] [Subsystem sftp/usr/lib/ssh/sftp-server] [# UseDNS yes #为了要判断客户端来源是正常合法的，因此会使用 DNS去反查客户端的主机名，不过在内网这项目设定为 no会让联机达成速度比较快]]]></content>
      <categories>
        <category>日常记录</category>
      </categories>
      <tags>
        <tag>日常记录</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[20个命令行工具监控 Linux 系统性能]]></title>
    <url>%2F2016%2F01%2F07%2F16%2F</url>
    <content type="text"><![CDATA[对于每个系统管理员或网络管理员来说，每天要[监控]和调试L[inux ]年L[inux ]个命令行系统监视工具。这些命令可以在所有版本的L[inux ]和查找系统性能的实际原因。这些监控命令足够你选择适合你的监控场景。 [1. top ]系统进程监控[top ]使用率过高的正在运行的进程。当我们对L[inux ]命令的实际操作。 # top {width=”630”height=”430”}\[] [2. vmstat ]— 虚拟内存统计[vmstat ]的程序包。命令格式常用用法如下： # vmstatprocs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free inact active si so bi bo in cs us sy id wa st 1 0 0 810420 97380 70628 0 0 115 4 89 79 1 6 90 3 0 [3. lsof ]— 打开文件列表[lsof ]命令对于很多L[inux/Unix ]系统都可以使用，主要以列表的形式显示打开的文件和进程。 打开的文件主要包括磁盘文件、网络套接字、管道、设备和进程。使用这个命令的主要原因是一个一个盘不能卸载并且显示文件正在使用或者打开的错误信息。这个命令很容易看出哪些文件正在使用。这个命令最常用的格式： # lsofCOMMAND PID USER FD TYPE DEVICE SIZE NODE NAME init 1 root cwd DIR 104,2 4096 2 / init 1 root rtd DIR 104,2 4096 2 / init 1 root txt REG 104,2 38652 17710339 /sbin/init init 1 root mem REG 104,2 129900 196453 /lib/ld-2.5.so init 1 root mem REG 104,2 1693812 196454 /lib/libc-2.5.so init 1 root mem REG 104,2 20668 196479 /lib/libdl-2.5.so init 1 root mem REG 104,2 245376 196419 /lib/libsepol.so.1 init 1 root mem REG 104,2 93508 196431 /lib/libselinux.so.1 init 1 root 10u FIFO 0,17 953 /dev/initctl [] [4. tcpdump ]— 网络数据包分析器[tcpdump ]几乎在所有的L[inux ]版本中都是可用的。 # tcpdump -i eth0tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes 22:08:59.617628 IP tecmint.com.ssh &gt; 115.113.134.3.static-mumbai.vsnl.net.in.28472: P 2532133365:2532133481(116) ack 3561562349 win 9648 22:09:07.653466 IP tecmint.com.ssh &gt; 115.113.134.3.static-mumbai.vsnl.net.in.28472: P 116:232(116) ack 1 win 9648 22:08:59.617916 IP 115.113.134.3.static-mumbai.vsnl.net.in.28472 &gt; tecmint.com.ssh: . ack 116 win 64347 [] [5. netstat ]— 网络统计[netstat ]命令是一个监控网络数据包传入和传出的统计界面的命令行工具。它对于许多系统管理员去监控网络性能和解决网络相关问题是一个非常有用的工具。 # netstat -a | more\Active Internet connections (including servers)\Proto Recv-Q Send-Q Local Address Foreign Address(state)\tcp 0 0 *.* *.*CLOSED\tcp4 0 0 *.* *.*CLOSED\tcp 0 0 *.* *.*CLOSED\tcp4 0 0 *.* *.*CLOSED\tcp 0 0 *.* *.*CLOSED\tcp4 0 0 *.* *.*CLOSED\tcp4 0 0 loopback.32848 loopback.32849ESTABLISHED\tcp4 0 0 loopback.32849 loopback.32848ESTABLISHED\tcp 0 0 *.ftp *.*LISTEN\tcp4 0 0 *.ssh *.*LISTEN\tcp4 0 0 *.smtp *.*LISTEN\tcp4 0 0 loopback.32897 loopback.32898ESTABLISHED\tcp4 0 0 loopback.32898 loopback.32897ESTABLISHED\tcp4 0 0 *.sunrpc *.*LISTEN\tcp 0 0 *.smux *.*LISTEN\tcp4 0 0 loopback.32803 loopback.33149ESTABLISHED\tcp4 0 0 loopback.33149 loopback.32803ESTABLISHED\tcp4 0 0 lc4fis22p.33661 lc4fis15.fhdba01cESTABLISHED\tcp4 0 0 loopback.32848 loopback.33152ESTABLISHED\tcp4 0 0 loopback.33152 loopback.32848ESTABLISHED [6. htop ]— 进程监控[htop ]是一个第三方工具并不包括在L[inux ]包管理工具进行安装。 # htop {width=”600”height=”363”}\[] [7. iotop ][iotop ]写过程是非常有用的。 # iotop [] [8. iostat ]输出统计[iostat ]远程磁盘。 # iostatLinux 2.6.18-238.9.1.el5 (tecmint.com) 09/13/2012 avg-cpu: %user %nice %system %iowait %steal %idle 2.60 3.65 1.04 4.29 0.00 88.42 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn cciss/c0d0 17.79 545.80 256.52 855159769 401914750 cciss/c0d0p1 0.00 0.00 0.00 5459 3518 cciss/c0d0p2 16.45 533.97 245.18 836631746 384153384 cciss/c0d0p3 0.63 5.58 3.97 8737650 6215544 cciss/c0d0p4 0.00 0.00 0.00 8 0 cciss/c0d0p5 0.63 3.79 5.03 5936778 7882528 cciss/c0d0p6 0.08 2.46 2.34 3847771 3659776 9. IPTraf —实时[IP]局域网监控IPTraf 是一个基于开源的L[inux ]校验错误，界面活性等一般信息和详细信息的接口统计数据。 {width=”600”height=”377”}\[] [10. Psacct ]— 监视用户活动[Psacct ]是用于监测每个用户对系统的活跃状态的一个非常有用的工具。在后台有两个守护进程在运行，一个是密切关注系统上每个用户的整体活动，另一个进程关注有哪些资源被它们消耗。 [ ]这个工具对于系统管理员是非常有用的去跟踪每个用户的活动，可以知道用户正在做什么，发出了什么样的命令，占用了多少资源，多长时间活跃在系统上。 [11. Monit ]— 程序和服务监测这是一个免费的开源的基于 [web ] 等等。系统状态是可以从命令行或者自己的网络接口来查看。 {width=”600”height=”450”}\[] [12. NetHogs ]— 监视每个进程的网络带宽[NetHogs ]是一个开源的漂亮的小程序（类似于L[inux ]命令），在您的系统上保持每个进程的网络活动状态。它也保持了一个程序或者应用实时的网络流量带宽使用情况。 {width=”600”height=”450”}\[] [13. iftop ]— 网络带宽监控[iftop ]监视一个选定的接口并且显示两台主机之间当前宽带的使用情况。 {width=”601”height=”387”}\[] [14. Monitorix ]— 系统和网络监控[Monitorix ]是一个尽可能多的在L[inux/Unix ]上一个轻量级监控工具，主要设计是监控正在运行的系统和网络资源。它有一个内置的 [HTTPweb ]数据库等等更多的服务。它的主要目的是监控整个系统的性能，并且有助于监测故障、瓶颈、异常活动等状况。 {width=”863”height=”655”} [15. Arpwatch ]— 以太网活动监控器[Arpwatch]是一种用来监视L[inux ]地址对发生变化的时候，它会发送电子邮件通知管理员。 并且它在检测 [ARP ]攻击是非常有用的。 [16. Suricata ]— 网络安全监控[Suricata ]（[OpenInformation SecurityFoundation]）拥有的。 [17. VnStat PHP ]— 监测网络带宽[VnStatPHP ]”。 [VnStatPHP ]使用了很好的图形模式监控网络流量的使用情况。它显示了每时、每天、每月的总结报告中的网络流量使用情况。 18. Nagios — 网络/服务器监控[Nagios ]可以监控远程L[inux]、开关、单窗口的路由器和打印机。它能显示你的网络和服务器关键的告警，有利于在错误反生之前帮助你解决问题。 [19. Nmon — ]系统性能[Nmon]格式后的处理。 [{width=”681”height=”421”}] [20. Collectl ]— 一体化性能检测工具[Collectl ]套接等等。 {width=”678”height=”449”} 我们想知道你使用什么样的监控程序来监控你的服务器性能？如果我们错过你想要的任何工具，请通过评论告知我们，并且不要忘记分享他。]]></content>
      <categories>
        <category>日常记录</category>
      </categories>
      <tags>
        <tag>日常记录</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[TCP IP基础知识]]></title>
    <url>%2F2016%2F01%2F06%2F17%2F</url>
    <content type="text"><![CDATA[CP/IP网络协议栈分为应用层（Application）、传输层（Transport）、网络层（Network）和链路层（Link）四层。如下图所示 {width=”361”height=”201”} 两台计算机通过TCP/IP协议通讯的过程如下所示 {width=”670”height=”347”} 传输层及其以下的机制由内核提供，应用层由用户进程提供,应用程序对通讯数据的含义进行解释，而传输层及其以下处理通讯的细节，将数据从一台计算机通过一定的路径发送到另一台计算机。应用层数据通过协议栈发到网络上时，每层协议都要加上一个数据首部（header），称为封装（Encapsulation），如下图所示: {width=”668”height=”458”} 不同的协议层对数据包有不同的称谓，在传输层叫做段（segment），在网络层叫做数据报（datagram），在链路层叫做帧（frame）。数据封装成帧后发到传输介质上，到达目的主机后每层协议再剥掉相应的首部，最后将应用层数据交给应用程序处理。 上图对应两台计算机在同一网段中的情况，如果两台计算机在不同的网段中，那么数据从一台计算机到另一台计算机传输过程中要经过一个或多个路由器，如下图所示: {width=”697”height=”428”} 其实在链路层之下还有物理层，指的是电信号的传递方式，比如现在以太网通用的网线（双绞线）、早期以太网采用的的同轴电缆（现在主要用于有线电视）、光纤等都属于物理层的概念。物理层的能力决定了最大传输速率、传输距离、抗干扰性等。集线器（Hub）是工作在物理层的网络设备，用于双绞线的连接和信号中继（将已衰减的信号再次放大使之传得更远）。 链路层有以太网、令牌环网等标准，链路层负责网卡设备的驱动、帧同步（就是说从网线上检测到什么信号算作新帧的开始）、冲突检测（如果检测到冲突就自动重发）、数据差错校验等工作。交换机是工作在链路层的网络设备，可以在不同的链路层网络之间转发数据帧（比如十兆以太网和百兆以太网之间、以太网和令牌环网之间），由于不同链路层的帧格式不同，交换机要将进来的数据包拆掉链路层首部重新封装之后再转发。 网络层的IP协议是构成Internet的基础。Internet上的主机通过IP地址来标识，Internet上有大量路由器负责根据IP地址选择合适的路径转发数据包，数据包从Internet上的源主机到目的主机往往要经过十多个路由器。路由器是工作在第三层的网络设备，同时兼有交换机的功能，可以在不同的链路层接口之间转发数据包，因此路由器需要将进来的数据包拆掉网络层和链路层两层首部并重新封装。IP协议不保证传输的可靠性，数据包在传输过程中可能丢失，可靠性可以在上层协议或应用程序中提供支持。 网络层负责点到点（point-to-point）的传输（这里的“点”指主机或路由器），而传输层负责端到端（end-to-end）的传输（这里的“端”指源主机和目的主机）。传输层可选择TCP或UDP协议。TCP是一种面向连接的、可靠的协议，有点像打电话，双方拿起电话互通身份之后就建立了连接，然后说话就行了，这边说的话那边保证听得到，并且是按说话的顺序听到的，说完话挂机断开连接。也就是说TCP传输的双方需要首先建立连接，之后由TCP协议保证数据收发的可靠性，丢失的数据包自动重发，上层应用程序收到的总是可靠的数据流，通讯之后关闭连接。UDP协议不面向连接，也不保证可靠性，有点像寄信，写好信放到邮筒里，既不能保证信件在邮递过程中不会丢失，也不能保证信件是按顺序寄到目的地的。使用UDP协议的应用程序需要自己完成丢包重发、消息排序等工作。 目的主机收到数据包后，如何经过各层协议栈最后到达应用程序呢？整个过程如下图所示: {width=”766”height=”391”} 以太网驱动程序首先根据以太网首部中的“上层协议”字段确定该数据帧的有效载荷（payload，指除去协议首部之外实际传输的数据）是IP、ARP还是RARP协议的数据报，然后交给相应的协议处理。假如是IP数据报，IP协议再根据IP首部中的“上层协议”字段确定该数据报的有效载荷是TCP、UDP、ICMP还是IGMP，然后交给相应的协议处理。假如是TCP段或UDP段，TCP或UDP协议再根据TCP首部或UDP首部的“端口号”字段确定应该将应用层数据交给哪个用户进程。IP地址是标识网络中不同主机的地址，而端口号就是同一台主机上标识不同进程的地址，IP地址和端口号合起来标识网络中唯一的进程。 注意，虽然IP、ARP和RARP数据报都需要以太网驱动程序来封装成帧，但是从功能上划分，ARP和RARP属于链路层，IP属于网络层。虽然ICMP、IGMP、TCP、UDP的数据都需要IP协议来封装成数据报，但是从功能上划分，ICMP、IGMP与IP同属于网络层，TCP和UDP属于传输层。本文对RARP、ICMP、IGMP协议不做进一步介绍，有兴趣的读者可以看参考资料。 以太网的帧格式如下所示 {width=”722”height=”280”} 其中的源地址和目的地址是指网卡的硬件地址（也叫MAC地址），长度是48位，是在网卡出厂时固化的。用ifconfig命令看一下，“HWaddr00:15:F2:14:9E:3F”部分就是硬件地址。类型字段有三种值，分别对应IP、ARP、RARP。帧末尾是CRC校验码。 以太网帧中的数据长度规定最小46字节，最大1500字节，ARP和RARP数据包的长度不够46字节，要在后面补填充位。最大值1500称为以太网的最大传输单元（MTU），不同的网络类型有不同的MTU，如果一个数据包从以太网路由到拨号链路上，数据包长度大于拨号链路的MTU了，则需要对数据包进行分片（fragmentation）。ifconfig命令的输出中也有“MTU:1500”。注意，MTU这个概念指数据帧中有效载荷的最大长度，不包括帧首部的长度。 ARP数据报格式在网络通讯时，源主机的应用程序知道目的主机的IP地址和端口号，却不知道目的主机的硬件地址，而数据包首先是被网卡接收到再去处理上层协议的，如果接收到的数据包的硬件地址与本机不符，则直接丢弃。因此在通讯前必须获得目的主机的硬件地址。ARP协议就起到这个作用。 [源主机发出ARP请求，询问“IP地址是192.168.0.1的主机的硬件地址是多少”，并将这个请求广播到本地网段（以太网帧首部的硬件地址填FF:FF:FF:FF:FF:FF表示广播），目的主机接收到广播的ARP请求，发现其中的IP地址与本机相符，则发送一个ARP应答数据包给源主机，将自己的硬件地址填写在应答包中。] 每台主机都维护一个ARP缓存表，可以用arp-a命令查看。缓存表中的表项有过期时间（一般为20分钟），如果20分钟内没有再次使用某个表项，则该表项失效，下次还要发ARP请求来获得目的主机的硬件地址。想一想，为什么表项要有过期时间而不是一直有效？ ARP数据报的格式如下所示: {width=”692”height=”153”} 注意到源MAC地址、目的MAC地址在以太网首部和ARP请求中各出现一次，对于链路层为以太网的情况是多余的，但如果链路层是其它类型的网络则有可能是必要的。硬件类型指链路层网络类型，1为以太网，协议类型指要转换的地址类型，0x0800为IP地址，后面两个地址长度对于以太网地址和IP地址分别为6和4（字节），op字段为1表示ARP请求，op字段为2表示ARP应答。 下面举一个具体的例子。 请求帧如下（为了清晰在每行的前面加了字节计数，每行16个字节）： 以太网首部（14字节） \0000: ff ff ff ff ff ff 00 05 5d 61 58 a8 08 06 \ARP帧（28字节） \0000: 00 01 \0010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 37 \0020: 00 00 00 00 00 00 c0 a8 00 02 \填充位（18字节） \0020: 00 77 31 d2 50 10 \0030: fd 78 41 d3 00 00 00 00 00 00 00 00 以太网首部：目的主机采用广播地址，源主机的MAC地址是00:05:5d:61:58:a8，上层协议类型0x0806表示ARP。 ARP帧：硬件类型0x0001表示以太网，协议类型0x0800表示IP协议，硬件地址（MAC地址）长度为6，协议地址（IP地址）长度为4，op为0x0001表示请求目的主机的MAC地址，源主机MAC地址为00:05:5d:61:58:a8，源主机IP地址为c0a8 00 37（192.168.0.55），目的主机MAC地址全0待填写，目的主机IP地址为c0a8 00 02（192.168.0.2）。 由于以太网规定最小数据长度为46字节，ARP帧长度只有28字节，因此有18字节填充位，填充位的内容没有定义，与具体实现相关。 应答帧如下： 以太网首部 \0000: 00 05 5d 61 58 a8 00 05 5d a1 b8 40 08 06 \ARP帧 \0000: 00 01 \0010: 08 00 06 04 00 02 00 05 5d a1 b8 40 c0 a8 00 02 \0020: 00 05 5d 61 58 a8 c0 a8 00 37 \填充位 \0020: 00 77 31 d2 50 10 \0030: fd 78 41 d3 00 00 00 00 00 00 00 00 以太网首部：目的主机的MAC地址是00:05:5d:61:58:a8，源主机的MAC地址是00:05:5d:a1:b8:40，上层协议类型0x0806表示ARP。 ARP帧：硬件类型0x0001表示以太网，协议类型0x0800表示IP协议，硬件地址（MAC地址）长度为6，协议地址（IP地址）长度为4，op为0x0002表示应答，源主机MAC地址为00:05:5d:a1:b8:40，源主机IP地址为c0a8 0002（192.168.0.2），目的主机MAC地址为00:05:5d:61:58:a8，目的主机IP地址为c0a8 00 37（192.168.0.55）。 IP数据报格式{width=”605”height=”400”} IP数据报的首部长度和数据长度都是可变长的，但总是4字节的整数倍。对于IPv4，4位版本字段是4。4位首部长度的数值是以4字节为单位的，最小值为5，也就是说首部长度最小是4x5=20字节，也就是不带任何选项的IP首部，4位能表示的最大值是15，也就是说首部长度最大是60字节。 8位TOS字段有3个位用来指定IP数据报的优先级（目前已经废弃不用），还有4个位表示可选的服务类型（最小延迟、最大呑吐量、最大可靠性、最小成本），还有一个位总是0。总长度是整个数据报（包括IP首部和IP层payload）的字节数。每传一个IP数据报，16位的标识加1，可用于分片和重新组装数据报。3位标志和13位片偏移用于分片。TTL（Timetolive)是这样用的：源主机为数据包设定一个生存时间，比如64，每过一个路由器就把该值减1，如果减到0就表示路由已经太长了仍然找不到目的主机的网络，就丢弃该包，因此这个生存时间的单位不是秒，而是跳（hop）。协议字段指示上层协议是TCP、UDP、ICMP还是IGMP。然后是校验和，只校验IP首部，数据的校验由更高层协议负责。IPv4的IP地址长度为32位。选项字段的解释从略。 IP地址与路由IPv4的IP地址长度为4字节，通常采用点分十进制表示法（dotted decimalrepresentation）例如0xc0a80002表示为192.168.0.2。 Internet被各种路由器和网关设备分隔成很多网段，为了标识不同的网段，需要把32位的IP地址划分成网络号和主机号两部分，网络号相同的各主机位于同一网段，相互间可以直接通信，网络号不同的主机之间通信则需要通过路由器转发。 过去曾经提出一种划分网络号和主机号的方案，把所有IP地址分为五类，如下图所示: {width=”646”height=”295”} A类 0.0.0.0到127.255.255.255 \B类 128.0.0.0到191.255.255.255 \C类 192.0.0.0到223.255.255.255 \D类 224.0.0.0到239.255.255.255 \E类 240.0.0.0到247.255.255.255 一个A类网络可容纳的地址数量最大，一个B类网络的地址数量是65536，一个C类网络的地址数量是256。D类地址用作多播地址，E类地址保留未用。 UDP段格式 {width=”669”height=”232”} 下面分析一帧基于UDP的TFTP协议帧。 以太网首部 \0000: 00 05 5d 67 d0 b1 00 05 5d 61 58 a8 08 00 \IP首部 \0000: 45 00 \0010: 00 53 93 25 00 00 80 11 25 ec c0 a8 00 37 c0 a8 \0020: 00 01 \UDP首部 \0020： 05 d4 00 45 00 3f ac 40 \TFTP协议 \0020: 00 01 \’c\’\’:\’\’\\’\’q\’ \0030: \’w\’\’e\’\’r\’\’q\’\’.\’\’q\’\’w\’\’e\’00\’n\’\’e\’\’t\’\’a\’\’s\’\’c\’\’i\’ \0040: \’i\’00 \’b\’\’l\’\’k\’\’s\’\’i\’\’z\’\’e\’00 \’5\’\’1\’\’2\’00\’t\’\’i\’ \0050: \’m\’\’e\’\’o\’\’u\’\’t\’00 \’1\’\’0\’00\’t\’\’s\’\’i\’\’z\’\’e\’00 \’0\’ \0060: 00 以太网首部：目的MAC地址是00:05:5d:67:d0:b1，源MAC地址是00:05:5d:61:58:a8，上层协议类型0x0800表示IP。 IP首部：第一个字节0x45包含4位版本号和4位首部长度，版本号为4，即IPv4，首部长度为5，说明IP首部不带有选项字段。服务类型为0，没有使用服务。16位总长度字段（包括IP首部和IP层payload的长度）为0x0053，即83字节，加上以太网首部14字节可知整个帧长度是97字节。IP报标识是0x9325，标志字段和片偏移字段设置为0x0000，就是DF=0允许分片，MF=0此数据报没有更多分片，没有分片偏移。TTL是0x80，也就是128。上层协议0x11表示UDP协议。IP首部校验和为0x25ec，源主机IP是c0a8 00 37（192.168.0.55），目的主机IP是c0 a8 00 01（192.168.0.1）。 UDP首部：源端口号0x05d4（1492）是客户端的端口号，目的端口号0x0045（69）是TFTP服务的well-known端口号。UDP报长度为0x003f，即63字节，包括UDP首部和UDP层payload的长度。UDP首部和UDP层payload的校验和为0xac40。 TFTP是基于文本的协议，各字段之间用字节0分隔，开头的0001表示请求读取一个文件，接下来的各字段是： c:\qwerq.qwe \netascii \blksize 512 \timeout 10 \tsize 0 一般的网络通信都是像TFTP协议这样，通信的双方分别是客户端和服务器，客户端主动发起请求（上面的例子就是客户端发起的请求帧），而服务器被动地等待、接收和应答请求。客户端的IP地址和端口号唯一标识了该主机上的TFTP客户端进程，服务器的IP地址和端口号唯一标识了该主机上的TFTP服务进程，由于客户端是主动发起请求的一方，它必须知道服务器的IP地址和TFTP服务进程的端口号，所以，一些常见的网络协议有默认的服务器端口，例如HTTP服务默认TCP协议的80端口，FTP服务默认TCP协议的21端口，TFTP服务默认UDP协议的69端口（如上例所示）。在使用客户端程序时，必须指定服务器的主机名或IP地址，如果不明确指定端口号则采用默认端口，请读者查阅ftp、tftp等程序的manpage了解如何指定端口号。/etc/services中列出了所有well-known的服务端口和对应的传输层协议，这是由IANA（InternetAssigned NumbersAuthority）规定的，其中有些服务既可以用TCP也可以用UDP，为了清晰，IANA规定这样的服务采用相同的TCP或UDP默认端口号，而另外一些TCP和UDP的相同端口号却对应不同的服务。 很多服务有well-known的端口号，然而客户端程序的端口号却不必是well-known的，往往是每次运行客户端程序时由系统自动分配一个空闲的端口号，用完就释放掉，称为ephemeral的端口号，想想这是为什么。 前面提过，UDP协议不面向连接，也不保证传输的可靠性，例如： 发送端的UDP协议层只管把应用层传来的数据封装成段交给IP协议层就算完成任务了，如果因为网络故障该段无法发到对方，UDP协议层也不会给应用层返回任何错误信息。 接收端的UDP协议层只管把收到的数据根据端口号交给相应的应用程序就算完成任务了，如果发送端发来多个数据包并且在网络上经过不同的路由，到达接收端时顺序已经错乱了，UDP协议层也不保证按发送时的顺序交给应用层。 通常接收端的UDP协议层将收到的数据放在一个固定大小的缓冲区中等待应用程序来提取和处理，如果应用程序提取和处理的速度很慢，而发送端发送的速度很快，就会丢失数据包，UDP协议层并不报告这种错误。 因此，使用UDP协议的应用程序必须考虑到这些可能的问题并实现适当的解决方案，例如等待应答、超时重发、为数据包编号、流量控制等。一般使用UDP协议的应用程序实现都比较简单，只是发送一些对可靠性要求不高的消息，而不发送大量的数据。例如，基于UDP的TFTP协议一般只用于传送小文件（所以才叫trivial的ftp），而基于TCP的FTP协议适用于各种文件的传输。下面看TCP协议如何用面向连接的服务来代替应用程序解决传输的可靠性问题。 TCP协议 {width=”685”height=”406”} 和UDP协议一样也有源端口号和目的端口号，通讯的双方由IP地址和端口号标识。32位序号、32位确认序号、窗口大小稍后详细解释。4位首部长度和IP协议头类似，表示TCP协议头的长度，以4字节为单位，因此TCP协议头最长可以是4x15=60字节，如果没有选项字段，TCP协议头最短20字节。URG、ACK、PSH、RST、SYN、FIN是六个控制位，本节稍后将解释SYN、ACK、FIN、RST四个位，其它位的解释从略。16位检验和将TCP协议头和数据都计算在内。紧急指针和各种选项的解释从略。 下图是一次TCP通讯的时序图。 []{} 图 36.13. TCP连接建立断开 在这个例子中，首先客户端主动发起连接、发送请求，然后服务器端响应请求，然后客户端主动关闭连接。两条竖线表示通讯的两端，从上到下表示时间的先后顺序，注意，数据从一端传到网络的另一端也需要时间，所以图中的箭头都是斜的。双方发送的段按时间顺序编号为1-10，各段中的主要信息在箭头上标出，例如段2的箭头上标着SYN,8000(0), ACK 1001, &lt;mss1024&gt;，表示该段中的SYN位置1，32位序号是8000，该段不携带有效载荷（数据字节数为0），ACK位置1，32位确认序号是1001，带有一个mss选项值为1024。 建立连接的过程： 客户端发出段1，SYN位表示连接请求。序号是1000，这个序号在网络通讯中用作临时的地址，每发一个数据字节，这个序号要加1，这样在接收端可以根据序号排出数据包的正确顺序，也可以发现丢包的情况，另外，规定SYN位和FIN位也要占一个序号，这次虽然没发数据，但是由于发了SYN位，因此下次再发送应该用序号1001。mss表示最大段尺寸，如果一个段太大，封装成帧后超过了链路层的最大帧长度，就必须在IP层分片，为了避免这种情况，客户端声明自己的最大段尺寸，建议服务器端发来的段不要超过这个长度。 服务器发出段2，也带有SYN位，同时置ACK位表示确认，确认序号是1001，表示“我接收到序号1000及其以前所有的段，请你下次发送序号为1001的段”，也就是应答了客户端的连接请求，同时也给客户端发出一个连接请求，同时声明最大尺寸为1024。 客户端发出段3，对服务器的连接请求进行应答，确认序号是8001。 在这个过程中，客户端和服务器分别给对方发了连接请求，也应答了对方的连接请求，其中服务器的请求和应答在一个段中发出，因此一共有三个段用于建立连接，称为\’\’\’三方握手（three-way-handshake）\’\’\’。在建立连接的同时，双方协商了一些信息，例如双方发送序号的初始值、最大段尺寸等。 在TCP通讯中，如果一方收到另一方发来的段，读出其中的目的端口号，发现本机并没有任何进程使用这个端口，就会应答一个包含RST位的段给另一方。例如，服务器并没有任何进程使用8080端口，我们却用telnet客户端去连接它，服务器收到客户端发来的SYN段就会应答一个RST段，客户端的telnet程序收到RST段后报告错误Connectionrefused： $ telnet 192.168.0.200 8080 Trying 192.168.0.200... telnet: Unable to connect to remote host: Connection refused 数据传输的过程： 客户端发出段4，包含从序号1001开始的20个字节数据。 服务器发出段5，确认序号为1021，对序号为1001-1020的数据表示确认收到，同时请求发送序号1021开始的数据，服务器在应答的同时也向客户端发送从序号8001开始的10个字节数据，这称为piggyback。 客户端发出段6，对服务器发来的序号为8001-8010的数据表示确认收到，请求发送序号8011开始的数据。 在数据传输过程中，ACK和确认序号是非常重要的，应用程序交给TCP协议发送的数据会暂存在TCP层的发送缓冲区中，发出数据包给对方之后，只有收到对方应答的ACK段才知道该数据包确实发到了对方，可以从发送缓冲区中释放掉了，如果因为网络故障丢失了数据包或者丢失了对方发回的ACK段，经过等待超时后TCP协议自动将发送缓冲区中的数据包重发。 这个例子只描述了最简单的一问一答的情景，实际的TCP数据传输过程可以收发很多数据段，虽然典型的情景是客户端主动请求服务器被动应答，但也不是必须如此，事实上TCP协议为应用层提供了全双工（full-duplex）的服务，双方都可以主动甚至同时给对方发送数据。 如果通讯过程只能采用一问一答的方式，收和发两个方向不能同时传输，在同一时间只允许一个方向的数据传输，则称为\’\’\’半双工（half-duplex）\’\’\’，假设某种面向连接的协议是半双工的，则只需要一套序号就够了，不需要通讯双方各自维护一套序号，想一想为什么。 关闭连接的过程： 客户端发出段7，FIN位表示关闭连接的请求。 服务器发出段8，应答客户端的关闭连接请求。 服务器发出段9，其中也包含FIN位，向客户端发送关闭连接请求。 客户端发出段10，应答服务器的关闭连接请求。 建立连接的过程是三方握手，而关闭连接通常需要4个段，服务器的应答和关闭连接请求通常不合并在一个段中，因为有连接半关闭的情况，这种情况下客户端关闭连接之后就不能再发送数据给服务器了，但是服务器还可以发送数据给客户端，直到服务器也关闭连接为止，稍后会看到这样的例子。 流量控制介绍UDP时我们描述了这样的问题：如果发送端发送的速度较快，接收端接收到数据后处理的速度较慢，而接收缓冲区的大小是固定的，就会丢失数据。TCP协议通过\’\’\’滑动窗口（SlidingWindow）\’\’\’机制解决这一问题。看下图的通讯过程。 []{} 图 36.14. 滑动窗口 发送端发起连接，声明最大段尺寸是1460，初始序号是0，窗口大小是4K，表示“我的接收缓冲区还有4K字节空闲，你发的数据不要超过4K”。接收端应答连接请求，声明最大段尺寸是1024，初始序号是8000，窗口大小是6K。发送端应答，三方握手结束。 发送端发出段4-9，每个段带1K的数据，发送端根据窗口大小知道接收端的缓冲区满了，因此停止发送数据。 接收端的应用程序提走2K数据，接收缓冲区又有了2K空闲，接收端发出段10，在应答已收到6K数据的同时声明窗口大小为2K。 接收端的应用程序又提走2K数据，接收缓冲区有4K空闲，接收端发出段11，重新声明窗口大小为4K。 发送端发出段12-13，每个段带1K数据，段13同时还包含FIN位。 接收端应答接收到的2K数据（6145-8192），再加上FIN位占一个序号8193，因此应答序号是8194，连接处于半关闭状态，接收端同时声明窗口大小为2K。 接收端的应用程序提走2K数据，接收端重新声明窗口大小为4K。 接收端的应用程序提走剩下的2K数据，接收缓冲区全空，接收端重新声明窗口大小为6K。 接收端的应用程序在提走全部数据后，决定关闭连接，发出段17包含FIN位，发送端应答，连接完全关闭。 上图在接收端用小方块表示1K数据，实心的小方块表示已接收到的数据，虚线框表示接收缓冲区，因此套在虚线框中的空心小方块表示窗口大小，从图中可以看出，随着应用程序提走数据，虚线框是向右滑动的，因此称为滑动窗口。 从这个例子还可以看出，发送端是一K一K地发送数据，而接收端的应用程序可以两K两K地提走数据，当然也有可能一次提走3K或6K数据，或者一次只提走几个字节的数据，也就是说，应用程序所看到的数据是一个整体，或说是一个流（stream），在底层通讯中这些数据可能被拆成很多数据包来发送，但是一个数据包有多少字节对应用程序是不可见的，因此TCP协议是面向流的协议。而UDP是面向消息的协议，每个UDP段都是一条消息，应用程序必须以消息为单位提取数据，不能一次提取任意字节的数据，这一点和TCP是很不同的。]]></content>
      <categories>
        <category>网络</category>
      </categories>
      <tags>
        <tag>网络</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[salt-api https证书报错解决方法]]></title>
    <url>%2F2015%2F12%2F12%2F18%2F</url>
    <content type="text"><![CDATA[错误如下: 问题的原因是“SSL: CERTIFICATE_VERIFY_FAILED”。 Python 升级到 2.7.9 之后引入了一个新特性，当使用urllib.urlopen打开一个https 链接时，会验证一次 SSL 证书。\而当目标网站使用的是自签名的证书时就会抛出一个 urllib2.URLError:&lt;urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificateverify failed&gt;的错误消息，详细信息可以在这里查看（https://www.python.org/dev/peps/pep-0476/）。 解决方案包括下列两种方式： 1. 使用ssl创建未经验证的上下文，在urlopen中传入上下文参数 import ssl import urllib2 context = ssl._create_unverified_context() print urllib2.urlopen(&quot;https://www.12306.cn/mormhweb/&quot;, context=context).read()12345 2. 全局取消证书验证 import ssl import urllib2 ssl._create_default_https_context = ssl._create_unverified_context print urllib2.urlopen(&quot;https://www.12306.cn/mormhweb/&quot;).read()123456]]></content>
      <categories>
        <category>Python相关</category>
      </categories>
      <tags>
        <tag>Python相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[运维自动化之殇 | 高效运维最佳实践05]]></title>
    <url>%2F2015%2F12%2F08%2F19%2F</url>
    <content type="text"><![CDATA[[作者 萧田国 发布于2015年6月23日 [|] 分享到：微博微信FacebookTwitter有道云笔记邮件分享 “稍后阅读” “我的阅读清单” 专栏介绍“高效运维最佳实践”是InfoQ在2015年推出的精品专栏，由触控科技运维总监萧田国撰写，InfoQ总编辑崔康策划。 前言这些年来，大家都在谈运维自动化。但大家是否也会困惑于“只见树木、不见森林”？或者说，做了几年的运维自动化，但依然不能确定还有哪些工作没做？怎么更优雅的实施运维自动化？ 另外，运维自动化会潜在的带来哪些问题？且听本文分解~ 本文实际上包括两部分，关于运维自动化的一些观点（前3部分）和运维自动化的痛点（第4部分）。如果已是运维自动化的专业人士，可以跳过前面内容，直接鉴赏第4部分——运维自动化之殇。依惯例放上目录，请享用。 什么是运维自动化？ 运维自动化的三个阶段 怎么做运维自动化？ 运维自动化之殇 好吧，我们正式开始。 1. 什么是运维自动化？有人从实用性的角度来表述运维自动化，就是把运维日常需要登录机器的操作，完全Web化，以后只需要点一下鼠标就搞定。然后，和监控结合，就有自动扩缩容，自动告警分析，自动故障发现，自动流量切换。 这种说法正确么？实际上，Web化只是最基础的工作（而且这更多是运维自助化），我们不能将Web化和运维自动化画上等号。 在了解运维自动化之前，让我们回到起点，先看看什么是运维。运维应包括如下： 环境定义：开发环境、测试环境、类生产环境、生产环境等。 部署：能够将部署包有效的部署到不同的环境。 监控：能够监控部署后的系统和应用。 告警响应：出现问题时的响应和处理机制。 性能优化：系统各个服务如Nginx/Java/PHP/DB/网络的优化。 SLA保障：通常要和业务相关部门讨论确定。 所以，运维自动化，应该包括上述这些内容。我们结合起来，略举几例。 1）环境定义自动化：很多公司采用的是数据中心+虚拟机，团队需要某种环境的时候，必须要走流程申请，申请就意味着和不同部门打交道，挨个部门进行层层审批，很浪费时间。 所以环境/基础设施能否自动化很重要，负责开发、管理基础设施的部门，一定要提供方便的接口，帮助其他团队能自动创建资源。 2）部署自动化：这部分的进化过程大抵如此：Scripts -&gt; Auto tools -&gt; Cloud -&gt;Container，略作说明如下： 最早的部署方式，都是ssh到目标机器上，下载部署包，拷贝到指定的位置，重启服务。如果应用频繁升级，操作人员就会很痛苦，所以就想办法自动化。于是大家来写Shell脚本，自动化部署过程。虽然，Shell脚本好用，但是读起来代码量大，不好维护。 随着工具的发展，客户的部署脚本迁移到了Chef/Puppet，使用起来方便，而且容易维护。 再往后有了私有云，公有云，部署方式又发生变化，这时候面对的层次不一样，部署包也不一样，以前的war包，rpm包，现在到了IaaS层，都变成了image，虽然部署简单了，但考虑的问题更多了，怎么管理image，怎么用好image，怎么更快的scale？都是问题。 现在，Container来了，部署在Image的基础上，又变化了，部署自动化现在解决的已经不仅仅是部署本身了，还包括怎么能更快scale，更容易管理artifact，更容易屏蔽底层的不同。 3）监控自动化：现在一般都用Zabbix做问题发现，但得考虑做告警归并，以解决特殊情况下告警泛滥的问题，例如机房断网造成的批量服务器报警。 监控自动化是运维自动化的起点之一，这个又包括了部分故障恢复的自动化，即故障自愈。后者又往往借助于故障树等机制，至少对诸如503错误，可通过自动重启应用服务器程序来恢复。 2. 运维自动化的三个阶段站得高，所以看得更远。也许我们还在给一个小的业务环节搭建运维自动化，但从更高层次了解运维自动化的各个阶段，不无裨益。 1）操作自动化：这个层次的特征是，把运维一系列的手工执行的操作，用脚本或工具简单串起来。最简单的例子就是，把多个Shell脚本串在一起执行实现某个特定的操作目的。 诚如前文所说，这个层次的自动化只部分解决了运维手工执行的问题，但一旦操作的条件发生了变化，可能Shell脚本也得变，运维的压力还是很大，而且容易出错。管理的服务器越多，出错的概率越大得多。 2）场景自动化：这个层次的特征是，工具会根据外部环境判断如何运行，而这些判断条件是事先运维定义好的。此层次的运维系统需要各类环境数据来做为判断条件，同时还要能够变化操作行为（比如不同的执行步骤）。 因此，此层次的运维系统需要跟很多其他系统对接（比如对接了配置系统、网管系统等），最好还要有流程引擎； 3）智能化：此层次的运维系统具备数据核心（大数据存储，所有运营中的数据都会按关联关系集中存储），具备根据数据自己分析和判断、并自我决策和执行的能力。 在此层次，运维的主要工作是为系统增添分析策略、运营和维护此智能运维系统，以及在系统执行的关键节点上介入做人工判断； 3. 怎么做运维自动化？很多运维同仁实施运维自动化时，谋求设计一个完备的系统，来自动化完成几乎所有运维工作——但与此同时，又往往被其复杂程度所困惑、踌躇不前。在我们思考怎么做运维自动化之前，我们需认识到的是： “企业的架构不是设计出来的，是演变而来的。” 这可以近似作为指导思想。这也表明，除非是成熟的大公司，否则不要一开始想着我怎么做个大一统的自动化平台，然后千辛万苦找公司要到资源，然后大半年不出成果（然后绩效还得了个C）。 1）先解决痛点如果登录服务器部署更新程序非常频繁、经常为此起夜或因响应不及时常被业务投诉，那就先做Web部署自助化（例如Jenkins+Ansible）。至于说是否基于CMDB，反而不太重要，特别是如果业务系统并没那么大，服务器变动也没那么频繁的话。 日常工作中，对常见问题进行分类和梳理，能做成工具的就工具化，能程序化操作的，就避免人为干预。 这样各种工具越来越多，小工具组装起来，发挥更大的效能。对于复杂的自动化任务需求，也可以用多个小的、单一功能的模块，组合起来完成复杂的操作，类似于先造零件，再拼装（后文再详细介绍）。 2）选择正确的阶段运维自动化一般沿袭这样的阶段： 手动支撑 =&gt; 线上标准规范化 =&gt; 运维工具化 =&gt;平台自助化/自动化。 选择适合自己当前业务发展阶段的运维自动化方式，很重要哦，不要图谋一口吃成胖子，呵呵。 [也有人说，运维自动化平台就是一个任务执行系统，如果确保准确执行是整个系统的核心所在。] 所以，标准化是运维自动化的前提，如Ngnix/JAVA/PHP/MySQL这些常见服务的应用初始化流程、部署更新流程等，得提前固化下来；另外同理，业务流程和操作顺序也不能乱来。 另外，对于大中型运维自动化平台而言， CMDB和配置系统依然不可或缺。 CMDB即配置管理数据库，一般用于统一管理IT数据、服务器数据资产等。CMDB数据的准确性和权威性，关系到运维自动化是否走在正确的路上——毕竟系统不是人，无法加入感性判断，只能基于冰冷的数据进行触发式处理。 [需要注意的是，解决痛点和标准化/CMDB不是矛盾互斥的：] 解决痛点而搭建的运维自助部署平台，和基于标准化/CMDB而部署的高大上运维自动化平台，可以共存。毕竟前者实施起来快，后者建设周期长。 3）原子件 &amp; 复合件上好佳的运维自动化平台需要融入一些架构设计的思想。这里最重要的就是原子件和复合件的设计，我们先看一下Zachman，企业信息化架构创始人怎么说的： 只有拥有大量原子模型时，才可能大规模重用和组装。也就是在你得到订单之前你就应该在仓库里拥有东西，这样你才能做到大规模客户定制和按订单生产。 复合件的数量是无限的，原子件的数量是有限的；原子件可用于一个以上的实施。 这可以作为我们的指导思想。我们来看一下腾讯游戏基于此的最佳实践。腾讯游戏在底层设计并封装很多原子件，这些原子件可被多次调用。例如原子件“DB容量管理”就应用到复合件“数据决策自动缩扩容”、“运营活动自动开关”等。 4.运维自动化之殇运维自动化是我们的必经之路，那么，一定就是解决所有问题的灵丹妙药么？可能不尽然哦。潜在问题包括如下： 1）忽略权限和基线运维自动化平台通常由DevOps开发（例如Python +Shell），更多的是以实现功能为主，可能对账号权限或服务器操作权限，未做特殊限制，这样问题就来了，例如： 是否针对运维自动化平台的服务器账号做了特殊限制，使得这个账号只能操作指定目录，只能重启Nginx、不能重启PHP？ 是否做了超限检查？例如，对部分特殊请求如“rm-Rf”或超高数值调整做了二次过滤？ 是否做了关键操作的双保险？例如，数据库合并类的危险操作，增加了一个检查人审核机制？ [另外，运维自动化发布平台是否保存有程序基线，并有一键恢复功能？] 大公司的业务系统，运行十多年，开发人员你来我往数以千计，而发布平台每次仅更新部分代码（类似缝缝补补）。这样的后果是，可能根本没有人有一套完整的业务系统代码。 如果执行任意系统命令+缺乏基线，两者兼备，刚好又有人触发了执行操作，那么灾难性的后果就会突然来临。 毕竟，对于历史悠久的大型业务系统而言，老代码往往没人敢动，而且严重SOA化，从零重建的难度之大，也许需要几十个小时。而又因为这种极端情况下，很难形成一个强一致性的版本，所以重建成功往往只是灾难的开始，之后就是开发、客服和DBA陷入长期的疲于奔命之中。 2）缺乏安全机制运维自动化平台一般由非专业开发人员实施，而且是给内部人员使用，主观上容易忽略代码安全和系统安全。 [“上帝节点”是安全灾难的起点。] 之前没有运维自动化，小米加步枪的时代，上千台服务器相对独立，还有各种堡垒机、动态令牌或私钥登录服务器等安全措施，想一个命令删除大批量服务器的程序，还真不容易实现。 运维自动化平台已然是“上帝节点”，天然的实现了连接到大批量服务器（甚至可能直接是root权限）。这样，为广大的黑客朋友带来了无限想象空间。 有朋友可能会说，我放在公司内网了非常安全。其实，现在黑客可以很容易的扫描到内网所有域名，识别到疑似运维自动化平台的域名，然后用常规或非常规手段入侵，然后就“一锅端”了。例如： 你的运维自动化平台是基于通用框架如Django么。一个常识是，越是流行的框架，已知漏洞、甚至0day漏洞越多哦。 3）忽略专业性运维自动化越是充分的公司，隐藏的风险就越大。 即使一个再优秀的运维自动化平台，也不能解决所有运维问题。所以，如果忽略了对人员专业能力的培养，那么在某些需要人工操作的场景（例如机房迁移这类重大调试），问题就会报复性的反弹和爆发。 一次专业的调试，体现在对调试时长和调试效果的掌控上。调试时长必须可接受、并可控。 例如一次跨机房迁移，停业务10小时甚至以上，是很难被接受的；停业务10分钟以下，则是很令人愉快的。但这个的专业化要求很多，包括如充分的演练、更多的任务前置，保证只有必须的操作在调试期间进行。 可控性主要体现在调试节奏的把握，例如是否有快速可操作的回滚措施，保证如果预计调试不能如期完成，能提前预警并快速切回之前的系统状态。 当有重大调试需求时，突然发现中级运维人员没那么多了，初级运维人员缺少专业化锻炼和练手机会，“手生”，主管不敢用之；高级运维人员都已“金盆洗手”多年，自己不敢上手。 4）自得和忽略人文关怀运维自动化平台上线后，运维人员可能会产生一种主观的优越感，并严重阻碍后续工作的开展。以前是开发追着运维打，运维往往疲于奔命，心力憔悴。现在神器在手，容易“多年的媳妇熬成婆”。。。 其实运维自动化只是解决了运维部分工作效率的问题，远没有解决运维的全部问题，外部门对运维的不满，可能涛声依旧，例如经常容易犯的“老板着个脸，说话直接不拐弯；需求老不及时完成，完不成也不说”等等。 运维自动化越是充分的公司，高层管理者（技术VP或CTO）可能产生一种错觉，运维人员是否可以靠边站了？甚至夸张些说，是否可以“卸磨杀驴”了？这种意识层的错觉或者说自我心理暗示，会导致各种多米诺骨牌式的效应。 如果高层忽略人为关怀，在某些极端情况下，运维自动化平台的高权限人员，可能“有意”利用上述提及的平台缺陷，进行极具破坏性的事情。。然后灾难性的后果，可能长时间难以补救。 结语运维自动化的价值在于，将运维从繁琐的、例行、容易发生人为事故的工作中脱离出来，做更有价值的业务运维和服务运维。 所以，从这个角度来看，运维自动化既不是起点，也不是终点。运维自动化不是万能的，我们需要看清楚它的位置。运维自动化既不是起点，也不是终点。 运维自动化，终归只是一个高级工具而已。运维的价值最终是要体现在业务上的： 体现的方式就是运维服务化，所以运维自动化（智能化）最终都要为运维的服务化服务。所以如何构建你的自动化系统最终要看你所支撑的业务需要什么样的服务。 所以，在做之前一定要弄清楚我们的目标，不要为了做而做，如果这样，结果就只能是呵呵了。]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Fiddler教程]]></title>
    <url>%2F2015%2F12%2F08%2F20%2F</url>
    <content type="text"><![CDATA[[1.简介] Fiddler（中文名称：小提琴）是一个HTTP的调试代理，以代理服务器的方式，监听系统的Http网络数据流动， Fiddler可以也可以让你检查所有的HTTP通讯，设置断点，以及Fiddle所有的“进出”的数据（我一般用来抓包）,Fiddler还包含一个简单却功能强大的基于JScript .NET事件脚本子系统，它可以支持众多的HTTP调试任务。 Fiddler官方网站提供了大量的帮助文档和视频教程,这是学习Fiddler的最好资料 Fiddler_官方网站 Fiddler_官方文档 Fiddler_官方视频 Fiddler_官方插件 2. 工作原理Fiddler是以代理WEB服务器的形式工作的,浏览器与服务器之间通过建立TCP连接以HTTP协议进行通信，浏览器默认通过自己发送HTTP请求到服务器，它使用代理地址:127.0.0.1,端口:8888. 当Fiddler开启会自动设置代理，退出的时候它会自动注销代理，这样就不会影响别的程序。不过如果Fiddler非正常退出，这时候因为Fiddler没有自动注销，会造成网页无法访问。解决的办法是重新启动下Fiddler. 3. HTTP协议简介3.1 什么是HTTP协议协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则，超文本传输协议(HTTP)是一种通信协议，它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器，目前我们使用的是HTTP/1.1版本。 3.2 URL详解URL(Uniform Resource Locator) 地址用于描述一个网络上的资源,基本格式如下 schema://host[:port#]/path/.../[?query-string][#anchor] 名称 解释 scheme 指定低层使用的协议(例如：http, https, ftp) host HTTP服务器的IP地址或者域名 port# HTTP服务器的默认端口是80，这种情况下端口号可以省略。如果使用了别的端口，必须指明，例如 http://www.test.com:8080/ path 访问资源的路径 query-string 发送给http服务器的数据 anchor 锚 3.3 HTTP消息的结构 Request\\先看Request 消息的结构, Request 消息分为3部分，第一部分叫Requestline, 第二部分叫Request header, 第三部分是body.header和body之间有个空行 第一行中的Method表示请求方法,比如\”POST\”,\”GET\”,Path-to-resoure表示请求的资源， Http/version-number表示HTTP协议的版本号,当使用的是\”GET\” 方法的时候， body是为空的\ Response\\我们再看Response消息的结构, 和Request消息的结构基本一样。同样也分为三部分,第一部分叫Response line, 第二部分叫Responseheader，第三部分是body. header和body之间也有个空行\ 3.4 状态码Response 消息中的第一行叫做状态行，由HTTP协议版本号， 状态码， 状态消息三部分组成。\状态码用来告诉HTTP客户端,HTTP服务器是否产生了预期的Response.\HTTP/1.1中定义了5类状态码，状态码由三位数字组成，第一个数字定义了响应的类别 状态码 解释 1XX 提示信息，表示请求已被成功接收，继续处理 2XX 成功，表示请求已被成功接收，理解，接受 3XX 重定向，要完成请求必须进行更进一步的处理 4XX 客户端错误，请求有语法错误或请求无法实现 5XX 服务器端错误，服务器未能实现合法的请求 200 OK\最常见的就是成功响应状态码200了，这表明该请求被成功地完成，所请求的资源发送回客户端\ 302 Found\重定向，新的URL会在response中的Location中返回，浏览器将会自动使用新的URL发出新的Request 例如在IE中输入， http://www.google.com.HTTP服务器会返回302， IE取到Response中Location header的新URL,又重新发送了一个Request.\ 304 Not Modified\代表上次的文档已经被缓存了， 还可以继续使用，例如打开博客园首页,发现很多Response 的status code 都是304\[提示： 如果你不想使用本地缓存可以用Ctrl+F5 强制刷新页面]\ 400 Bad Request 客户端请求与语法错误，不能被服务器所理解 403 Forbidden 服务器收到请求，但是拒绝提供服务 404 Not Found\ 500 Internal Server Error 服务器发生了不可预期的错误 503 Server Unavailable服务器当前不能处理客户端的请求，一段时间后可能恢复正常 4. 界面操作4.1 主界面Fiddler的主界面分为工具面板、会话面板、监控面板、状态面板，下面进行一一介绍。 4.2 工具面板 说明\注释、重新请求、删除会话、继续执行、流模式/缓冲模式、解码、保留会话、监控指定进程、寻找、保存会话、切图、计时、打开浏览器、清除IE缓存、编码/解码工具、弹出控制监控面板、MSDN、帮助 两种模式 缓冲模式（Buffering Mode）\Fiddler直到HTTP响应完成时才将数据返回给应用程序。可以控制响应，修改响应数据。但是时序图有时候会出现异常 流模式（Streaming Mode）\Fiddler会即时将HTTP响应的数据返回给应用程序。更接近真实浏览器的性能。时序图更准确。但是不能控制响应。 4.3 会话面板4.4 监控面板 统计报表 (1) 请求总数、请求包大小、响应包大小； (2)请求起始时间、响应结束时间、握手时间、等待时间、路由时间、TCP/IP传输时间； (3) HTTP状态码统计； (4) 返回的各种类型数据的大小统计以及饼图展现。\ 时间轴\每个网络请求都会经历域名解析、建立连接、发送请求、接受数据等阶段。把多个请求以时间作为X轴，用图表的形式展现出来，就形成了瀑布图。在Fiddler 中，只要在左侧选中一些请求，右侧选择Timeline标签，就可以看到这些请求的瀑布图 看到这张图，你是否可以回答这些问题： 图标的 Y 轴上显示的是简化后的URL。为什么有些是绿色的，有些是黑色的？ 为什么第一个请求用阴影线来表示，其它请求却都是实心的？ 请求条的不同颜色分别代表什么？ 每个请求中的黑色竖线表示什么？ 请求后面的图标（如闪电和软盘）代表了什么？ 每个请求前面两个小圆圈是什么，为什么有的是红色，有的是绿色？\下面将一一揭晓。 绿色的请求表示这是一个“有条件的请求”。HTTP 协议定义了 5个条件请求头部，最常见的两个是“If-Modified-Since”和“If-None-Match”。服务器根据这两个头部来验证本地缓存是否过期，如果过期则正常返回资源的最新版本；否则仅返回304 NotModified，浏览器继续使用本地缓存。包含条件请求头部的请求用绿色显示，否则用黑色。 有阴影线的请求是缓冲模式下的请求，实心的是流模式下的请求。Fiddler提供了缓冲（Buffering）和流（Streaming）两种抓包模式：缓冲模式下，Fiddler会在响应完成时才将数据返回给应用程序（通常是浏览器），这种模式下可以控制响应，方便地修改响应内容；流模式下，Fiddler会实时返回响应数据给浏览器，但没办法控制响应。一般使用流模式，瀑布图会更真实一些。这两种模式可以通过Fiddler 的工具栏选择。特别的，通过 Fiddler的“AutoResponder”功能返回的响应，只能是缓冲模式。 请求条的不同颜色对应着不同类型的响应，根据响应头的 MIME Type来归类。如浅绿色表示图片类型的响应；深绿色是 JavaScript；紫色是CSS；其它都是蓝色。 请求中的黑色竖线，表示的是浏览器收到服务端响应的第一个字节这一时刻。这个时间受DNS 解析、建立连接、发送请求、等待服务端响应等步骤的影响。 请求条后面的图标表示响应的某些特征。如软盘图标表示这个响应正文从本地获得，也就是说服务端返回了304；闪电表示这是 Fiddler的“AutoResponder”的响应；向下的箭头表示响应是302，需要重定向；红色感叹号说明这个请求有错误发生（状态码是 4XX 或5XX）。特别的，如果请求条后面有一个红色的X，说明服务端响应完这个请求之后，断开了连接。出现这种情况一般有两种可能：HTTP/1.0的响应中没有 Connection: Keep-Alive；或者是 HTTP/1.1 的响应中包含了Connection: close。使用持久连接可以省去建立连接的开销，也可以减小TCP 慢启动和其它拥塞控制机制带来的影响，总之是好处多多。 请求前面的红色圆圈表示这个连接是新建的，绿色表示是复用的。上面的圆圈表示的是浏览器到Fiddler 的连接，下面的圆圈是 Fiddler 到服务端的连接。 4.5 状态面板 控制台\Fiddler的左下角有一个命令行工具叫做QuickExec,允许你直接输入命令。\常见得命令有 命令 解释 help 打开官方的使用页面介绍，所有的命令都会列出来cls 清屏 (Ctrl+x 也可以清屏)select 选择会话的命令?.png 用来选择png后缀的图片bpu 截获requestbpafter 截获response 5. 常用功能5.1 监听HTTPSFiddler不仅能监听HTTP请求而且默认情况下也能捕获到HTTPS请求，Tool -&gt;Fiddler Option -&gt; HTTPS下面进行设置，勾选上“Decrypt HTTPStraffic”，如果不必监听服务器端得证书错误可以勾上“Ignore servercertification errors”，也可以跳过几个指定的HOST来缩小或者扩大监听范围。 HTTPS例子：\https://pay.tenpay.com/main/app/v1.0/trans_manage.cgi?OutPutType=JSON 5.2 HOST切换5.2 模拟各类场景 通过GZIP压缩，测试性能 模拟Agent测试，查看服务端是否对不同客户端定制响应 模拟慢速网络，测试页面的容错性 禁用缓存，方便调试一些静态文件或测试服务端响应情况 根据一些场景自定义规则\ 低网速模拟\有时出于兼容性考虑或者对某处进行性能优化，在低网速下往往能较快发现问题所在也容易发现性能瓶颈，可惜其他调试工具没能提供低网速环境，而强大的Fiddler考虑到了这一点，能够进行低网速模拟设置Rules &gt;Performance &gt; Stimulate Modem Speeds。 5.3 Compare（对比文本）5.4 Composer（构造器）请求构造顾名思义就是我们可以模拟请求，也就是说我们可以借助Fiddler的Composer在不改动开发环境实际代码的情况下修改请求中的参数值并且方便的重新调用一次该请求，然后相比较2次请求响应有何具体不同。任何一个请求参数只要是合法的取值再次调用后都会有相应的响应，那么你想要的任意一个合法请求组合自然也能够按照你的意愿构造出来，然后再次调用以及查看返回数据，十分方便！ 下面举一个交易查询请求构造的例子。首先进入交易查询页面抓包找到目标请求https://pay.tenpay.com/main/app/v1.0/trans\_manage.cgi?OutPutType=JSON，双击该包在Inspectors标签下查看返回数据为JSON格式，而XML格式一栏为空：\ 将该请求鼠标左键单击拖入Fiddler右侧RequestBuilder标签内并修改原请求参数OutPutType=JSON为OutPutType=XML，然后点击Execute按钮再次触发调用请求，\ 双击这次请求包在Inspectors标签下查看返回数据为XML格式，而JSON格式一栏为空：\ 5.5 Filters(过滤监控)对一个重新载入的页面进行抓包，如果包的条目过多而你需要关注的就那么几项的话，可以使用Fiddler的过滤器Filters进行抓包，那么抓包时只会抓取你希望抓到的那些包。切换到Filters标签勾选Usefilter，以便激活过滤器，这样下面的各种过滤方式就可以进行选择了。 (1).\ (2).\ 选项1 解释 No zone filter 不设置hosts过滤 Show Only Intranet Hosts 只显示内网HOST Show Only Internet Hosts 只显示外网HOST令 选项2 解释 No Host Filter 不设置hosts过滤 Show Only The Following Hosts 隐藏过滤到的域名 Show Only The Following Hosts 只显示过滤到的域名 Flag The Following Hosts 标记过滤到的域名 5.5 AutoResponder(请求重定向)所谓请求无非就是需要调用到的一些资源(包括JS、CSS和图片等)，所谓重定向就是将页面原本需要调用的资源指向其他资源(你能够控制的资源或者可以引用到的资源)。 (1)你可以将前台服务器的诸多或者某个资源在本地做个副本，如果正常网络访问环境下该资源出现了BUG而导致开发环境崩溃时，可以先将这个资源的请求重定向到本地副本，这样就可以继续进行开发调试你的页面，从而大量节省资源维护的等待时间。 (2)你也可以将多人同时维护的某个JS文件复制一份出来在本地，当你的开发调试收到他人调试代码干扰时，可以将这个JS的调用重定向到本地无干扰的JS文件，进行无干扰开发，功能开发完成并调试OK之后再将你的代码小心合入到开发环境中，这样就可以避免受到他人干扰专心搞你的模块开发，也就是说能够将JS文件脱离开发环境却不影响线上调试。 (3)你还可以将样式文件或者图片指向本地如果需要的话。开发过程中的很多页面其实都是惨不忍睹的，究其原因很大程度上是因为缺少对应的样式文件或者没有图片资源，所以样式文件和图片的重定向会对美感稍有要求的开发人员带来福音。 6. 插件介绍6.1 Format6.2 Script Fiddler Script 是用JScript.NET语言写的，\JScript.NET.aspx) 在这个方法中修改Request的内容， 我们用得最多, static function OnBeforeRequest(oSession: Session) 在这个方法中修改Response的内容， static function OnBeforeResponse(oSession: Session) 添加IP Main方法中添加 FiddlerObject.UI.lvSessions.AddBoundColumn(&quot;HostIP&quot;, 50, &quot;x-hostIP&quot;); 请求，响应延迟 在OnBeforeRequest 添加 oSession[&quot;request-trickle-delay&quot;] = &quot;3000&quot;; oSession[&quot;response-trickle-delay&quot;] = &quot;3000&quot;; 我们可以控制Session在Fiddler中显示的样式，把这段脚本放在OnBeforeRequest(oSession:Session) 方法下，并且点击\”Save script\”,这样所有的cnblogs的会话都会显示红色. if (oSession.HostnameIs(&quot;www.cnblogs.com&quot;)) { oSession[&quot;ui-color&quot;] = &quot;red&quot;; } Fiddler Script中修改Cookie\Cookie其实就是request中的一个header,注意:FiddlerScript不能直接删除或者编辑单独的一个cookie，你需要用replace方法或者正则表达式的方法去操作cookie的string static function OnBeforeRequest(oSession: Session) { if (oSession.HostnameIs(&apos;www.example.com&apos;) &amp;&amp; oSession.uriContains(&apos;pagewithCookie&apos;) &amp;&amp; oSession.oRequest.headers.Contains(&quot;Cookie&quot;)) { var sCookie = oSession.oRequest[&quot;Cookie&quot;]; // 用replace方法或者正则表达式的方法去操作cookie的string sCookie = sCookie.Replace(&quot;cookieName=&quot;, &quot;ignoreme=&quot;); oSession.oRequest[&quot;Cookie&quot;] = sCookie; } 删除所有的cookie oSession.oRequest.headers.Remove(&quot;Cookie&quot;); 新建cookie oSession.oRequest.headers.Add(&quot;Cookie&quot;, &quot;username=testname;testpassword=P@ssword1&quot;); Fiddler Script中修改Request 中的body static function OnBeforeRequest(oSession: Session) { if(oSession.uriContains(&quot;http://www.cnblogs.com/&quot;)) { // 获取Request 中的body字符串 var strBody=oSession.GetRequestBodyAsString(); // 用正则表达式或者replace方法去修改string strBody=strBody.replace(&quot;1111&quot;,&quot;2222&quot;); // 弹个对话框检查下修改后的body FiddlerObject.alert(strBody); // 将修改后的body，重新写回Request中 oSession.utilSetRequestBody(strBody); } } VS插件：https://visualstudiogallery.msdn.microsoft.com/872d27ee-38c7-4a97-98dc-0d8a431cc2ed 6.3 三方插件 .NET可以开发 插件管理\ 7. 浏览器抓包方式7.1 IE7.2 Firefox7.3 Chrome7.4 VS我们在用visual stuido 开发ASP.NET网站的时候也需要用Fiddler来分析HTTP，默认的时候Fiddler是不能嗅探到localhost的网站。 在localhost后面加个点号，Fiddler就能嗅探到。 例如：原本ASP.NET的地址是 http://localhost:2391/Default.aspx， 加个点号后，变成http://localhost.:2391/Default.aspx就可以了\ 8. 移动端抓包Fiddler不但能截获各种浏览器发出的HTTP请求,也可以截获各种智能手机发出的HTTP/HTTPS请求。 Fiddler能捕获IOS,Andriod,WinPhone,设备发出的请求，同理，也可以截获IPad,MacBook的等设备发出的HTTP/HTTPS。 前提条件是：安装Fiddler的机器，跟Iphone 在同一个网络里，否则IPhone不能把HTTP发送到Fiddler的机器上来。 具体操作步骤如下： Fiddler设置\打开Fiddler, Tools-&gt; FiddlerOptions。（配置完后记得要重启Fiddler）. 选中\”Allow remote computers to connect\”.是允许别的机器把HTTP/HTTPS请求发送到Fiddler上来\ 获取Fiddler所在机器的IP 安装Fiddler证书\这一步是为了让Fiddler能捕获HTTPS请求。 如果你只需要截获HTTP请求，可以忽略这一步 首先要知道Fiddler所在的机器的IP地址： 假如我安装了Fiddler的机器的IP地址是:192.168.1.104\打开IPhone 的Safari,访问 [http://192.168.1.104:8888，]{} 点\”FiddlerRoot certificate\”然后安装证书 打开IPhone, 找到你的网络连接， 打开HTTP代理，输入Fiddler所在机器的IP地址(比如:192.168.1.104)以及Fiddler的端口号8888\ 9. 推荐书籍 《Fiddler调试权威指南》是Fiddler的开发者EricLawrence编写的一本权威的参考指南。全书分为10章和4个附录，从认识Fiddler开始，介绍了基本技巧和概念、配置选项、Inspectors、扩展、数据流导入导出、FiddlerScript和FiddlerCore等主题；附录部分还给出了故障排除和命令行等有用的参考信息。 《Fiddler调试权威指南》适合Web开发人员和Web测试人员阅读参考，也适合想要学习和掌握Fiddler的读者阅读。通过《Fiddler调试权威指南》，你将学会如何利用Fiddler调试Web相关的应用，掌握如何调试HTTPS数据流，学会如何在流行的设备上使用Fiddler，甚至掌握更多高级的扩展功能。 10. 其他抓包工具同类的工具有 : HttpWatch, Firebug,Chrome自带调试工具，WireShark 11. 总结通过以上的介绍，你应该已经发现fiddler其它强大的功能。fiddler绝对是开发利器。 Fiddler能记录所有客户端和服务器的HTTP和HTTPS请求，允许你监视、设置断点，甚至修改输入输出数据，Fiddler包含了一个强大的基于事件脚本的子系统，并且能使用.NET语言进行扩展； 你对HTTP协议越了解，你就能越掌握Fiddler的使用方法，你越使用Fiddler,就越能帮助你了解HTTP协议，两者关系紧密、相辅相成； 强大图形呈现，拖拽操作，丰富的插件。 使用Fiddler无论对Coder还是Tester来说，都是非常有用的工具。]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[FIDDLER 抓包分析]]></title>
    <url>%2F2015%2F12%2F08%2F21%2F</url>
    <content type="text"><![CDATA[撮此处]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[【干货】大众点评运维架构的图文详解]]></title>
    <url>%2F2015%2F11%2F25%2F22%2F</url>
    <content type="text"><![CDATA[分享内容今天分享专题大纲如图所示，从5个方面跟大家一起探讨： {width=”498”height=”333”} 1、点评运维团队的配置目前我们运维分为4个组，相信跟大部分公司一样，运维团队分为：应用运维、系统运维、运维开发和监控运维，当然还有DBA团队和安全团队，这里就不一一罗列了。整个运维团队全算上目前是不到40人规模。 {width=”498”height=”446”} 我们团队分工是这样的： 应用运维：负责支持线上业务，各自会负责对应的业务线，主要职能是保证线上业务稳定性和同开发共同支撑对应业务，以及线上服务管理和持续优化。 运维开发：帮助运维提升工作效率，开发方便快捷的工具，实现运维平台化自动化。 系统运维：负责操作系统定制和优化，IDC管理和机器交付，以及跳板机和账号信息管理。 监控运维：负责发现故障，并第一时间通知相关人员，及时处理简单故障和启动降级方案等。 2、点评的整体架构先看下点评的机房情况。 {width=”498”height=”453”} 点评目前是双机房结构，A机房主跑线上业务，B机房跑测试环境和大数据处理作业，有hadoop集群、日志备份、灾备降级应用（在建）等。点评目前机房物理机+虚拟机有近万台机器。 点评的整体架构，还是跟多数换联网公司一样，采用多级分层模式，我们继续来详细看下点评整体架构。 {width=”498”height=”451”} 上面这幅图基本概括了点评的整体架构环境： 用户引导层用的是第三方的智能DNS+CDN。 负载均衡首先是F5做的4层负载均衡之后是dengine做的7层负载均衡（Dengine是在tengine基础上做了二次开发）。再往后是varnish做的页面缓存 之后请求到web端 web端通过内部协议调用service（RPC）。 图片存储用的是mogileFS分布式存储 。 所有业务，全部有高可用方案，应用全部是至少2台以上。 当然，具体业务要复杂很多，这里只是抽象出简单层面，方便各位同学理解。 目前，点评运维监控是从4个维度来做的： 业务层面，如团购业务每秒访问数，团购券每秒验券数，每分钟支付、创建订单等（cat）。 应用层面，每个应用的错误数，调用过程，访问的平均耗时，最大耗时，95线等（cat）。 系统资源层面：如cpu、内存、swap、磁盘、load、主进程存活等（zabbix）。 网络层面： 如丢包、ping存活、流量、tcp连接数等（zabbix cat）。 3、点评运维系统介绍{width=”498”height=”426”} 点评的运维和平台架构组做了很多实用的工具，这些工具组成了点评的整体运维体系。 目前自动化运维比较热，但自动化运维个人觉得是一种指导思想，没必要硬造概念和生搬硬套。自动化在很多公司百花齐放，各家有各家的玩法。但不管怎么定义，运维人员都必须从不同纬度去面对和解决企业所存在的问题。 点评在这方面，也是摸着石头过河，我们的思路是先造零件，再整合，通过零件的打造和之间的整合，慢慢勾勒出一条适合自己的运维自动化框架。 我们运维的理念是： 能用程序干活的，坚决程序化、平台化； 能用管理解决的问题，不用技术解决； 同一个错误不能犯三次； 每次故障，都是学习和提升的机会； 每个人都要有产品化思维，做平台产品让开发走自助路线； 小的，单一的功能，组合起来完成复杂的操作（任务分解）； 所以，我们将自己的理念，融入到自己的作品中，做出了很多工具。 首先整体做个说明，点评运维工具系统汇总： 全方位监控系统：覆盖业务、应用、网络、系统等方面，做到任何问题，都可直观反馈。对不同应用等级，做到不同监控策略和报警策略。 自动化工具系统：对重复的、容易出错的、繁琐的工作尽可能工具化，通过小的策略组合，完成大的任务。 配置和管理系统：对于复杂的配置管理，尽可能web化、标准化、简单化，有模板定义，有规范遵循。 记录和分析系统：对发生的问题和数据做记录并分析，不断的总结、完善和提升。 下面就跟大家来一一介绍下： 3.1 全方位监控系统Zabbix大家应该非常熟悉了，这里就不做介绍，主要介绍下cat监控。 {width=”498”height=”334”} 业务监控： 这张是cat的应用监控图表，可直观从业务角度看出问题，可跟基线的对比，发现问题所在。如图所示，此时支付远偏离基线，流量正常，可能后端出了问题。 除了这些，还有创建订单、支付、首页访问、手机访问等业务数据。 这张图是从业务角度来监控的。 {width=”498”height=”440”} 这张也是从业务层面来监控的，该图展示的是手机的访问量趋势图，下面包括延迟、成功率、链接类型、运营商等都有明确数据，该监控可全方位覆盖业务。 {width=”498”height=”379”} 应用监控： 从业务层面往下，就是应用层面。 应用状态大盘可清晰表示当前业务组件状态，如果某个业务不可用，其下面某个应用大量报错，说明可能是该应用导致。 该监控大盘十分清晰明的能展示业务下面的应用状态，可在某业务或者某域名打不开的时候，第一时间找出源头。 下图为应用报错大盘，出问题的应用会实时登榜（每秒都会刷新数据），当出现大故障时，运维人员可一眼看出问题；而当多个不同业务同时报错时，则可能是公共基础服务出了问题。 {width=”498”height=”390”} 再看下图的这个功能，是Cat最强大的功能，能完整显示应用之间调用过程，做了什么事情，请求了那些，用了多长时间，成功率是多少，访问量是多大，尽收眼底。Cat几乎无死角的覆盖到业务和应用层面的监控，当然还可做网络等层面监控，总之非常强大。这也是点评的鹰眼系统。 {width=”498”height=”392”} Logscan日志扫描工具: {width=”498”height=”434”} Logscan系统，是一套日志扫描工具，可根据你定义的策略，对日志内容进行定时扫描，该工具可覆盖到基于日志内容的检测，结合zabbix和cat，实现无死角覆盖。比如有一些攻击的请求，一直遍历你的url，通过cat、zabbix等都无法灵活捕获，有了日志扫描，便可轻松发现。 3.2 自动化工作系统首先介绍下点评的流程系统-workflow系统 顾名思义workflow是一套流程系统，其核心思想是把线上所有的变更以标准化流程的方式，梳理出来。 我们遵循一个理念，能用程序跑，就不去人操作。 流程有不同状态的转化，分别为发起、审计、执行、验证等环节。用户可自行发起自己的需求变更，通过运维审核，操作（大部分是自动的），验证。如扩容、上线、dump内存、封IP等都为自动化流程。 {width=”498”height=”436”} 以我们线上自动化扩容流程为展示，用户使用时，需要填写对应信息，提交后，运维在后台审核过后，就完全自动化扩容，扩容完成会有邮件通知，全程运维不需要登录服务器操作。（自动化倒不是太复杂的技术难题，通过小的任务组合，设置好策略即可）.几十台机器的扩容，运维只需点个审核通过按钮，数分钟而已。 {width=”498”height=”453”} 经过长时间的推广，点评现在98%以上变更都是通过工作流平台完成的，所有变更全部有记录，做到出问题时有法可依，违法可纠。 而且通过流程单的使用频率，可做数据分析，了解哪些操作比较频繁，能否自动化掉，是否还有优化空间。这才是做平台的意义，以用户为导向。 {width=”498”height=”397”} 流程系统就介绍到这里，朋友们可关注下其中核心思想。 下面介绍另一套重量级核心系统：Button系统 Button是一套代码管理、打包、部署上线系统，开发可完全自主化进行上传代码，自动化测试，打包，预发，灰度上线，全部上线，问题回滚等操作。全程运维不用干预，完全平台自主化。 {width=”498”height=”437”} 点评的运维，除了有些没法自动化的手动配置下，其他基本都是开发自助。这就是自动化的威力！ Go平台系统，是一套运维操作系统，其中包含了很多常规操作、如批量重启、降级、切换、上下线、状态检测等。 该系统主要是解决运维水平参差不齐，工具又各有各的用法，比如说批量重启操作，有用ssh、有用fabric、有自己写shell脚本的。干脆直接统一，进行规范，定义出来操作，通过平台化进行标准化。由于长时间不出问题，偶尔出一下，运维长时间不操作，找个批量重启脚本还要找半天。哪些不能自动化的，我们基本都做到go里了，在这里基本都是一键式的傻瓜操作了。 {width=”498”height=”411”} 现在，我们监控团队就可以灵活操作，不需要有多高的技术含量，并且每次操作都有记录，做好审计和授权。 {width=”498”height=”439”} 所有后台基本都是python、shell脚本实现，小的脚本组再整合成任务，这也是我们的重要理念之一。对于比较复杂的任务，我们进行分解，然后用小的，单一的功能，组合起来完成复杂的操作（任务分解）。其实我们实现自动化也是这个思路，先造零件，再拼装。 {width=”498”height=”431”} 尽管有了puppet，go等工具，但对于一些job作业的管理，也显得非常吃力，我们架构组的同学做出一套任务调度系统。相当于分布式的crontab，并且有强大的管理端。完全自主化管理，只需要定义你需要跑的job，你的策略，就完全不用管了。会自动去做，并且状态汇报、监控、等等全部都有记录，并实现完全自助化。 {width=”498”height=”440”} {width=”498”height=”451”} 以上这些系统都非常注重体验，都有非常详细的数据统计和分析，每过一段时间，都有人去看，不断改进和优化，真正做到产品自运营。还有一些自动化系统就不一一介绍了。 3.3 配置和管理系统先介绍下puppet管理系统，相信不少同学对puppet语法格式深恶痛绝，并且也领教过一旦改错造成的故障严重性。 而且随着多人协同工作后，模板和文件命名千奇百怪，无法识别。 针对这些问题，点评就做了一套管理工具，主要是针对puppet语法进行解析，实现web化管理，并进行规范化约束。 跟go系统一样的想法，将puppet中模块进行组合，组合成模块集（方法集），可方便识别和灵活管理。 {width=”498”height=”416”} 下面展示的是我们的软负载均衡管理页面，该系统是线上SLB的管理系统。其核心在于把nginx语法通过xml进行解析，实现web化管理，傻瓜式配置，规范化配置，避免误操作，版本控制，故障回滚等。 {width=”498”height=”435”} {width=”498”height=”436”} 点评系统很多，基本上遇到个痛点，都会有人想办法把痛点解决。 下面就介绍下点评另一套强大配置系统，lion。 {width=”498”height=”419”} Lion是一套应用配置管理系统，点评的所有应用用到的配置，不在本地文本文件存储，都在一个单独系统存储，存储以key/value的方式存储。并且也是完全平台化，运维负责做好权限控制和审计。开发全部自助。 其核心是用了zookeeper的管理机制，将配置信息保存在 Zookeeper的某个目录节点中，然后将所有需要修改的应用机器监控配置信息的状态，一旦配置信息发生变化，每台应用机器就会收到Zookeeper 的通知，然后从 Zookeeper 获取新的配置信息应用到系统中。 是不是在点评做运维轻松很多？各种操作都工具化，自助化，自动化了。那运维还需要做什么。 3.4 记录和分析系统此类系统虽然不怎么起眼，但对我们帮助也是特别大的，我们通过一些系统的数据记录和分析，发现了不少问题，也解决不少潜在问题，更重要的是，在这个不断完善总结的过程中，学习到了很多东西。 这个是我们故障分析系统，所有的故障都会做记录，故障结束后都会case bycase的进行深入分析和总结。其实以上很多系统，都是从这些记录中总结出来的。 {width=”498”height=”407”} 该系统为故障记录系统，每个故障都有发生的缘由和改进的方案，定期有人review。 运维起来很轻松吗？也不轻松，只是工作重点有了转移，避开了那些重复繁琐的工作，和开发同学深度结合，共同注重运营质量和持续优化。 再来看下图所示是点评的DOM系统，即运营质量管理平台，该平台汇总了线上的服务器状态、应用响应质量、资源利用率、业务故障等全方位的数据汇总平台。 {width=”498”height=”424”} 并通过同比和环比，以及平均指标等数据，让各开发团队进行平台化PK，性能差的运维会去推动改进。 {width=”498”height=”411”} 最后一个需要介绍的是雷达系统，该系统是我们最近在做的，一个比较高大上的项目。 朋友们也感受到了，我们系统之多，出问题查起来也比较费时。不少同学生产环节也遇到过类似问题，出了问题到底是什么鬼？到底哪一块引起的呢？结合这个问题，我们把线上的问题做了个分类，并给了一些策略层面的算法，能快速显示。可让故障有个上下文的联系，如：上线时间、请求数下降、错误数增多等，哪个先出现，哪个后出现？当然，这块功能还在做，目标是实现出问题的时候，一眼就能从雷达系统定位问题类型和范围。 {width=”498”height=”403”} 以上向大家演示的就是点评的运维系统，相信我们点评的运维思想都在里面体现了。 运维点评这几年的发展，主要目标是实现平台规范化、运维高效化、开发自主化。 之前也是通过运维root登录，然后写脚本批量跑命令的低效运维。也经历过CMDB系统信息不准确，上线信息错乱的尴尬局面。也遇到过出了很大问题，运维忙来忙去，找不到rootcase。 好在，通过努力，这些问题现在都有了很大改观，相信朋友们通过展示的系统，能感觉出点评运维的进步。 4、运维踩过的坑和改进的地方我就这些年，点评运维出的一些case案例，跟大家聊一聊我们做了哪些具体工作: 变更不知道谁做的，无法恢复，变更完也找不到根据，造成重大故障。//之前线上puppet通过vim的管理方式，由于运维同学失误推了一个错误配置，导致全部业务不可用1个小时，我们后面通过规范puppet配置修改并做成工具，进行权限控制，还加了流程系统，进行避免。 出了问题，开发说代码没问题，运维说环境没问题，该找谁？//我们后面做了工具，通过DOM和cat系统，可进行深度诊断，基本很容易定位问题所属。 执行了个错误命令，全线都变更了，导致服务不可用。//我们通过go系统，进行日常操作梳理，并做成工具，运维90%操作都可通过自动化流程和go平台完成。大大缩减故障产生率，并且之后进行权限回收。 出问题了，各种系统翻来查去，无法快速定位，找不到rootcase。//点评正在做雷达系统，就是将历史存在的问题，进行复盘，将一些故障类型，进行分级，然后通过策略和算法，在雷达系统上进行扫描，出问题环节可快速第一时间优先显示。 运维天天忙成狗，还不出成绩，天天被开发吐槽。//点评这两年完全扭转了局势，现在是运维吊打开发，因为我们目前，大部分系统都实现了开发自助化，运维被解放出来，开始不断完善平台和关注业务运营质量，我们dom系统是可定制的，运维每天都把各业务的核心指标报表发到各位老大那里，哪些服务质量差，响应慢，开发都会立即去改。（当然，需要老大们支持）。 5、未来关注的领域和方向点评也有些前沿的关注点，比如比较热的Paas技术。 PaaS和云很热，还有docker技术，点评也不能掉队，目前点评有数千个docker的实例在跑线上的业务。 {width=”498”height=”427”} {width=”498”height=”381”} 上图java都是跑的docker实例 {width=”498”height=”403”} 目前点评Docker这块可做到10秒内快速部署业务并可响应用户请求。30秒内可完成一次实例无缝迁移。个人感觉docker技术不在于底层这块，在于上层管理系统的构造。底层一方面是持续优化，挖掘性能，但更重要的是在策略层和调度层。如何快速部署、迁移、恢复、降级、扩容等，做好这些还有不少挑战。 点评这两年成长很多，但需要走的路也很多，未来关注的点会在多系统的有机整合和新技术的尝试以及发展，还会更多的关注智能策略层面。 结束语在最后结束时，感谢各位到场朋友捧场，也感谢点评运维和平台架构的每一位同事，有了你们，点评运维才走到了今天，我们共同努力，来创造新时代的运维体系。 点评很多系统都是第一次拿出跟大家分享，大家可看一下设计理念和思想。]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[为什么安装 Navicat version 9 后，当打开查询或保存报表时，我会收到错误信息？]]></title>
    <url>%2F2015%2F11%2F18%2F23%2F</url>
    <content type="text"><![CDATA[可应用操作系统： Windows Vista、Windows 7 可应用 Navicat 产品： 全部 可应用 Navicat 版本编号：版本 9 \ Cannot create file \”C:\Program Files\PremiumSoft\Navicat 8.2MySQL\ … xxx.xxx\”. 系统找不到指定的路径。\ [原因]{}如果你使用 Windows Vista/7以及启用用户帐户控制功能，并在默认安装路径安装 Navicat 版本8，而你的查询及报表保存在 Navicat 安装文件夾，例如：\”C:\ProgramFiles\PremiumSoft\Navicat 8.2MySQL\Server1\Database1\xxx.xxx\”；请注意，你的查询及报表将实际写入一个虚拟存储，例如：\”C:\Users\[YourUserName]\AppData\Local\VirtualStore\ProgramFiles\PremiumSoft\Navicat 8.2 MySQL\Server1\Database1\xxx.xxx\” 如果你在不同的安装文件夾升级到 Navicat 版本 9，例如：\”C:\ProgramFiles\PremiumSoft\Navicat for MySQL\”，当 Navicat 版本 9 尝试访问\”C:\Program Files\PremiumSoft\Navicat 8.2MySQL\Server1\Database1\xxx.xxx\”，Windows Vista/7不会对应到虚拟存储路径\”C:\Users\[YourUserName]\AppData\Local\VirtualStore\ProgramFiles\PremiumSoft\Navicat 8.2MySQL\Server1\Database1\xxx.xxx\”，因而访问失败。 \ [解决方法 1]{}更改设置保存路径到一个 Program Files 目录以外的位置。例如：\ &quot;C:\Users\[YourUserName]\Documents\Navicat\....\....&quot; {width=”486”height=”226”} [解决方法 2]{}更改相关路径到 Navicat 版本 8 虚拟存储。\ 例如 - 设置保存路径： &quot;C:\Program Files\PremiumSoft\Navicat 8.2 MySQL\....\....\....&quot; =&gt; &quot;C:\Users\[YourUserName]\AppData\Local\VirtualStore\Program Files\PremiumSoft \Navicat 8.2 MySQL\....\....\....&quot; {width=”486”height=”223”}]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[脚本一键检测数据库以及数据库表的大小]]></title>
    <url>%2F2015%2F11%2F11%2F24%2F</url>
    <content type="text"><![CDATA[上代码:\ 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120#!/bin/bash#author: xiao白#date: 2015-11-11#qq: 530035210#blog: http://my.oschina.net/pwd/blog #查询数据库以及数据库表的大小 logdir=/data/log/shell #日志路径log=$logdir/log.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=1 #是否记录日志: 1记录 0不记录 datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho -e "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;random=$(date "+%s")getDbSize()&#123;if [[ $&#123;#dbinfo[@]&#125; -eq 0 ]];thenprint_log "$FUNCNAME():参数不能为空,退出函数"returnfidbhost=$&#123;dbinfo[0]&#125;dbuser=$&#123;dbinfo[1]&#125;dbpasswd=$&#123;dbinfo[2]&#125;dbname=$&#123;dbinfo[3]&#125;if [[ $dbname == "" ]];thendbs=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e 'show databases;' |grep -v Database &gt; /tmp/dbs_$random.txt )print_log "开始检测-&gt;数据库IP:$dbhost"print_log "数据库名:数据库大小"while read linedodb_size=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e "use information_schema ;select concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data from TABLES where table_schema='$line' \G;"|grep data |awk '&#123;print $2&#125;')echo "$line $db_size" &gt;&gt;/tmp/dbsize_$random.txtdone &lt; /tmp/dbs_$random.txtcat /tmp/dbsize_$random.txt|sort -n -k 2 -r |column -t &gt; /tmp/dbstring_$random.txtprint_log "\n`cat /tmp/dbsize_$random.txt|sort -n -k 2 -r |column -t |sed "s/^/\\t\\t\\t/"`"totalStr=$(cat /tmp/dbstring_$random.txt |grep "M" |grep -v "0.00" |awk '&#123;print $2&#125;' |sed "s/MB//g" |xargs |sed "s/ / + /g")sum=$(echo "$totalStr" |bc)print_log "[$dbhost]总数据库的大小:$sum MB"elsedb_size=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e "use information_schema ;select concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data from TABLES where table_schema='$dbname' \G;"|grep data |awk '&#123;print $2&#125;')print_log "开始检测-&gt;数据库IP:$dbhost"print_log "数据库名:数据库大小"print_log "\n\t\t\t$dbname:$db_size"firm -f /tmp/dbs_$random.txt /tmp/dbsize_$random.txt &#125;getTableSize()&#123;if [[ $&#123;#dbinfo[@]&#125; -eq 0 ]];thenprint_log "$FUNCNAME():参数不能为空,退出函数"returnfidbhost=$&#123;dbinfo[0]&#125;dbuser=$&#123;dbinfo[1]&#125;dbpasswd=$&#123;dbinfo[2]&#125;dbname=$&#123;dbinfo[3]&#125;if [[ $dbname == "" ]];thencat /tmp/dbstring_$random.txt |grep "M" |grep -v "0.00" |awk '&#123;print $1&#125;' &gt; /tmp/databases_$random.txtprint_log "排除空数据,开始检测以下数据的大小: `cat /tmp/databases_$random.txt |xargs`"dbs=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e 'show databases;' |grep -v Database &gt; /tmp/dbs_$random.txt )print_log "数据库名:数据库大小"while read linedotable_list=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e "use $line ;show tables \G ;" |grep "Tables_in" |awk '&#123;print $2&#125;')db_size=$(cat /tmp/dbstring_$random.txt |grep "M" |grep -v "0.00" |grep "^$line " |awk '&#123;print $2&#125;')print_log "数据库[$line]-&gt;数据库IP:$dbhost 数据库大小:$db_size 表的数量为:`echo "$table_list"|sed "s/ /\n/g" |wc -l`个"print_log "表名 表空间大小 表索引大小"for i in $table_listdotablename="$i"table_size=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e "use information_schema;select concat(round(sum(data_length/1024/1024),2),'MB') as data_length_MB, concat(round(sum(index_length/1024/1024),2),'MB') as index_length_MB from tables where table_schema='$line' and table_name = '$tablename' \G; " |grep "length_MB" | awk '&#123;print $2&#125;' |xargs )echo "$tablename $table_size" &gt;&gt; /tmp/$random.txtdoneprint_log "\n`cat /tmp/$random.txt|sort -n -k 2 -r |column -t|sed "s/^/\\t\\t\\t/"`"rm -f /tmp/$random.txtdone &lt; /tmp/databases_$random.txtrm -f /tmp/databases_$random.txt /tmp/dbstring_$random.txt elsetable_list=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e "use $dbname ;show tables \G ;" |grep "Tables_in" |awk '&#123;print $2&#125;')print_log "数据库[$line]-&gt;数据库IP:$dbhost 表的数量为:`echo "$table_list"|sed "s/ /\n/g" |wc -l`个"print_log "表名 表空间大小 表索引大小"for i in $table_listdotablename="$i"table_size=$(mysql -h $dbhost -u$dbuser -p"$dbpasswd" -e "use information_schema;select concat(round(sum(data_length/1024/1024),2),'MB') as data_length_MB, concat(round(sum(index_length/1024/1024),2),'MB') as index_length_MB from tables where table_schema='$dbname' and table_name = '$tablename' \G; " |grep "length_MB" | awk '&#123;print $2&#125;' |xargs )echo "$tablename $table_size" &gt;&gt; /tmp/$random.txtdoneprint_log "\n`cat /tmp/$random.txt|sort -n -k 2 -r |column -t |sed "s/^/\\t\\t\\t/"` "rm -f /tmp/$random.txt fi&#125;dbinfo=("localhost" "root" "password" "")getDbSizegetTableSize 当dbinfo第4个参数为空默认检测整个数据库的数据库以及数据库表大小:\ 当第四个参数为具体的数据库时:]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[安全运维之：Linux系统账户和登录安全]]></title>
    <url>%2F2015%2F11%2F09%2F25%2F</url>
    <content type="text"><![CDATA[一、合理使用Shell历史命令记录功能 在Linux下可通过history命令查看用户所有的历史操作记录，同时shell命令操作记录默认保存在用户目录下的.bash_history文件中，通过这个文件可以查询shell命令的执行历史，有助于运维人员进行系统审计和问题排查，同时，在服务器遭受黑客攻击后，也可以通过这个命令或文件查询黑客登录服务器所执行的历史命令操作，但是有时候黑客在入侵服务器后为了毁灭痕迹，可能会删除.bash_history文件，这就需要合理的保护或备份.bash_history文件。下面介绍下history日志文件的安全配置方法。 默认的history命令只能查看用户历史操作记录，并不能区分每个用户操作命令的时间，这点对于排查问题十分不便，不过可以通过下面的方法（加入四行内容）让history命令自动记录所有shell命令的执行时间，编辑/etc/bashrc文件： HISTFILESIZE=4000 HISTSIZE=4000 HISTTIMEFORMAT=\’%F %T\’ export HISTTIMEFORMAT HISTFILESIZE=4000 HISTSIZE=4000 HISTTIMEFORMAT=\’%F %T\’ export HISTTIMEFORMAT 其中，HISTFILESIZE定义了在.bash_history文件中保存命令的记录总数，默认值是1000，这里设置为4000；HISTSIZE定义了history命令输出的记录总数；HISTTIMEFORMAT定义时间显示格式，这里的格式与date命令后的“+\”%F%T\””是一致的；HISTTIMEFORMAT作为history的时间变量将值传递给history命令。 通过这样的设置后，执行history命令，就会显示每个历史命令的详细执行时间，例如： [root@server{.referer} ~]#history 247 2013-10-05 17:16:28 vi /etc/bashrc 248 2013-10-05 17:16:28 top 249 2013-10-05 17:04:18 vmstat 250 2013-10-05 17:04:24 ps -ef 251 2013-10-05 17:16:29 ls -al 252 2013-10-05 17:16:32 lsattr 253 2013-10-05 17:17:16 vi /etc/profile 254 2013-10-05 17:19:32 date +\”%F %T\” 255 2013-10-05 17:21:06 lsof 256 2013-10-05 17:21:21 history 为了确保服务器的安全，保留shell命令的执行历史是非常有用的一条技巧。shell虽然有历史功能，但是这个功能并非针对审计目的而设计，因此很容易被黑客篡改或是丢失。下面再介绍一种方法，可以实现详细记录登录过系统的用户、IP地址、shell命令以及详细操作时间等，并将这些信息以文件的形式保存在一个安全的地方，以供系统审计和故障排查。 将下面这段代码添加到/etc/profile文件中，即可实现上述功能。 #history USER_IP=`who -u am i 2&gt;/dev/null| awk \’{print \$NF}\’|sed -e\’s/[()]//g\’` HISTDIR=/usr/share/.history if [ -z \$USER_IP ] then USER_IP=`hostname` fi if [ ! -d \$HISTDIR ] then mkdir -p \$HISTDIR chmod 777 \$HISTDIR fi if [ ! -d \$HISTDIR/\${LOGNAME} ] then mkdir -p \$HISTDIR/\${LOGNAME} chmod 300 \$HISTDIR/\${LOGNAME} fi export HISTSIZE=4000 DT=`date +%Y%m%d_%H%M%S` export HISTFILE=\”\$HISTDIR/\${LOGNAME}/\${USER_IP}.history.\$DT\” export HISTTIMEFORMAT=\”[%Y.%m.%d %H:%M:%S]\” chmod 600 \$HISTDIR/\${LOGNAME}/*.history* 2&gt;/dev/null 这段代码将每个用户的shell命令执行历史以文件的形式保存在/usr/share/.history目录中，每个用户一个文件夹，并且文件夹下的每个文件以IP地址加shell命令操作时间的格式命名。下面是user01用户执行shell命令的历史记录文件，基本效果如下： [root@server{.referer} user01]# pwd /usr/share/.history/user01 [root@server{.referer} user01]# ls-al -rw——- 1 user01 wheel 56 Jul 6 17:07192.168.12.12.history.20130706_164512 -rw——- 1 user01 wheel 43 Jul 6 17:42192.168.12.12.history.20130706_172800 -rw——- 1 user01 wheel 22 Jul 7 12:05192.168.12.19.history.20130707_111123 -rw——- 1 user01 wheel 22 Jul 8 13:41192.168.12.20.history.20130708_120053 -rw——- 1 user01 wheel 22 Jul 1 15:28192.168.12.186.history.20130701_150941 -rw——- 1 user01 wheel 22 Jul 2 19:47192.168.12.163.history.20130702_193645 -rw——- 1 user01 wheel 22 Jul 3 12:38192.168.12.19.history.20130703_120948 -rw——- 1 user01 wheel 22 Jul 3 19:14192.168.12.134.history.20130703_183150 保存历史命令的文件夹目录要尽量隐蔽，避免被黑客发现后删除。 二、合理使用su、sudo命令 su命令是一个切换用户的工具，经常用于将普通用户切换到超级用户下，当然也可以从超级用户切换到普通用户。为了保证服务器的安全，几乎所有服务器都禁止了超级用户直接登录系统，而是通过普通用户登录系统，然后再通过su命令切换到超级用户下，执行一些需要超级权限的工作。通过su命令能够给系统管理带来一定的方便，但是也存在不安全的因素，例如系统有10个普通用户，每个用户都需要执行一些有超级权限的操作，就必须把超级用户的密码交给这10个普通用户，如果这10个用户都有超级权限，通过超级权限可以做任何事，那么会在一定程度上对系统的安全造成了威协。因此su命令在很多人都需要参与的系统管理中，并不是最好的选择，超级用户密码应该掌握在少数人手中，此时sudo命令就派上用场了。 sudo命令允许系统管理员分配给普通用户一些合理的“权利”，并且不需要普通用户知道超级用户密码，就能让他们执行一些只有超级用户或其他特许用户才能完成的任务，比如系统服务重启、编辑系统配置文件等，通过这种方式不但能减少超级用户登录次数和管理时间，也提高了系统安全性。因此，sudo命令相对于权限无限制性的su来说，还是比较安全的，所以sudo也被称为受限制的su，另外sudo也是需要事先进行授权认证的，所以也被称为授权认证的su。 sudo执行命令的流程是：将当前用户切换到超级用户下，或切换到指定的用户下，然后以超级用户或其指定切换到的用户身份执行命令，执行完成后，直接退回到当前用户，而这一切的完成要通过sudo的配置文件/etc/sudoers来进行授权。 例如，/etc/shadow文件普通用户是无法访问的： [user01@unknown{.referer} ~]\$ more/etc/shadow /etc/shadow: Permission denied 如果要让普通用户user01可访问这个文件，可以在/etc/sudoers添加如下内容： user01 ALL = /bin/more /etc/shadow 这样，通过如下方式user01用户就可访问/etc/shadow文件： [user01@unknown{.referer} ~]\$ sudomore /etc/shadow [sudo] password for user01: 执行这个命令后，需要输入user01用户的密码，然后就可访问文件内容了。在这里sudo使用时间戳文件来完成类似“检票”的系统，当用户输入密码后就获得了一张默认存活期为5分钟的“入场券”（默认值可以在编译的时候改变）。超时以后，用户必须重新输入密码才能查看文件内容。 如果每次都需要输入密码，那么某些自动调用超级权限的程序就会出现问题，此时可以通过下面的设置，让普通用户无需输入密码即可执行具有超级权限的程序。例如，要让普通用户centreon具有/etc/init.d/nagios脚本重启的权限，可以在/etc/sudoers添加如下设置： CENTREON ALL = NOPASSWD: /etc/init.d/nagios restart 这样，普通用户centreon就可以执行nagios重启的脚本而无需输入密码了。如果要让一个普通用户user02具有超级用户的所有权限，而又不想输入超级用户的密码，只需在/etc/sudoers添加如下内容即可： user02 ALL=(ALL) NOPASSWD: ALL 这样user02用户登录系统后，就可以通过执行如下命令切换到超级用户下： [user02@unknown ~]\$ sudo su - [root@unknown ~]# pwd /root sudo设计的宗旨是：赋予用户尽可能少的权限但仍允许它们完成自己的工作，这种设计兼顾了安全性和易用性，因此，强烈推荐通过sudo来管理系统账号的安全，只允许普通用户登录系统，如果这些用户需要特殊的权限，就通过配置/etc/sudoers来完成，这也是多用户系统下账号安全管理的基本方式。 三、删减系统登录欢迎信息 系统的一些欢迎信息或版本信息，虽然能给系统管理者带来一定的方便，但是这些信息有时候可能被黑客利用，成为攻击服务器的帮凶，为了保证系统的安全，可以修改或删除某些系统文件，需要修改或删除的文件有4个，分别是/etc/issue、/etc/issue.net、/etc/redhat-release和/etc/motd。 /etc/issue和/etc/issue.net文件都记录了操作系统的名称和版本号，当用户通过本地终端或本地虚拟控制台等登录系统时，/etc/issue的文件内容就会显示，当用户通过ssh或telnet等远程登录系统时，/etc/issue.net文件内容就会在登录后显示。在默认情况下/etc/issue.net文件的内容是不会在ssh登录后显示的，要显示这个信息可以修改/etc/ssh/sshd_config文件，在此文件中添加如下内容即可： Banner /etc/issue.net 其实这些登录提示很明显泄漏了系统信息，为了安全起见，建议将此文件中的内容删除或修改。 /etc/redhat-release文件也记录了操作系统的名称和版本号，为了安全起见，可以将此文件中的内容删除。 /etc/motd文件是系统的公告信息。每次用户登录后，/etc/motd文件的内容就会显示在用户的终端。通过这个文件系统管理员可以发布一些软件或硬件的升级、系统维护等通告信息，但是此文件的最大作用就、是可以发布一些警告信息，当黑客登录系统后，会发现这些警告信息，进而产生一些震慑作用。看过国外的一个报道，黑客入侵了一个服务器，而这个服务器却给出了欢迎登录的信息，因此法院不做任何裁决。]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[nginx缓存设置]]></title>
    <url>%2F2015%2F11%2F09%2F26%2F</url>
    <content type="text"><![CDATA[目的：缓存nginx服务器的静态文件。如css,js,htm,html,jpg,gif,png,flv,swf，这些文件都不是经常更新。便于缓存以减轻服务器的压力。\实现：nginxproxy_cache可以将用户的请缓存到本地一个目录，当下一个请求时可以直接调取缓存文件，就不用去后端服务器去取文件了。\配置：打开配置文件/usr/local/nginx/conf/nginx.conf user www www;\worker_processes 2;\error_log /var/log/nginx_error.log crit;\worker_rlimit_nofile 65535;\events\{\ use epoll;\ worker_connections 65535;\}\ http\{\ include mime.types;\ default_type application/octet-stream;\ server_names_hash_bucket_size 128;\ client_header_buffer_size 32k;\ large_client_header_buffers 4 32k;\ client_max_body_size 8m;\ sendfile on;\ tcp_nopush on;\ keepalive_timeout 0;\ tcp_nodelay on;\ fastcgi_connect_timeout 300;\ fastcgi_send_timeout 300;\ fastcgi_read_timeout 300;\ fastcgi_buffer_size 64k;\ fastcgi_buffers 4 64k;\ fastcgi_busy_buffers_size 128k;\ fastcgi_temp_file_write_size 128k;\[ ##cache##\ proxy_connect_timeout 5;\ proxy_read_timeout 60;\ proxy_send_timeout 5;\ proxy_buffer_size 16k;\ proxy_buffers 4 64k;\ proxy_busy_buffers_size 128k;\ proxy_temp_file_write_size 128k;\ proxy_temp_path /home/temp_dir;\ proxy_cache_path /home/cache levels=1:2 keys_zone=cache_one:200minactive=1d max_size=30g;\ ##end##]\ gzip on;\ gzip_min_length 1k;\ gzip_buffers 4 8k;\ gzip_http_version 1.1;\ gzip_types text/plain application/x-javascript text/cssapplication/xml;\ gzip_disable \”MSIE [1-6]\.\”;\ log_format access \’\$remote_addr - \$remote_user[\$time_local] \”\$request\” \’\ \’\$status \$body_bytes_sent \”\$http_referer\” \’\ \’\”\$http_user_agent\” \$http_x_forwarded_for\’;\ upstream appserver { \ server 192.168.1.251;\ }\ server {\ listen 80 default;\ server_name www.gangpao.com;\ [location ~.*\.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) {\ proxy_pass http://appserver;\ proxy_redirect off;\ proxy_set_header Host \$host;\ proxy_cache cache_one;\ proxy_cache_valid 200 302 1h;\ proxy_cache_valid 301 1d;\ proxy_cache_valid any 1m;\ expires 30d;\ }\ location ~ .*\.(php)(.*){\ proxy_pass http://appserver;\ proxy_set_header Host \$host;\ proxy_set_header X-Real-IP \$remote_addr;\ proxy_set_header X-Forwarded-For\$proxy_add_x_forwarded_for;]\ }\ access_log /usr/local/nginx/logs/www.gangpao.com.log;\ }\} 红色部分是配置缓存的参数。\说明：\1、http段设置。\ proxy_temp_path /home/temp_dir;设置临时目录\proxy_cache_path /home/cache levels=1:2 keys_zone=cache_one:200minactive=1dmax_size=30g;设置缓存目录为二级目录，共享内存区大小，非活动时间，最大容量，注意临时目录要跟缓存目录在同一个分区。\2、server段设置\请求静态文件设置。\proxy_cache cache_one;设置缓存共享内存区块，也就是keys_zone名称。\proxy_cache_valid 200 302 1h;设置http状态码为200,302缓存时间为1小时。\expires 30d;设置失期时间，为30天\请求动态文件设置。\proxy_pass http://appserver;不进行缓存，直接转到后端服务器。\测试：当客户端发起http请求时在服务器上会产一个缓存文件如\ /home/cache/0/b9/8bd841b1c44ee5b91457eb561e44eb90]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[ORACLE 数据转换为MYSQL]]></title>
    <url>%2F2015%2F11%2F06%2F27%2F</url>
    <content type="text"><![CDATA[ORACLE 数据转换为MYSQL ①将oracle数据转换为txt文本，且分割符为\’|\’ ②新建表，记得修改的表结构，因为oracle和mysql 字段有些不一致的。 参照下面表格: ③执行导入操作 load data local infile \’文件名.txt\’ into table 数据库表名 characterset utf8 fields terminated by \’|\’ ;]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[7z(p7zip)压缩软件在Linux下的安装和使用]]></title>
    <url>%2F2015%2F11%2F06%2F28%2F</url>
    <content type="text"><![CDATA[Evernote Export 7z(p7zip)压缩软件在Linux下的安装和使用 1) 简介 7z，全称7-Zip， 是一款开源软件。是目前公认的压缩比例最大的压缩解压软件。 主页：http://www.7-zip.org/ 中文主页：http://7z.sparanoid.com/ 命令行版本下载：http://7z.sparanoid.com/download.html 主要特征： # 全新的LZMA算法加大了7z格式的压缩比 # 支持格式： * 压缩 / 解压缩：7z, XZ, BZIP2, GZIP, TAR, ZIP * 仅解压缩：ARJ, CAB, CHM, CPIO, DEB, DMG, FAT, HFS, ISO, LZH, LZMA,MBR, MSI, NSIS, NTFS, RAR, RPM, UDF, VHD, WIM, XAR, Z 2）退出代码 0 ： 正常，没有错误； 1 ： 警告，没有致命的错误，例如某些文件正在被使用，没有被压缩； 2 ： 致命错误； 7 ： 命令行错误； 8 ： 没有足够的内存； 255 ： 用户停止了操作； 2) 安装 不得不说7z的压缩率真的很高，需要高压缩的同学可以关注一下，linux下的7z叫做p7zip,安装也很简单： +———————————–+———————————–+| 1 | apt-get install p7zip |+———————————–+———————————–+ 源码安装方式: wget http://sourceforge.net/projects/p7zip/files/p7zip/9.20.1/p7zip\_9.20.1\_x86\_linux\_bin.tar.bz2 tar -jxf p7zip_9.20.1_x86_linux_bin.tar.bz2 ./install.sh 2) 使用 下面说一下它的压缩命令： +———————————–+———————————–+| 1 | 7z a -t7z -r myfiles.7z myfile/* |+———————————–+———————————–+ 这里解释一下： a 添加文件或文件夹到压缩包 -t 指定压缩类型 7z -r 当然是递归了 myfiles.7z 是生成的压缩文件 myfile/* 是要压缩的目录 然后是解压命令： +———————————–+———————————–+| 1 | 7z x myfiles.7z -r -o./ |+———————————–+———————————–+ x 表示解压文件 myfiles.7z 是要解压的文件 -r 这个。。。仍然是递归 -o 指定解压目录 ./ 当前目录，可以是绝对路径]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[H3C和Cisco的无线设备自动监测和重启]]></title>
    <url>%2F2015%2F11%2F05%2F29%2F</url>
    <content type="text"><![CDATA[背景: 前一段时间公司的购置了一批企业级的无线AP,由于使用人数太多,运行一段时间后发现，无线还是经常掉线或者无法连上网络(有线不会出现这样的问题)，这时候我们会对无线设备进行重启，重启之后设备恢复正常，无线网络也恢复ok,由此萌生想用自动化的方式对无线设备进行监控和自动定期对无线设备重启来保持无线网络的稳定。 无线设备型号： H3C WA2620i-AGN 和 Cisco Aironet 1240AG 目的: 1.自动监测无线设备的运行情况，当监测到无线设备不能连接到外网或者延迟很高时,重启无线设备。 2.每天中午12:30和下午18:30 定期对无线设备进行重启 思路: 核心就是模拟手工登陆无线设备,运行相关无线设备的命令，去判断无线设备的运行情况，来实现自动监测和重启，核心方式使用shell的expect函数，为什么使用shell，而不使用其他语言比如python,是因为它能快速的完成这个功能。 上图-&gt; 自动重启无线设备图（H3C和Cisco ） 上图-&gt; 自动监测无线设备图（H3C和Cisco）–&gt;丢包正常图（模拟登陆无线设备ping外网地址，延迟正常则无需重启等动作) [Cisco] [] [[H3C**] [[**] [[\**] 上图-&gt; 自动监测无线设备图（H3C和Cisco）–&gt;丢包不正常图（模拟登陆无线设备ping外网地址，延迟不正常则需重启) [Cisco] \ [H3C] [] [] [代码如下：] 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208#!/bin/bash#author: GaoMing#date: 2015-11-02#qq: 530035210#blog: http://my.oschina.net/pwd/blog # 无线设备定期重启和自动监测 logdir=/data/log/shell #日志路径log=$logdir/log.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=1 #是否记录日志: 1记录 0不记录pingDes="223.5.5.5"#pingDes="8.8.8.8"datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;#H3C无线自动执行命令#$1:无线IP，$2:无线账号，$3:无线密码，$4:要执行的命令 runH3C()&#123; expect -c " spawn /usr/bin/telnet $1 23 set timeout -1 expect \"\*Username\*:\" send \"$2\r\" expect \"\*Password\*:\" send \"$3\r\" expect \"\*\&gt;\" send \"$4 \r\" expect \"\*\&gt;\" send \"quit\r\" expect eof "&#125;#H3c无线重启runH3cReboot()&#123; expect -c " spawn /usr/bin/telnet $1 23 set timeout -1 expect \"\*Username\*:\" send \"$2\r\" expect \"\*Password\*:\" send \"$3\r\" expect \"\*\&gt;\" send \"$4 \r\" expect \"\*\:\" send \"Y\r\" expect eof "&#125;#Cisco无线自动执行命令#$1:无线IP，$2:无线账号，$3:无线密码，$4:要执行的命令runCisco()&#123; expect -c " spawn /usr/bin/telnet $1 23 set timeout -1 expect \"\*Username\*:\" send \"$2\r\" expect \"\*Password\*:\" send \"$3\r\" expect \"\*\#\" send \"$4 \r\" expect \"\*\#\" send \"quit\r\" expect eof "&#125;#Cisco无线重启runCiscoReload()&#123; expect -c " spawn /usr/bin/telnet $1 23 set timeout -1 expect \"\*Username\*:\" send \"$2\r\" expect \"\*Password\*:\" send \"$3\r\" expect \"\*\#\" send \"$4 \r\" expect \"\*\]\" send \"\r\" expect eof "&#125;#整合H3C和Cisco无线自动执行#$1:无线设备类型 $2:无线IP，$3:无线账号，$4:无线密码，$5:要执行的命令runWirelessAction()&#123;print_log "\t-----Start-----"int=1while (( $int &lt;= $# ))doeval i=\$$intif [[ $i == "" ]];thenprint_log "$FUNCNAME():参数(第$int个)为空,退出."exitfilet "int++"doneprint_log "$FUNCNAME():检测IP($3)($2)是否存在..."pingIP=$(ping -c 3 $3 |grep "3 received" |wc -l)if [[ $pingIP -eq 0 ]];thenprint_log "$FUNCNAME():$3无线的IP不存在或者宕机了,退出当前函数."returnelseprint_log "$FUNCNAME():检测IP完成."ficase $1 in"restart") case $2 in "cisco") print_log "$FUNCNAME():开始重启无线思科设备..." reloadStr=$(runCiscoReload "$3" "$4" "$5" "$6") reloadStrResult=$(echo "$reloadStr"|grep "closed" |wc -l) if [[ $reloadStrResult -eq 1 ]];then print_log "$FUNCNAME(): IP为:$3的无线设备正在重启..." print_log "$FUNCNAME(): 设备返回的信息如下:\n\r$reloadStr" else print_log "$FUNCNAME(): IP为:$3的无线设备重启异常 \n\r return code:$reloadStrResult \n\r return Str:$reloadStr" fi print_log "$FUNCNAME():重启无线思科设备完成" ;; "h3c") print_log "$FUNCNAME():开始重启无线H3c设备..." runH3cReboot "$3" "$4" "$5" "$6" &gt; /tmp/rebootStr.txt &amp; sleep 5 rebootStr=$(cat /tmp/rebootStr.txt) rebootStrResult=$(cat /tmp/rebootStr.txt|grep "Continue" |wc -l) if [[ $rebootStrResult -eq 1 ]];then print_log "$FUNCNAME(): IP为:$3的无线设备正在重启..." print_log "$FUNCNAME(): 设备返回的信息如下:\n\r$rebootStr" else print_log "$FUNCNAME(): IP为:$3的无线设备重启异常 \n\r return code:$rebootStrResult \n\r return Str:$rebootStr" fi print_log "$FUNCNAME():重启无线H3c设备完成" ;; *) print_log "$FUNCNAME():暂不支持其他设备." ;; esac;;"run") case $2 in "cisco") print_log "$FUNCNAME():开始操作无线思科设备($3)..." print_log "$FUNCNAME():开始在该设备执行命令($6)..." runReStr=$(runCisco "$3" "$4" "$5" "$6") returnPercent=$(echo $runReStr |grep "percent" |awk -F'percent' '&#123;print $1&#125;' |awk '&#123; print $NF&#125;') print_log "$FUNCNAME():设备返回的信息如下:\n\r $runReStr" print_log "$FUNCNAME():ping包返回的成功百分比(5个包): $returnPercent%" if [[ $returnPercent -lt 50 ]];then print_log "$FUNCNAME():该无线设备的丢包率大于50%,开始重启该设备." runWirelessAction "restart" "cisco" "$3" "$4" "$5" "reload" fi print_log "$FUNCNAME():执行命令完成" ;; "h3c") print_log "$FUNCNAME():开始操作H3c设备($3)..." print_log "$FUNCNAME():开始在该设备执行命令($6)..." runReStr=$(runH3C "$3" "$4" "$5" "$6") returnPercent=$(echo "$runReStr" |grep "loss" |awk -F'.' '&#123;print $1&#125;') print_log "$FUNCNAME():ping包的丢包率(5个包):$returnPercent%" print_log "$FUNCNAME():设备返回的信息如下:\n\r $runReStr" if [[ $returnPercent -gt 50 ]];then print_log "$FUNCNAME():该无线设备的丢包率大于50%,开始重启该设备." runWirelessAction "restart" "h3c" "$3" "$4" "$5" "reboot" fi print_log "$FUNCNAME():执行命令完成" ;; esac;;*) print_log "$FUNCNAME():暂不支持其他类型无线AP或参数.";;esac&#125;#自动监测和重启#runWirelessAction "run" "cisco" "10.2.1.111" "admin" "password" "ping $pingDes"#runWirelessAction "run" "h3c" "10.2.1.112" "admin" "password" "ping $pingDes"#重启#runWirelessAction "restart" "cisco" "10.2.1.111" "admin" "password" "reload"#runWirelessAction "restart" "h3c" "10.2.1.111" "admin" "password" "reboot" [] 自动监测和定期重启直接加入crontab即可使用]]></content>
      <categories>
        <category>监控</category>
      </categories>
      <tags>
        <tag>监控</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[彻底删除微软拼音输入法这个讨厌的家伙]]></title>
    <url>%2F2015%2F09%2F24%2F30%2F</url>
    <content type="text"><![CDATA[点点点]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[zabbix自动发现和注册]]></title>
    <url>%2F2015%2F09%2F17%2F31%2F</url>
    <content type="text"><![CDATA[[在了解了《]\ 第一步Configuration &gt;&gt;Discovery&gt;&gt;Create rule，编辑网络发现规则 如上配置，zabbix每30秒会扫描10.9.7.88与10.9.32.106-107。会使用key：agent.uanme来判断客户端是否存在，并且以IP地址作为唯一性的标识。 规则属性 属性 描述 Name 规则名称，唯一 Discovery by proxy 谁执行当前发现规则:\ no proxy - zabbix server\ &lt;proxy name&gt; - 指定的proxy IP range 发现规则中的ip范围，格式如下\ 单IP: 192.168.1.33\ 一个IP段: 192.168.1.1-255\ 一个子网: 192.168.4.0/24\ 支持如下子网掩码:\ IPV4:/16 - /30\ IPV6:/112 - /128\ IP列表: 192.168.1.1-255,192.168.2.1-100,192.168.2.200,192.168.4.0/24\ 备注：1. IP列表中的IP不能重复2. 不同的发现规则里面不要包含相同的IP，否则可能会出现意想不到的问题 Delay (in sec) 规则执行完毕之后，要多久才执行下一次。 Checks 支持的checks: SSH, LDAP, SMTP, FTP, HTTP, HTTPS, POP, NNTP, IMAP, TCP, Telnet, Zabbix agent, SNMPv1 agent, SNMPv2 agent, SNMPv3 agent, ICMP ping.\ Port属性如下：\ 单个端口: 22\ 端口段: 22-45\ 端口列表: 22-45,55,60-70 Device uniqueness criteria 设备唯一标识:\ IP address - 使用IP地址作为设备唯一性标识\ Type of discovery check - 使用SNMP 或者Zabbix agent的check作为唯一标识 Enabled 是否启用当前规则 第二步Monitorning&gt;&gt;Discovery，可以看到已经发现了两台主机，ip地址作为他们的唯一标识。确保这个标识的唯一性，否则zabbix会认为他们是一台主机。 第三步目前仅仅是可以找到主机，并未自动添加到Host中，接下来完成几个步骤： 1. 加入到Linux Servers组 2.Linux link linux模板、windows linkwindows模板 3. 主机在线时长10分钟的主机添加到HOST中 4. 离线1天以上的主机从Host中移除 创建Action我们需要创建两个Action，一份正对windows，一份针对Linux。我们下面演示一下Linux服务器 Action添加主机 configuration&gt;&gt;action&gt;&gt;Eventsource（选discover）&gt;&gt;create action 首先，配置名称，以及定义消息内容，这些使用默认的即可 [Action] [条件配置] [操作] 回到HOST中，我们可以发现已经把主机加到列表里了，并且也Linux了模板以及加到了相应的组里 移除主机configuration&gt;&gt;action&gt;&gt;Eventsource（选discover）&gt;&gt;create action 首先，配置名称，以及定义消息内容，这些使用默认的即可 移除主机 [action] [条件] [动作] 移除主机我就不演示了。 通过使用discovery，zabbix能够自动完成添加到host等等一系列动作，这一切都是基于这个规则来实现的。那么如果离开这个规则，我能完成这一系列动作吗？这是肯定的，请关注下一篇文章《Activeagent自动注册》]]></content>
      <categories>
        <category>监控</category>
      </categories>
      <tags>
        <tag>监控</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[linux shell实现随机数多种方法（date,random,uuid)]]></title>
    <url>%2F2015%2F08%2F24%2F32%2F</url>
    <content type="text"><![CDATA[在日常生活中，随机数实际上经常遇到，想丢骰子，抓阄，还有抽签。呵呵，非常简单就可以实现。那么在做程序设计，真的要通过自己程序设计出随机数那还真的不简单了。现在很多都是操作系统内核会提供相应的api，这些原始参数是获取一些计算机运行原始信息，如内存，电压，物理信号等等，它的值在一个时间段可以保证是唯一的了。好了，废话我就不说了。呵呵。 shell脚本程序我们有那些获得随机数方法呢？ 一、通过时间获得随机数（date) 这个也是我们经常用到的，可以说时间是唯一的，也不会重复的，从这个里面获得同一时间的唯一值。适应所有程序里面了。 例子： 12345678910111213[chengmo@centos5 shell]$ date +%s1287764773#获得时间戳，当前到：1970-01-01 00:00:00 相隔的秒数#如果用它做随机数，相同一秒的数据是一样的。在做循环处理，多线程里面基本不能满足要求了。 [chengmo@centos5 shell]$ date +%N738710457#获得当前时间的纳秒数据，精确到亿分之一秒。#这个相当精确了，就算在多cpu，大量循环里面，同一秒里面，也很难出现相同结果，不过不同时间里面还会有大量重复碰撞 [chengmo@centos5 shell]$ date +%s%N1287764807051101270#这个可以说比较完美了，加入了时间戳，又加上了纳秒 通过上面说明，用它来做随机数的基数了，接下来我们看怎么样获得一段数据内怎么样获得随机数。 1234567891011121314151617181920212223242526#!/bin/sh #写个随机函数，调用方法random min max #在min 与 max直接获得随机整数#copyright chengmo QQ:8292669 #获得随机数返回值，shell函数里算出随机数后，更新该值function random()&#123; min=$1; max=$2-$1; num=$(date +%s+%N); ((retnum=num%max+min)); #进行求余数运算即可 echo $retnum; #这里通过echo 打印出来值，然后获得函数的，stdout就可以获得值 #还有一种返回，定义全价变量，然后函数改下内容，外面读取&#125; #得到1-10的seq数据项for i in &#123;1..10&#125;;do out=$(random 2 10000); echo $i,"2-10000",$out;done; 看看运行结果： [chengmo@centos5 shell]\$ sh testrandom.sh\ 1,2-10000,5600 2,2-10000,5295 3,2-10000,3432 4,2-10000,3148 5,2-10000,9041 6,2-10000,4290 7,2-10000,2380 8,2-10000,9009 9,2-10000,5474 10,2-10000,3664 一个循环里面，得到值各不相同。 这个是我们常用方法，适应各种语言，是一个通用算法，就算服务器不提供，某时刻相同唯一数据标记，我们也可以通过这种方法，做自己的伪随机数。下面还有更简单方法呢，不要我们自己做了。 2、通过内部系统变量(\$RANDOM) 其实，linux已经提供有个系统环境变量了，直接就是随机数，哈哈，觉得刚学习方法，是不是白费了！！ 123456[chengmo@centos5 shell]$ echo $RANDOM10918[chengmo@centos5 shell]$ echo $RANDOM10001 #连续2次访问，结果不一样，这个数据是一个小于或等于5位的整数 可能有疑问了，如果超过5位的随机数怎么得到呢？ 呵呵，加个固定10位整数，然后进行求余，跟例1一样了。接下来的例子又是我们自立更生做了。 3、通过系统内部唯一数据生成随机数（/dev/random,urandom) 我们知道dev目录下面，是linux一些默认设备，它给我们感觉就是放的是键盘，硬盘，光驱等设备的对应文件了。其实linux有些设备很特殊，有特殊用途。前面我们说到的：/dev/[udp|tcp]/host/port比较特殊吧。呵呵，有扯远了。 /dev/random设备，存储着系统当前运行的环境的实时数据。它可以看作是系统某个时候，唯一值数据，因此可以用作随机数元数据。我们可以通过文件读取方式，读得里面数据。/dev/urandom这个设备数据与random里面一样。只是，它是非阻塞的随机数发生器，读取操作不会产生阻塞。 实例： 1234567891011121314[chengmo@centos5 shell]$ head -1 /dev/urandomãÅ†ù…•KTþçanVÕã¹Û&amp;¡õ¾“ô2íùU“ žF¦_ ÿ”†mEðûUráÏ=J¯TŸA•ÌAÚRtÓ #读一行，怎么是乱码呢？其实它是通过二进制数据保存实时数据的，那么我们怎么样把它变成整型数据呢？ [chengmo@centos5 ~/shell]$ head -200 /dev/urandom | cksum1615228479 50333#由于urandom的数据是非常多，不能直接通过cat读取，这里取前200行，其实整个数据都是变化的，取多少也一样是唯一的。#cksum 将读取文件内容，生成唯一的表示整型数据，只有文件内容不变，生成结果就不会变化,与php crc函数 [chengmo@centos5 shell]$ head -200 /dev/urandom | cksum | cut -f1 -d" "484750180#cut 以” “分割，然后得到分割的第一个字段数据 得到整型数据，然后，类似一的方法就可以获得到随机数了。题外话：在程序里面，我们经常md5得到唯一值，然后是字符串的，如果想表示成整型方式，可以通过crc函数.crc是循环冗余校验，相同数据通过运算，都会得到一串整型数据。现在这种验证应用很广。详细要了解，可以参考：crc. 下面还有个方法，直接从设备读取生成好的uuid码。 4、读取linux 的uuid码 在提到这个之前，有个概念，就是什么是uuid呢？ UUID码全称是通用唯一识别码 (Universally Unique Identifier, UUID),它是一个软件建构的标准，亦为自由软件基金会 (Open Software Foundation, OSF)的组织在分布式计算环境 (Distributed Computing Environment, DCE)领域的一部份。 UUID的目的，是让分布式系统中的所有元素，都能有唯一的辨识信息，而不需要通过中央控制端来做辨识信息的指定。如此一来，每个人都可以创建不与其它人冲突的UUID。在这样的情况下，就不需考虑数据库创建时的名称重复问题。它会让网络任何一台计算机所生成的uuid码，都是互联网整个服务器网络中唯一的。它的原信息会加入硬件，时间，机器当前运行信息等等。 UUID格式是：包含32个16进位数字，以“-”连接号分为五段，形式为8-4-4-4-12的32个字符。范例；550e8400-e29b-41d4-a716-446655440000 ,所以：UUID理论上的总数为216 x 8=2128，约等于3.4 x 1038。也就是说若每奈秒产生1兆个UUID，要花100亿年才会将所有UUID用完。 其实，大家做数据库设计时候，肯定听说过，guid(全局唯一标识符)码，它其实是与uuid类似，由微软支持。这里编码，基本有操作系统内核产生。大家记得把，在windows里面，无论数据库，还是其它软件，很容易得到这个uuid编码。 linux 的uuid码 linux的uuid码也是有内核提供的，在/proc/sys/kernel/random/uuid这个文件内。其实，random目录，里面还有很多其它文件，都与生成uuid有关系的。 123456789[chengmo@centos5 ~/shell]$ cat /proc/sys/kernel/random/uuiddff68213-b700-4947-87b1-d9e640334196[chengmo@centos5 ~/shell]$ cat /proc/sys/kernel/random/uuid7b57209a-d285-4fd0-88b4-9d3162d2e1bc#连续2次读取，得到的uuid是不同的 [chengmo@centos5 ~/shell]$ cat /proc/sys/kernel/random/uuid| cksum | cut -f1 -d" "2141807556#同上方法得到随机整数 这是linux下面，几种常见活动随机数整数方法，除了第一个是不同外，其实后3个，产生随机码的伪数据来源，都与/dev/random设备有关系。只是它们各自呈现不同而已。如果你还有更多其它方法，请给我消息，与大家分享]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[批量生成secureCrt终端连接]]></title>
    <url>%2F2015%2F08%2F04%2F33%2F</url>
    <content type="text"><![CDATA[你是否在为手动连接很多服务器的终端Crt而烦恼呢？ Now 提供一个快捷的解决方法？ [1.批量创建SecureCRT的终端连接]\[①导出名称和IP的表格] ②将表格的转换为txt文件 serverlists.txt ③上传SecureCrt的模板配置文件 ④执行批量生成脚本 ⑤将该文件放到secureCrt的终端配置文件夹里面就可以看到了 终端配置文件查找图如下: 将ini文件丢到如上的文件夹即可。\ 批量创建ini文件脚本如下： 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#!/bin/bash#author: GaoMing#date: 2015-08-04#qq: 530035210#blog: http://my.oschina.net/pwd/blog #批量生成secureCrt终端连接 logdir=/data/log/shell #日志路径log=$logdir/log.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录file="serverlists.txt"iniFile="temp.ini" datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;autoCreateCrtConnect()&#123;print_log "开始读取服务器列表"、if [[ ! -f $file ]];thenprint_log "$file文件不存在"fiif [[ ! -f $iniFile ]];thenprint_log "$iniFile文件不存在"fiprint_log "开始批量生成ini文件"while read linedoname=$(echo $line |awk -F':' '&#123;print $1&#125;')ip=$(echo $line |awk -F':' '&#123;print $2&#125;'|sed 's/[ ][ ]*//g')\cp $iniFile "$name".inised -i "s/8.8.8.8/$ip/g" "$name".iniprint_log "生成$name.ini文件完成."done &lt; $fileprint_log "开始批量生成ini文件完成"&#125;autoCreateCrtConnect]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[RexDeploy-自动发布系统]]></title>
    <url>%2F2015%2F06%2F04%2F34%2F</url>
    <content type="text"><![CDATA[RexDeploy-自动发布系统一、简介RexDeploy是基于Rex开发的一个自动化发布平台。（原生是基于perl脚本构建的,这是第一版,后续会捣鼓出python版和web版本支持） 二、安装需求* Rex * DBI（perl模块） * DBD-mysql (perl模块) (运行Linux系统之上) 一键安装方法:(Centos 5.5 和Centos 6.3测试OK) unzip RexDeploy.zip cd RexDeploy/install /bin/bash install.sh 安装数据库过程省略,建立autask数据库,手工导入pre_host_zzb.sql,并按照如下提示做好配置。 配置： 进入到安装目录/data/RexDeploy ①配置远程服务器的通用账号和密码: Rexfile 其他配置项,缺省即可。 ②配置数据库配置: RexDeploy/lib/Deploy/Db/__module__.pm 其他配置请见: RexDeploy/lib/Deploy/Core/__module__.pm 采用默认即可。 三、目录层级解释tree -L 2 ├── backup (临时备份目录) ├── config (配置文件目录) │ ├── config.ini (配置常用的配置:暂未使用,后续整合) │ └── ip_lists.ini (IP分组列表) ├── configuredir (发布前的配置目录) ├── lib (模块目录) │ ├── Common (自定义公共模块) │ ├── Deploy (自定义发布模块) │ └── Rex (官放手动安装模块) ├── logs (日志目录) ├── remotecomdir (从远程服务器下载后的目录) ├── Rexfile (rex主程序入口) ├── softdir (发布前的工程目录) └── install (安装目录) ├── DBD-mysql-4.031.tar.gz ├── DBI-1.633.tar.gz └── install.sh 14 directories, 6 files 对于使用者只要关注 configuredir softdir . 四、自动发布原理图 五、数据库表字段约束和解释从以上的发布流程图也可以知道,整个发布的流程是以在数据库表中的规则为主,比如工程路径,启动脚本等。 表字段的详细介绍如下: CREATE TABLE `pre_host_zzb` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT &apos;序号&apos;, `depart_name` varchar(64) NOT NULL COMMENT &apos;分区名称&apos;, `server_name` varchar(128) DEFAULT NULL COMMENT &apos;服务器名称或域名&apos;, `groupby` varchar(128) DEFAULT NULL COMMENT &apos;分组名称&apos;, `network_ip` varchar(15) NOT NULL COMMENT &apos;内网IP&apos;, `cpu` varchar(64) DEFAULT NULL COMMENT &apos;CPU&apos;, `mem` varchar(64) DEFAULT NULL COMMENT &apos;内存&apos;, `disk` varchar(64) DEFAULT NULL COMMENT &apos;数据盘&apos;, `pro_type` varchar(64) DEFAULT &apos;&apos; COMMENT &apos;应用类型&apos;, `config_dir` varchar(164) DEFAULT &apos;&apos; COMMENT &apos;配置目录&apos;, `pro_dir` varchar(164) DEFAULT NULL COMMENT &apos;工程目录&apos;, `log_dir` varchar(164) DEFAULT NULL COMMENT &apos;日志路径&apos;, `pro_key` varchar(64) DEFAULT NULL COMMENT &apos;进程关键词&apos;, `pro_init` varchar(100) DEFAULT NULL COMMENT &apos;启动脚本&apos;, `pro_port` varchar(255) DEFAULT NULL COMMENT &apos;启动端口&apos;, `system_type` varchar(64) DEFAULT NULL COMMENT &apos;操作系统&apos;, `created_time` datetime DEFAULT NULL COMMENT &apos;创建时间&apos;, `updated_time` datetime DEFAULT NULL COMMENT &apos;更新记录的时间&apos;, `status` varchar(64) DEFAULT &apos;启用&apos; COMMENT &apos;状态&apos;, `note` varchar(128) DEFAULT NULL COMMENT &apos;备注&apos;, `mask` int(12) DEFAULT NULL COMMENT &apos;唯一标志位&apos;, `local_name` varchar(200) DEFAULT NULL COMMENT &apos;识别名称&apos;, `app_key` varchar(200) DEFAULT NULL COMMENT &apos;应用唯一关键词&apos;, `is_deloy_dir` varchar(64) DEFAULT NULL COMMENT &apos;发布目录判断&apos;, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8 上面是一台服务器的基本信息记录表,那么我着重只讲和发布相关的几个重要字段。其字段如下。 \”id\”,\”app_key\”,\”server_name\”,\”network_ip\”,\”pro_type\”,\”config_dir\”,\”pro_dir\”,\”pro_key\”,\”pro_init\”,\”local_name\”,\”is_deloy_dir\” app_key: 应用发布的唯一关键词,不能有重复,不能为空,如果为空,则不会加入到自动发布的系统里面。 pro_key: 进程关键字最好选择的唯一的关键词,在关闭应用失败的时候,会通过应用关键词去KILL应用 pro_init: 启动脚本必须是在/etc/init.d/下面的脚本,不然可能会启动失败。 is_deloy_dir: 发布目录判断 =&gt;2代表工程路径和配置路径是隔离开来的,比如:cm的工程路径为: /data/www/html 配置路径为: /data/www/ins_share =&gt;1代表 工程路径和配置路径是合在一起的比如task-dispatcher,它的工程路径为/data/www/apps/task-dispatcher,配置路径为: /data/www/apps/task-dispatcher/conf local_name: 应用发布初始目录的名字,比如 cm3系统设置的local_name为cm,且is_deloy_dir为2,那么发布的初始目录为: 工程路径:$softdir/cm 配置路径为: $configure/cm3 六、执行发布先上发布图：比如我要发布tpic3 (此次发布替换class文件) 第一步，进入到工程目录替换class 第二步，直接发布 七.自动发布系统几大功能点介绍①查看帮助 rex -T 目前暂时开发了以下的模块和功能(左边是任务模块的名称,右边是解释和示例) ②查看支持哪些系统的发布与操作 rexlist (app_key是唯一的,一个key代表一个系统) ③发布多个系统： rex deploy –k=\’atm jrdt cm3 carbiz3 cm6 carbiz6 rb3rb6\’ (以空格间隔) ④下载远程服务器数据(程序和配置)到本地: rex download –k=\’atm jrdt cm3carbiz3 cm6 carbiz6 rb3rb6\’ （如果你要下载所有关键词的系统到本地请使用: rex download–k=\’all\’） ⑤ 同步本地(远程download)的程序和配置=&gt;待发布目录 rexDeploy:Core:syncpro 执行上面的时候,自动将所有待发布的目录清空,然后将下载目录的程序同步待发布的目录中(可以设置自动同步数据到发布目录执行语句是： rex download –k=\’all\’=&gt;rex Deploy:Core:syncpro) ⑥检查数据库以及远程服务器的配置 rex check –k=\’cm6xampprobot6\’ (就是核对数据库中关于各个配置是否正确,比如远程服务器的工程目录/配置目录/启动脚本/进程等是否存在)(检查所有远程服务器的信息: rex check –k=\’all\’) ⑦批量执行命令 rex run –k=\’atm cm3 carbiz3 \’–cmd=\’uptime\’ (如查看系统的时间: rex run –k=\’all\’–cmd=\’date\’) 这是第一版,后续慢慢的改进! 我的项目地址: https://git.oschina.net/lookingdreamer/RexDeploy_v1 开箱即用 只要配置数据库配置就可以实现自动发布！ 欢迎大家拍砖!]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[MYSQL数据库常用知识整理]]></title>
    <url>%2F2015%2F06%2F01%2F35%2F</url>
    <content type="text"><![CDATA[MYSQL数据库常用知识整理 什么是MYSQL MYSQL的特性 MYSQL存储引擎的分类以及数据文件的介绍 MYSQL赋权 MYSQL备份与恢复 MYSQL的基本操作:增删查改 MYSQL的基本故障判断与处理 MYSQL的调优 MYSQL主主、主从复制的实现 MYSQL大数据备份和恢复 数据文件的损坏与修复 什么是MYSQL MySQL[是一个开放源码的小型关联式数据库管理系统，开发者为瑞典MySQLAB公司。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低，尤其是开放源码这一特点，许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。] MYSQL的特性 使用C和C++编写，并使用了多种编译器进行测试，保证源代码的可移植性。 支持AIX、BSDi、FreeBSD、HP-UX、Linux、Mac OS、NovellNetware、NetBSD、OpenBSD、OS/2Wrap、Solaris、SunOS、Windows等多种操作系统。 为多种编程语言提供了API。这些编程语言包括C、C++、C#、Delphi、Eiffel、Java、Perl、PHP、Python、Ruby和Tcl等。 支持多线程，充分利用CPU资源，支持多用户。 优化的SQL查询算法，有效地提高查询速度。 既能够作为一个单独的应用程序应用在客户端服务器网络环境中，也能够作为一个库而嵌入到其他的软件中。 提供多语言支持，常见的编码如中文的GB2312、BIG5，日文的Shift_JIS等都可以用作数据表名和数据列名。 提供TCP/IP、ODBC和JDBC等多种数据库连接途径。 提供用于管理、检查、优化数据库操作的管理工具。 可以处理拥有上千万条记录的大型数据库。 MYSQL存储引擎的分类以及数据文件的介绍 一、安装与部署、配置文件的介绍 ①安装简介 源码编译安装，请大家自己亲自动手编译安装。 (了解不同版本的区别尤其是5.5和5.6) ②配置文件说明 basedir = path 使用给定目录作为根目录(安装目录)。 character-sets-dir = path 给出存放着字符集的目录。 datadir = path 从给定目录读取数据库文件。 pid-file = filename 为mysqld程序指定一个存放进程ID的文件(仅适用于UNIX/Linux系统); Init-V脚本需要使用这个文件里的进程ID结束mysqld进程。 socket = filename 为MySQL客户程序与服务器之间的本地通信指定一个套接字文件(仅适用于UNIX/Linux系统; 默认设置一般是/var/lib/mysql/mysql.sock文件)。在Windows环境下，如果MySQL客户与服务器是通过命名管道进行通信 的，–sock选项给出的将是该命名管道的名字(默认设置是MySQL)。 lower_case_table_name = 1/0 新目录和数据表的名字是否只允许使用小写字母; 这个选项在Windows环境下的默认设置是1(只允许使用小写字母)。 mysqld程序：语言设置 character-sets-server = name 新数据库或数据表的默认字符集。为了与MySQL的早期版本保持兼容，这个字符集也可以用–default-character-set选项给出; 但这个选项已经显得有点过时了。 collation-server = name 新数据库或数据表的默认排序方式。 lanuage = name 用指定的语言显示出错信息。 mysqld程序：通信、网络、信息安全 enable-named-pipes 允许Windows 2000/XP环境下的客户和服务器使用命名管道(named pipe)进行通信。这个命名管道的默认名字是MySQL，但可以用–socket选项来改变。 local-infile [=0] 允许/禁止使用LOAD DATA LOCAL语句来处理本地文件。 myisam-recover [=opt1, opt2, …] 在启动时自动修复所有受损的MyISAM数据表。这个选项的可取值有4种:DEFAULT、BACKUP、QUICK和FORCE; 它们与myisamchk程序的同名选项作用相同。 old-passwords 使用MySQL 3.23和4.0版本中的老算法来加密mysql数据库里的密码(默认使用MySQL 4.1版本开始引入的新加密算法)。 port = n 为MySQL程序指定一个TCP/IP通信端口(通常是3306端口)。 safe-user-create 只有在mysql.user数据库表上拥有INSERT权限的用户才能使用GRANT命令; 这是一种双保险机制(此用户还必须具备GRANT权限才能执行GRANT命令)。 shared-memory 允许使用内存(shared memory)进行通信(仅适用于Windows)。 shared-memory-base-name = name 给共享内存块起一个名字(默认的名字是MySQL)。 skip-grant-tables 不使用mysql数据库里的信息来进行访问控制(警告:这将允许用户任何用户去修改任何数据库)。 skip-host-cache 不使用高速缓存区来存放主机名和IP地址的对应关系。 skip-name-resovle 不把IP地址解析为主机名; 与访问控制(mysql.user数据表)有关的检查全部通过IP地址行进。 skip-networking 只允许通过一个套接字文件(Unix/Linux系统)或通过命名管道(Windows系统)进行本地连接，不允许ICP/IP连接; 这提高了安全性，但阻断了来自网络的外部连接和所有的Java客户程序(Java客户即使在本地连接里也使用TCP/IP)。 user = name mysqld程序在启动后将在给定UNIX/Linux账户下执行; mysqld必须从root账户启动才能在启动后切换到另一个账户下执行; mysqld_safe脚本将默认使用–user=mysql选项来启动mysqld程序。 mysqld程序：内存管理、优化、查询缓存区 bulk_insert_buffer_size = n 为一次插入多条新记录的INSERT命令分配的缓存区长度(默认设置是8M)。 key_buffer_size = n 用来存放索引区块的RMA值(默认设置是8M)。 join_buffer_size = n 在参加JOIN操作的数据列没有索引时为JOIN操作分配的缓存区长度(默认设置是128K)。 max_heap_table_size = n HEAP数据表的最大长度(默认设置是16M); 超过这个长度的HEAP数据表将被存入一个临时文件而不是驻留在内存里。 max_connections = n MySQL服务器同时处理的数据库连接的最大数量(默认设置是100)。 query_cache_limit = n 允许临时存放在查询缓存区里的查询结果的最大长度(默认设置是1M)。 query_cache_size = n 查询缓存区的最大长度(默认设置是0，不开辟查询缓存区)。 query_cache_type = 0/1/2 查询缓存区的工作模式:0, 禁用查询缓存区; 1，启用查询缓存区(默认设置); 2，”按需分配”模式，只响应SELECT SQL_CACHE命令。 read_buffer_size = n 为从数据表顺序读取数据的读操作保留的缓存区的长度(默认设置是128KB); 这个选项的设置值在必要时可以用SQL命令SET SESSION read_buffer_size = n命令加以改变。 read_rnd_buffer_size = n 类似于read_buffer_size选项，但针对的是按某种特定顺序(比如使用了ORDER BY子句的查询)输出的查询结果(默认设置是256K)。 sore_buffer = n 为排序操作分配的缓存区的长度(默认设置是2M); 如果这个缓存区太小，则必须创建一个临时文件来进行排序。 table_cache = n 同时打开的数据表的数量(默认设置是64)。 tmp_table_size = n 临时HEAP数据表的最大长度(默认设置是32M); 超过这个长度的临时数据表将被转换为MyISAM数据表并存入一个临时文件。 mysqld程序：日志 log [= file] 把所有的连接以及所有的SQL命令记入日志(通用查询日志); 如果没有给出file参数，MySQL将在数据库目录里创建一个hostname.log文件作为这种日志文件(hostname是服务器的主机名)。 log-slow-queries [= file] 把执行用时超过long_query_time变量值的查询命令记入日志(慢查询日志); 如果没有给出file参数，MySQL将在数据库目录里创建一个hostname-slow.log文件作为这种日志文件(hostname是服务器主机 名)。 long_query_time = n 慢查询的执行用时上限(默认设置是10s)。 long_queries_not_using_indexs 把慢查询以及执行时没有使用索引的查询命令全都记入日志(其余同–log-slow-queries选项)。 log-bin [= filename] 把对数据进行修改的所有SQL命令(也就是INSERT、UPDATE和DELETE命令)以二进制格式记入日志(二进制变更日志，binary update log)。这种日志的文件名是filename.n或默认的hostname.n，其中n是一个6位数字的整数(日志文件按顺序编号)。 log-bin-index = filename 二进制日志功能的索引文件名。在默认情况下，这个索引文件与二进制日志文件的名字相同，但后缀名是.index而不是.nnnnnn。 max_binlog_size = n 二进制日志文件的最大长度(默认设置是1GB)。在前一个二进制日志文件里的信息量超过这个最大长度之前，MySQL服务器会自动提供一个新的二进制日志文件接续上。 binlog-do-db = dbname 只把给定数 据库里的变化情况记入二进制日志文件，其他数据库里的变化情况不记载。如果需要记载多个数据库里的变化情况，就必须在配置文件使用多个本选项来设置，每个数据库一行。 binlog-ignore-db = dbname 不把给定数据库里的变化情况记入二进制日志文件。 sync_binlog = n 每经过n次日志写操作就把日志文件写入硬盘一次(对日志信息进行一次同步)。n=1是最安全的做法，但效率最低。默认设置是n=0，意思是由操作系统来负责二进制日志文件的同步工作。 log-update [= file] 记载出错情况的日志文件名(出错日志)。这种日志功能无法禁用。如果没有给出file参数，MySQL会使用hostname.err作为种日志文件的名字。 mysqld程序：镜像(主控镜像服务器) server-id = n 给服务器分配一个独一无二的ID编号; n的取值范围是1~2的32次方启用二进制日志功能。 log-bin = name 启用二进制日志功能。这种日志的文件名是filename.n或默认的hostname.n，其中的n是一个6位数字的整数(日志文件顺序编号)。 binlog-do/ignore-db = dbname 只把给定数据库里的变化情况记入二进制日志文件/不把给定的数据库里的变化记入二进制日志文件。 mysqld程序：镜像(从属镜像服务器) +———————————–+———————————–+| server-id = n | 给服务器分配一个唯一的ID编号 |+———————————–+———————————–+| log-slave-updates | 启用从属服务器上的日志功能，使这台计算机可以用来构成一个镜像链(A || | -&gt;B-&gt;C)。 |+———————————–+———————————–+| master-host = hostname | 主控服务器的主机名或IP地址。如果从属服务器上存在mater.in || | fo文件(镜像关系定义文件)，它将忽略此选项。 |+———————————–+———————————–+| master-user = replicusername | 从属服务器用来连接主控服务器的用户名。如果从属服务器上存在mate || | r.info文件，它将忽略此选项。 |+———————————–+———————————–+| master-password = passwd | 从属服务器用来连接主控服务器的密码。如果从属服务器上存在mater || | .info文件，它将忽略此选项。 |+———————————–+———————————–+| master-port = n | 从属服务器用来连接主控服务器的TCP/IP端口(默认设置是3306 || | 端口)。 |+———————————–+———————————–+| master-connect-retry = n | 如果与主控服务器的连接没有成功，则等待n秒(s)后再进行管理方式( || | 默认设置是60s)。如果从属服务器存在mater.info文件，它 || | 将忽略此选项。 |+———————————–+———————————–+| master-ssl-xxx = xxx | 对主、从服务器之间的SSL通信进行配置。 |+———————————–+———————————–+| read-only = 0/1 | 0: || | 允许从属服务器独立地执行SQL命令(默认设置); || | || | 1: || | 从属服务器只能执行来自主控服务器的SQL命令。 |+———————————–+———————————–+| read-log-purge = 0/1 | 1: || | 把处理完的SQL命令立刻从中继日志文件里删除(默认设置); || | || | 0: || | 不把处理完的SQL命令立刻从中继日志文件里删除。 |+———————————–+———————————–+| replicate-do-table = | 与–replicate-do-table选项的含义和用法相同，但 || dbname.tablename | 数据库和数据库表名字里允许出现通配符”%” || | || | (例如: || | test%.%–对名字以”test”开头的所有数据库里的所以数据 || | 库表进行镜像处理)。 || | |+———————————–+———————————–+| replicate-do-db = name | 只对这个数据库进行镜像处理。 |+———————————–+———————————–+| replicate-ignore-table = | 不对这个数据表进行镜像处理。 || dbname.tablename | |+———————————–+———————————–+| replicate-wild-ignore-table = | 不对这些数据表进行镜像处理。 || dbn.tablen | |+———————————–+———————————–+| replicate-ignore-db = dbname | 不对这个数据库进行镜像处理。 |+———————————–+———————————–+| replicate-rewrite-db = db1name | 把主控数据库上的db1name数据库镜像处理为从属服务器上的db2 || &gt; db2name | name数据库。 |+———————————–+———————————–+| report-host = hostname | 从属服务器的主机名; || | 这项信息只与SHOW SLAVE || | HOSTS命令有关–主控服务器可以用这条命令生成一份从属服务器的 || | 名单。 |+———————————–+———————————–+| slave-compressed-protocol = 1 | 主、从服务器使用压缩格式进行通信–如果它们都支持这么做的话。 |+———————————–+———————————–+| slave-skip-errors = n1, n2, | 即使发生出错代码为n1、n2等的错误，镜像处理工作也继续进行(即不 || …或all | 管发生什么错误，镜像处理工作也继续进行)。如果配置得当，从属服务器 || | 不应该在执行 || | SQL命令时发生错误(在主控服务器上执行出错的SQL命令不会被发送 || | 到从属服务器上做镜像处理); || | 如果不使用slave-skip-errors选项，从属服务器上的镜 || | 像工作就可能因为发生错误而中断，中断后需要有人工参与才能继续进行。 |+———————————–+———————————–+ mysqld–InnoDB：基本设置、表空间文件 skip-innodb 不加载InnoDB数据表驱动程序–如果用不着InnoDB数据表，可以用这个选项节省一些内存。 innodb-file-per-table 为每一个新数据表创建一个表空间文件而不是把数据表都集中保存在中央表空间里(后者是默认设置)。该选项始见于MySQL 4.1。 innodb-open-file = n InnoDB数据表驱动程序最多可以同时打开的文件数(默认设置是300)。如果使用了innodb-file-per-table选项并且需要同时打开很多数据表的话，这个数字很可能需要加大。 innodb_data_home_dir = p InnoDB主目录，所有与InnoDB数据表有关的目录或文件路径都相对于这个路径。在默认的情况下，这个主目录就是MySQL的数据目录。 innodb_data_file_path = ts 用来容纳InnoDB为数据表的表空间: 可能涉及一个以上的文件; 每一个表空间文件的最大长度都必须以字节(B)、兆字节(MB)或千兆字节(GB)为单位给出; 表空间文件的名字必须以分号隔开; 最后一个表空间文件还可以带一个autoextend属性和一个最大长度(max:n)。例如，ibdata1:1G; ibdata2:1G:autoextend:max:2G的意思是: 表空间文件ibdata1的最大长度是1GB，ibdata2的最大长度也是1G，但允许它扩充到2GB。除文件名外，还可以用硬盘分区的设置名来定义表 空间，此时必须给表空间的最大初始长度值加上newraw关键字做后缀，给表空间的最大扩充长度值加上raw关键字做后缀(例如/dev/hdb1: 20Gnewraw或/dev/hdb1:20Graw); MySQL 4.0及更高版本的默认设置是ibdata1:10M:autoextend。 innodb_autoextend_increment = n 带有autoextend属性的表空间文件每次加大多少兆字节(默认设置是8MB)。这个属性不涉及具体的数据表文件，那些文件的增大速度相对是比较小的。 innodb_lock_wait_timeout = n 如果某个事务在等待n秒(s)后还没有获得所需要的资源，就使用ROLLBACK命令放弃这个事务。这项设置对于发现和处理未能被InnoDB数据表驱动 程序识别出来的死锁条件有着重要的意义。这个选项的默认设置是50s。 innodb_fast_shutdown 0/1 是否以最快的速度关闭InnoDB，默认设置是1，意思是不把缓存在INSERT缓存区的数据写入数据表，那些数据将在MySQL服务器下次启动时再写入 (这么做没有什么风险，因为INSERT缓存区是表空间的一个组成部分，数据不会丢失)。把这个选项设置为0反面危险，因为在计算机关闭时，InnoDB 驱动程序很可能没有足够的时间完成它的数据同步工作，操作系统也许会在它完成数据同步工作之前强行结束InnoDB，而这会导致数据不完整。 mysqld程序：InnoDB–日志 innodb_log_group_home_dir = p 用来存放InnoDB日志文件的目录路径(如ib_logfile0、ib_logfile1等)。在默认的情况下，InnoDB驱动程序将使用 MySQL数据目录作为自己保存日志文件的位置。 innodb_log_files_in_group = n 使用多少个日志文件(默认设置是2)。InnoDB数据表驱动程序将以轮转方式依次填写这些文件; 当所有的日志文件都写满以后，之后的日志信息将写入第一个日志文件的最大长度(默认设置是5MB)。这个长度必须以MB(兆字节)或GB(千兆字节)为单 位进行设置。 innodb_flush_log_at_trx_commit = 0/1/2 这个选项决定着什么时候把日志信息写入日志文件以及什么时候把这些文件物理地写(术语称为”同步”)到硬盘上。设置值0的意思是每隔一秒写一次日志并进行 同步，这可以减少硬盘写操作次数，但可能造成数据丢失; 设置值1(设置设置)的意思是在每执行完一条COMMIT命令就写一次日志并进行同步，这可以防止数据丢失，但硬盘写操作可能会很频繁; 设置值2是一般折衷的办法，即每执行完一条COMMIT命令写一次日志，每隔一秒进行一次同步。 innodb_flush_method = x InnoDB日志文件的同步办法(仅适用于UNIX/Linux系统)。这个选项的可取值有两种: fdatasync，用fsync()函数进行同步; O_DSYNC，用O_SYNC()函数进行同步。 innodb_log_archive = 1 启用InnoDB驱动程序的archive(档案)日志功能，把日志信息写入ib_arch_log_n文件。启用这种日志功能在InnoDB与 MySQL一起使用时没有多大意义(启用MySQL服务器的二进制日志功能就足够用了)。 mysqld程序–InnoDB：缓存区的设置和优化 +———————————–+———————————–+| innodb_log_buffer_pool_size = | 为InnoDB数据表及其索引而保留的RAM内存量(默认设置是8MB || n | )。这个参数对速度有着相当大的影响，如果计算机上只运行有 || | || | MySQL/InnoDB数据库服务器，就应该把全部内存的80%用于 || | 这个用途。 || | |+———————————–+———————————–+| innodb_log_buffer_size = n | 事务日志文件写操作缓存区的最大长度(默认设置是1MB)。 |+———————————–+———————————–+| innodb_additional_men_pool_si | 为用于内部管理的各种数据结构分配的缓存区最大长度(默认设置是1MB || ze | )。 || = n | |+———————————–+———————————–+| innodb_file_io_threads = n | I/O操作(硬盘写操作)的最大线程个数(默认设置是4)。 |+———————————–+———————————–+| innodb_thread_concurrency = n | InnoDB驱动程序能够同时使用的最大线程个数(默认设置是8)。 |+———————————–+———————————–+ mysqld程序：其它选项 bind-address = ipaddr MySQL服务器的IP地址。如果MySQL服务器所在的计算机有多个IP地址，这个选项将非常重要。 default-storage-engine = type 新数据表的默认数据表类型(默认设置是MyISAM)。这项设置还可以通过–default-table-type选项来设置。 default-timezone = name 为MySQL服务器设置一个地理时区(如果它与本地计算机的地理时区不一样)。 ft_min_word_len = n 全文索引的最小单词长度工。这个选项的默认设置是4，意思是在创建全文索引时不考虑那些由3个或更少的字符构建单词。 Max-allowed-packet = n 客户与服务器之间交换的数据包的最大长度，这个数字至少应该大于客户程序将要处理的最大BLOB块的长度。这个选项的默认设置是1MB。 Sql-mode = model1, mode2, … MySQL将运行在哪一种SQL模式下。这个选项的作用是让MySQL与其他的数据库系统保持最大程度的兼容。这个选项的可取值包括ansi、db2、 oracle、no_zero_date、pipes_as_concat。 \ \ ③启动脚本 \ \ 二、MYSQL存储引擎的分类: MYISAM INNODB \ [myISAM：这个是默认类型，它是基于传统的ISAM类型，ISAM是IndexedSequential Access Method (有索引的顺序访问方法)的缩写，它是存储记录和文件的标准方法。与其他存储引擎比较，MyISAM具有检查和修复表格的大多数工具。MyISAM表格可以被压缩，而且它们支持全文搜索。它们不是事务安全的，而且也不支持外键。如果事物回滚将造成不完全回滚，不具有原子性。如果执行大量的]SELECT，MyISAM是更好的选择。 MyIASM是IASM表的新版本，有如下扩展： 二进制层次的可移植性。 NULL列索引。 对变长行比ISAM表有更少的碎片。 支持大文件。 更好的索引压缩。 更好的键吗统计分布。 更好和更快的auto_increment处理。 [InnoDB：这种类型是事务安全的。它与BDB类型具有相同的特性，它们还支持外键。InnoDB表格速度很快，具有比BDB还丰富的特性，因此如果需要一个事务安全的存储引擎，建议使用它。如果你的数据执行大量的]INSERT或UPDATE，出于性能方面的考虑，应该使用InnoDB表。对于支持事物的InnoDB类型的表，影响速度的主要原因是AUTOCOMMIT默认设置是打开的，而且程序没有显式调用BEGIN开始事务，导致每插入一条都自动Commit，严重影响了速度。可以在执行sql前调用begin，多条sql形成一个事物(即使autocommit打开也可以)，将大大提高性能。 具体可以看看下表： +———————-+———————-+———————-+| \ | MyISAM | InnoDB |+———————-+———————-+———————-+| 构成上区别 | 每个MyISAM在磁盘上存储成三个文件。 | 基于磁盘的资源是InnoDB表空间数据文 || | 文件名为表名，扩展名为文件类型。 | 件和它的日志文件，InnoDB || | | || | | 表的大小只受限于操作系统文件的大小，一般 || | .frm | 为 || | 文件存储表定义；\ | 2GB || | .MYD(MYData) | || | 数据文件的扩展名；\ | || | .MYI(MYIndex) | || | 索引文件的扩展名。 | |+———————-+———————-+———————-+| 事务处理方面 | MyISAM类型的表强调的是性能，其执行 | InnoDB提供事务支持事务，外 || | 速度比InnoDB类型更快，但是不提供事 | 部键等高级数据库功能。 || | 务支持。 | |+———————-+———————-+———————-+| 锁 | 表级锁 | 行级锁 || | | || | | InnoDB表的行锁也不是绝对的，如果在 || | | 执行一个SQL语句时MySQL不能确定要 || | | 扫描的范围，InnoDB表同样会锁全表， || | | 例如update || | | table set num=1 || | | where name like || | | “%aaa%” |+———————-+———————-+———————-+| select、insert、upda | 如果执行大量的 | 1.如果你的数据执行大量的INSERT或 || te、delete操作 | SELECT，MyISAM | UPDATE，出于性能方面的考虑，应该使 || | 是更好的选择。 | 用InnoDB表。 || | | || | | 2.DELETE FROM || | | table时，InnoDB不会重新建立表 || | | ，而是一行一行的删除。 || | | || | | || | | 3.LOAD TABLE FROM || | | MASTER操作对InnoDB是不起作用 || | | 的，解决方法是首先把InnoDB表改成M || | | yISAM表，导入数据后再改成InnoD || | | B表，但是对于使用的额外的InnoDB特 || | | 性（例如外键）的表不适用。 |+———————-+———————-+———————-+| 对于AUTO_INCREMENT类 | 必须包含只有该字段的索引 | 可以和其他字段一起建立联合索引 || 型的字段 | | |+———————-+———————-+———————-+| \ | \ | InnoDB不支持FULLTEXT类型的 || | | 索引。 |+———————-+———————-+———————-+| \ | MyISAM类型的二进制数据文件可以在不 | \ || | 同操作系统中迁移 | |+———————-+———————-+———————-+ 以下是一些细节和具体实现的差别： InnoDB不支持FULLTEXT类型的索引。 InnoDB 中不保存表的具体行数，也就是说，执行select count(*) fromtable时，InnoDB要扫描一遍整个表来计算有多少行，但是MyISAM只要简单的读出保存好的行数即可。注意的是，当count(*)语句包含where条件时，两种表的操作是一样的。 对于AUTO_INCREMENT类型的字段，InnoDB中必须包含只有该字段的索引，但是在MyISAM表中，可以和其他字段一起建立联合索引。 DELETE FROM table时，InnoDB不会重新建立表，而是一行一行的删除。 LOAD TABLE FROMMASTER操作对InnoDB是不起作用的，解决方法是首先把InnoDB表改成MyISAM表，导入数据后再改成InnoDB表，但是对于使用的额外的InnoDB特性（例如外键）的表不适用。 综上所述，任何一种表都不是万能的，只有恰当的针对业务类型来选择合适的表类型，才能最大的发挥MySQL的性能优势。 二、MYSQL数据文件的介绍 一、MySQL数据库文件介绍 MySQL的每个数据库都对应存放在一个与数据库同名的文件夹中，MySQL数据库文件包括MySQL所建数据库文件和MySQL所用存储引擎创建的数据库文件。 1、MySQL创建并管理的数据库文件： .frm文件：存储数据表的框架结构，文件名与表名相同，每个表对应一个同名frm文件，与操作系统和存储引擎无关，即不管MySQL运行在何种操作系统上，使用何种存储引擎，都有这个文件。 除了必有的.frm文件，根据MySQL所使用的存储引擎的不同（MySQL常用的两个存储引擎是MyISAM和InnoDB），存储引擎会创建各自不同的数据库文件。 2、MyISAM数据库表文件： .MYD文件：即MY Data，表数据文件 .MYI文件：即MY Index，索引文件 .log文件：日志文件 3、InnoDB采用表空间（tablespace）来管理数据，存储表数据和索引， InnoDB数据库文件（即InnoDB文件集，ib-file set）： ibdata1、ibdata2等：系统表空间文件，存储InnoDB系统信息和用户数据库表数据和索引，所有表共用 .ibd文件：单表表空间文件，每个表使用一个表空间文件（file pertable），存放用户数据库表数据和索引 日志文件： ib_logfile1、ib_logfile2 二、MySQL数据库存放位置： 1、MySQL如果使用MyISAM存储引擎，数据库文件类型就包括.frm、.MYD、.MYI，默认存放位置是C:\DocumentsandSettings\All Users\Application Data\MySQL\MySQL Server 5.1\data 2、MySQL如果使用InnoDB存储引擎，数据库文件类型就包括.frm、ibdata1、.ibd，存放位置有两个， .frm文件默认存放位置是C:\Documents and Settings\AllUsers\ApplicationData\MySQL\MySQL Server5.1\data，ibdata1、.ibd文件默认存放位置是MySQL安装目录下的data文件夹 \ \ 三、MYSQL赋权 \ #给用户cacti赋予所有库的所有权限\GRANT ALL PRIVILEGES ON *.* TO \’cacti\’@\’%\’ IDENTIFIED BY \’cacti\’WITH GRANT OPTION;\#重新载入赋权表\FLUSH PRIVILEGES;\ #收回权限(不包含赋权权限)\REVOKE ALL PRIVILEGES ON *.* FROM cacti;\REVOKE ALL PRIVILEGES ON cacti.* FROM cacti;\#收回赋权权限\REVOKE GRANT OPTION ON *.* FROM cacti;\#重新载入赋权表\FLUSH PRIVILEGES; #查看赋权权限 show grants for \’cacti\’@\’%\’ \ 四、MYSQL备份与恢复 \ \ [一：实验环境介绍：]\ [系统介绍：CentOS6.4_X64] [数据库版本：mysql-5.5.33] [\] [二：基于Mysqldump命令实现备份恢复] [2.1] [[ Mysqldump] [ Mysqldump] [2.2] [Mysqldump] [2.3] [（1）Mysqldump全备] [ 由于Mysql数据库默认的为MyISAM存储引擎所以只有使用温备（备份同时仅支持读请求）进行，所以我们要为所有数据库添加读锁] +———————————–+———————————–+| 1 | [root@stu18 ~] || | #mysqldump -uroot -pmypass - | | | -lock-all-tables --master-data=2 | | | --events --routines--all-database | | | s &gt; /zhao/database_`date +%F`.sql | | | |+———————————–+———————————–+ [ 解析：–lock-all-tables表示为所有表施加读锁；–master-data=2表示在备份文件中记录当前二进制日志的位置；–events表示备份数据的同时备份时间调度器代码；–routines表示备份数据的同时备份存储过程和存储函数；–all-databases表示备份所有库。] +———————————–+———————————–+| 1 | [root@stu18 zhao] || | # less database_2013-08-13.sql | | 2 | || | || 3 | -- || | #表示注释项 || 4 | || | -- Position to start replication | | 5 | or point- || | in || 6 | - time || | recovery from || 7 | || | -- || 8 | || | -- CHANGE MASTER TO MASTER_LOG_F | | 9 | ILE= || | || | &#39;mysql-bin.000001&#39; || | || | , MASTER_LOG_POS=14203; || | || | #这里表示当前处于mysql-bin.000001这个二进制 | | | 日志中，事件为14203这是通过--master-data=2产生 | | | 的 || | || | -- || | || | -- Current Database: `hellodb` | | | || | || | -- || | || | CREATE DATABASE /*!32312 IF NO | | | T EXISTS*/ `hellodb` /*!40100 DEF | | | AULT CHARACTER SET utf8 */; |+———————————–+———————————–+ [（2）二进制全备] [ 方法一： 导出二进制日志文件内容] +———————————–+———————————–+| 1 | [root@stu18 data] || | ` # mysqlbinlog mysql-bin.0000 | | | 01 &gt;/zhao/binlog_date +%F.sql || | ` |+———————————–+———————————–+ [ 方法二：滚动日志复制文件]\ +———————————–+———————————–+| 1 | mysql&gt; flush logs; | | | || 2 | #滚动日志 || | || | [root@stu18 data] || | # cp mysql-bin.000001 /zhao/my | | | sql-bin.000001 #复制导出二进制文件 |+———————————–+———————————–+ [（3）二进制增备] [ 首先添加数据信息] +———————————–+———————————–+| 1 | mysql&gt; use hellodb; || | || 2 | mysql&gt; INSERT INTO students(Name | | | ,Age,Gender,ClassID,TeacherID) va | | | lues ( || | &#39;Yang kang&#39; || | ,22, || | &#39;M&#39; ,3,3); |+———————————–+———————————–+ [ 然后二进制增备] +———————————–+———————————–+| 1 | [root@stu18 data] || | # mysqlbinlog --start-positi | | | on=14203 --stop-position=14527 my | | | sql-bin.000001 &gt; /zhao/binlog_`da | | | te +%F_%H`.sql |+———————————–+———————————–+ [ 解析：–start-position=14203是上次全备之后的二进制事件位置；–stop-position=14527最近一天的二进制事件位置。] [2.4、] +———————————–+———————————–+| 1 | mysql&gt; DROP DATABASE hellodb; | | | || 2 | #删除数据库 || | || 3 | ############下面这些过程要在离线状态下执行##### | | | ####### || 4 | || | mysql&gt; SET sql_log_bin=0; | | 5 | || | #先关闭二进制日志 || 6 | || | mysql&gt; flush logs; | | 7 | || | #滚动日志 || 8 | || | [root@stu18 ~] || | # mysql -uroot -pmypass &lt; /zha | | | o/database_2013-08-13.sql #导入数据库 | | | 备份文件 || | || | [root@stu18 ~] || | # mysql -uroot -pmypass &lt; /zha | | | o/binlog_2013-08-13_19.sql #导入增量备 | | | 份文件 || | || | [root@stu18 ~] || | # mysql -uroot –pmypass #登录 | | | 查看，恢复完成 || | || | mysql&gt; SET sql_log_bin=1; | | | || | #开启二进制日志 |+———————————–+———————————–+ [ 这种备份方式恢复简单，但是恢复还原之后索引会出现错误需要重建，而且备份结果会占据很大的空间，请酌情使用。] [三、基于LVM快照实现备份恢复] [3.1] [（1）LVM这种备份方式要求Mysql的数据保存在逻辑卷上] [（2）需要给Mysql服务器施加读锁（mysql&gt;FLUSH TABLES WITHREADLOCK;），这里不可直接退出服务器] [（3）另起终端为数据所在的卷创建快照（lvcreate），保证事务日志和数据文件必须在同一卷上（分别创建可能会导致数据文件和事务日志不一致，从而可能导致无法正常恢复）] [3.2] [ LVM] [3.3] [[ （1）创建逻辑卷及挂载逻辑卷，此过程在此就不做演示了可参考博文] [[http://pangge.blog.51cto.com/6013757/1256568] [ （2）] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # cd /usr/local/mysql/ || 2 | || | [root@stu18 mysql] || | || | # scripts/mysql_install_db --u | | | ser=mysql --datadir=/mydata/data |+———————————–+———————————–+ [ （3）编辑查看配置文件，重启服务] +———————————–+———————————–+| 1 | [root@stu18 mysql] || | # vim /etc/my.cnf || 2 | || | datadir = || 3 | /mydata/data || | || 4 | #查看此项是否定义数据目录位置 || | || | sync_binlog=1 || | || | || | #添加此项，每个事务提交时候，把事务日志从缓存区写到日志文件 | | | 中，并且刷新日志文件的数据到磁盘上； || | || | || | [root@stu18 mysql] || | # service mysqld start |+———————————–+———————————–+ [3.4、过程展示] [ （1）确保事务日志和数据文件必须在同一卷上] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # ls /mydata/data/ || 2 | || | hellodb myclass m | | 3 | ysql-bin.000003 stu18.magedu.c | | | om.err || 4 | || | ibdata1 mysql m | | 5 | ysql-bin.000004 stu18.magedu.c | | | om.pid || | || | ib_logfile0 mysql-bin.000001 m | | | ysql-bin.index student || | || | ib_logfile1 mysql-bin.000002 p | | | erformance_schema || | test |+———————————–+———————————–+ [ 解析：其中ib_logfile0与ib_logfile1是日志文件]\ [ （2）施加全局锁并滚动日志] +———————————–+———————————–+| 1 | mysql&gt; FLUSH TABLES WITH READ LO | | | CK; || 2 | || | mysql&gt; FLUSH LOGS; |+———————————–+———————————–+ [ （3）查看并保存当前正在使用的二进制日志及当前执行二进制日志位置（非常重要）] +———————————–+———————————–+| 1 | mysql&gt; SHOW MASTER STATUS; || | || 2 | +------------------+----------+- | | | -------------+------------------+ | | 3 | || | || 4 | | File | Position | | | | Binlog_Do_DB | Binlog_Ignore_DB | | | 5 | || | || 6 | +------------------+----------+- | | | -------------+------------------+ | | 7 | || | || | | mysql-bin.000004 | 187 | | | | | | | | | || | || | +------------------+----------+- | | | -------------+------------------+ | | | || | || | [root@stu18 zhao] || | # mysql -uroot -pmypass -e &#39;SH | | | OW MASTER STATUS;&#39; &gt;/zhao/lvmback | | | -2013-08-14/binlog.txt |+———————————–+———————————–+ [ （4）创建快照卷] +———————————–+———————————–+| 1 | [root@stu18 zhao] || | # lvcreate -L 100M -s -p r -n | | | mydata-lvm /dev/vg1/mydata |+———————————–+———————————–+ [ （5）立即切换终端释放锁] +———————————–+———————————–+| 1 | mysql&gt; UNLOCK TABLES; |+———————————–+———————————–+ [ （6）备份数据] +———————————–+———————————–+| 1 | [root@stu18 data] || | # cp -a * /zhao/lvmback-2013-0 | | | 8-14/ |+———————————–+———————————–+ [ （7）二进制实现增量备份] +———————————–+———————————–+| 1 | mysql&gt; use hellodb; || | || 2 | #指定默认数据库 || | || 3 | Database changed || | || 4 | mysql&gt; CREATE TABLE testtb ( || | id || 5 | int,name CHAR(10)); || | #创建表 || 6 | || | Query OK, 0 rows affected (0.35 | | 7 | sec) || | || | mysql&gt; INSERT INTO testtb VALUES | | | (1, || | &#39;tom&#39; || | ); || | #添加数据 || | || | Query OK, 1 row affected (0.09 s | | | ec) || | || | [root@stu18 data] || | # mysqlbinlog --start-position | | | =187 mysql-bin.000004 &gt; /zhao/lvm | | | logbin_2013-08-14/binlog.sql | | | #日志实现增量备份 |+———————————–+———————————–+ [ （8）模拟数据库崩溃] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # service mysqld stop || 2 | || | [root@stu18 ~] || 3 | # cd /mydata/data/ || | || | [root@stu18 data] || | # rm -rf * |+———————————–+———————————–+ [ （9）恢复数据] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # cp /zhao/lvmback-2013-08-14/ | | 2 | * /mydata/data/ -a #完全备份 | | | 恢复 || 3 | || | [root@stu18 ~] || 4 | # cd /mydata/data/ | | | #查看恢复数据内容 || 5 | || | [root@stu18 data] || 6 | # chown -R mysql.mysql * #更 | | | 改属主属组 || 7 | || | [root@stu18 data] || 8 | # service mysqld start #启 | | | 动服务 || 9 | || | [root@stu18 data] || 10 | # mysql -uroot –pmypass #登录 | | | 测试 || 11 | || | mysql&gt; SHOW DATABASES; || 12 | || | #查看数据完整性，无测试表testtd使用二进制恢复 || 13 | || | || 14 | mysql&gt; SET sql_log_bin=0 || | #关闭二进制日志 || 15 | || | mysql&gt; || 16 | source || | /zhao/lvmlogbin_2013-08-14/bin | | 17 | log || | .sql; || 18 | #二进制恢复 || | || 19 | mysql&gt; SHOW TABLES; || | #查看恢复结果 || 20 | || | +-------------------+ || 21 | || | | Tables_in_hellodb | || 22 | || | +-------------------+ || | || | | classes | || | || | | coc | || | || | | courses | || | || | | scores | || | || | | students | || | || | | teachers | || | || | | testtb | || | || | | toc | || | || | +-------------------+ || | || | mysql&gt; SET sql_log_bin=1; || | #开启二进制日志 |+———————————–+———————————–+ [\] [此工具是接近于热备的方式实现的，并且用此方法来备份恢复数据速度是非常快的。] [四:基于xtrabackup来实现备份恢复] [4] [ 完全以热备的形式进行，能够实现快速可靠地完全备份和部分备份，支持增量备份，支持时间点还原，备份过程中不会打扰到事务操作，能够实现网络传输和压缩功能从而有效的节约磁盘空间，备份完成后可自动验证数据是否可用，恢复速度较快等等。更多优势特性请参考http://www.percona.com/software/percona-xtrabackup] [注意：以上这些优势特性只能在InnoDB引擎上完美实现，而在MyISAM存储引擎上依然最多只能使用温备的形式进行并且还不支持增量备份。] [另外Xtrabackup更多的高级功能还依赖于Mysql数据库对于InnoDB实现了单独的表空间，否则也就没有办法实现单表导入导出查看方式如下：] +———————————–+———————————–+| 1 | mysql&gt; SHOW GLOBAL VARIABLES LIK | | | E || 2 | &#39;innodb_file%&#39; || | ; || 3 | || | +--------------------------+---- | | 4 | ------+ || | || 5 | | Variable_name | Val | | | ue | || 6 | || | +--------------------------+---- | | 7 | ------+ || | || 8 | | innodb_file_format | Ant | | | elope | || 9 | || | | innodb_file_format_check | ON | | | | || | || | | innodb_file_format_max | Ant | | | elope | || | || | | innodb_file_per_table | ON | | | | || | || | +--------------------------+---- | | | ------+ |+———————————–+———————————–+ [ 其中的innodb_file_per_table为ON则表示实现了单表单空间。若为OFF则需要使用mysqldump全备然后更改配置文件删除原来的数据文件并重新初始化服务器最后将数据重新导入。所以建议以后在安装Mysql服务器时将其选项默认设置成1即可（innodb_file_per_table= 1）。单表单空间的数据显示形式为：] +———————————–+———————————–+| 1 | [root@stu18 hellodb] || | # ls || 2 | || | classes.frm coc.MYD course | | 3 | s.MYI scores.MYI teachers.frm | | | testtb.ibd || 4 | || | classes.MYD coc.MYI db.opt | | 5 | students.frm teachers.MYD | | | toc.frm || | || | classes.MYI courses.frm scores | | | .frm students.MYD teachers.MYI | | | toc.MYD || | || | coc.frm courses.MYD scores | | | .MYD students.MYI testtb.frm | | | toc.MYI |+———————————–+———————————–+ [4.2、安装Xtrabackup] [ 下载percona-xtrabackup最新的版本为2.1.4（percona-xtrabackup-2.1.4-656.rhel6.x86_64.rpm）] [ 安装：] +———————————–+———————————–+| 1 | [root@stu18 ~]# rpm -ivh percona | | | -xtrabackup- || | 2.1 || | . 4 || | - 656 || | .rhel6.x86_64.rpm |+———————————–+———————————–+ 若有错误无法安装请安装perl-DBD-mysql依赖包 +———————————–+———————————–+| 1 | [root@stu18 ~]# yum -y install p | | | erl-DBD-mysql |+———————————–+———————————–+ [注意：不同的环境依赖的关系包可能有多个，请依照提示进行配置] [4.3] [ 使用innobakupex备份时，其会调用xtrabackup备份所有的InnoDB表，复制所有关于表结构定义的相关文件(.frm)、以及MyISAM、MERGE、CSV和ARCHIVE表的相关文件，同时还会备份触发器和数据库配置信息相关的文件。这些文件会被保存至一个以时间命令的目录中。完全备份] +———————————–+———————————–+| 1 | # innobackupex --user=DBUSER--pa | | | ssword=DBUSERPASS /path/to/BACKUP | | | -DIR/ |+———————————–+———————————–+ [ 实现过程及说明：] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # mkdir /innobackup | | 2 | #创建备份文件目录 || | || 3 | [root@stu18 ~] || | # innobackupex --user=root --p | | 4 | assword=mypass /innobackup/ #完 | | | 全备份 || 5 | || | ################如果执行正确其后输出的几行信息通 | | 6 | 常如下############### || | || 7 | xtrabackup: Transaction log of l | | | sn (1604655) to (1604655) was cop | | 8 | ied. || | || 9 | #二进制日志的位置（lsn） || | || | 130814 07:04:55 innobackupex: A | | | ll tables unlocked || | || | innobackupex: Backup created || | in || | directory || | &#39;/innobackup/2013-08-14_07-04- | | | 49&#39; || | || | #备份文件保存的位置 || | || | innobackupex: MySQL binlog posit | | | ion: filename || | || | &#39;mysql-bin.000003&#39; || | , position 538898 || | || | 130814 07:04:55 innobackupex: C | | | onnection to database server clos | | | ed || | || | 130814 07:04:55 innobackupex: c | | | ompleted OK! 备份完成 |+———————————–+———————————–+ [ 切换至备份文件目录查看备份的数据信息及创建生成的文件：] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # cd /innobackup/2013-08-14_07 | | 2 | -04-49/ || | || 3 | [root@stu18 2013-08-14_07-04-49] | | | || 4 | # ls || | || 5 | backup-my.cnf myclass | | | student xtrabackup_ | | | binlog_info || | || | hellodb mysql | | | || | || | test || | xtrabackup_checkpoints || | || | ibdata1 performance_schem | | | a xtrabackup_binary xtrabackup_ | | | logfile |+———————————–+———————————–+ [ 针对文件解析：] [ (1)xtrabackup_checkpoints ——备份类型（如完全或增量）、备份状态（如是否已经为prepared状态）和LSN(日志序列号)范围信息；] [每个InnoDB页(通常为16k大小)都会包含一个日志序列号，即LSN。LSN是整个数据库系统的系统版本号，每个页面相关的LSN能够表明此页面最近是如何发生改变的。] [ (2)xtrabackup_binlog_info ][——mysql服务器当前正在使用的二进制日志文件及至备份这一刻为止二进制日志事件的位置。] [ (3)xtrabackup_binary ][——备份中用到的xtrabackup的可执行文件；] [ (4)backup-my.cnf ][——备份时用到的配置选项信息，也就是配置文件中关于mysqld的相关文件配置；] [ (5) xtrabackup_logfile ][——非文本文件是xtrabackup本身的日志文件；] [4.4、准备一个完全备份] [一般情况下，在备份完成后，数据尚且不能用于恢复操作，因为备份的数据中可能会包含尚未提交的事务或已经提交但尚未同步至数据文件中的事务。因此，此时数据文件仍处于不一致状态。“准备”的主要作用正是通过回滚未提交的事务及同步已经提交的事务至数据文件从而使得数据文件处于一致性状态。] [ innobakupex] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex -apply-log /inn | | 2 | obackup/2013-08-14_07-04-49/ || | || 3 | #############如果执行正确，其最后输出的几行信息通常 | | | 如下################ || 4 | || | xtrabackup: starting || 5 | shutdown || | with innodb_fast_shutdown = 1 || 6 | || | 130814 7:39:33 InnoDB: Startin | | | g || | shutdown || | ... || | || | 130814 7:39:37 InnoDB: Shutdow | | | n completed; log sequence number | | | 1606156 || | || | 130814 07:39:37 innobackupex: c | | | ompleted OK! |+———————————–+———————————–+ [4.5、模拟数据库崩溃实现完全恢复] [ （1）模拟崩溃] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # service mysqld stop || 2 | || | [root@stu18 ~] || 3 | # cd /mydata/data/ || | || | [root@stu18 data] || | # rm -rf * |+———————————–+———————————–+ [（2）从完全备份中恢复数据]\ [ innobackupex] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex --copy-back /in | | 2 | nobackup/2013-08-14_07-04-49/ || | || 3 | #############如果执行正确，其最后输出的几行信息通常 | | | 如下################ || 4 | || | innobackupex: Starting to copy I | | 5 | nnoDB log files || | || 6 | innobackupex: || | in || 7 | &#39;/innobackup/2013-08-14_07-04- | | | 49&#39; || 8 | || | innobackupex: back to original I | | 9 | nnoDB log directory || | &#39;/mydata/data&#39; || | || | innobackupex: Copying || | || | &#39;/innobackup/2013-08-14_07-04- | | | 49/ib_logfile0&#39; || | to || | &#39;/mydata/data&#39; || | || | innobackupex: Copying || | || | &#39;/innobackup/2013-08-14_07-04- | | | 49/ib_logfile1&#39; || | to || | &#39;/mydata/data&#39; || | || | innobackupex: Finished copying b | | | ack files. || | || | 130814 07:58:22 innobackupex: c | | | ompleted OK! |+———————————–+———————————–+ [（3）当数据恢复至数据目录以后，还需要确保所有数据文件的属主和属组均为正确的用户，如mysql，否则，在启动mysqld之前还需要事先修改数据文件的属主和属组。] +———————————–+———————————–+| 1 | # chown -R mysql:mysql /mydata/ | | | data/ |+———————————–+———————————–+ [（4）启动服务器登陆查看恢复完成。]\ +———————————–+———————————–+| 1 | [root@stu18 data] || | # service mysqld start |+———————————–+———————————–+ [注意：每一次恢复完成之后一定要重新做一次完全备份工作！！] [4.6、使用innobackupex进行增量备份] [ 说明：每个InnoDB的页面都会包含一个LSN信息，每当相关的数据发生改变，相关的页面的LSN就会自动增长。这正是InnoDB表可以进行增量备份的基础，即innobackupex通过备份上次完全备份之后发生改变的页面来实现。] [[第一次改动数据实现增量备份] [实现增量备份可以使用下面的命令进行：] +———————————–+———————————–+| 1 | [root@stu18 data] || | # innobackupex --user=root --p | | | assword=mypass --incremental /inn | | | obackup --incremental-basedir=/in | | | nobackup/2013-08-14_08-14-12/ |+———————————–+———————————–+ [其中，/innobackup指的是完全备份所在的目录，此命令执行结束后，innobackupex命令会在/backup目录中创建一个新的以时间命名的目录以存放所有的增量备份数据。–incremental-basedir是指向上一次完全备份所在的目录。] [[第二次改动数据进行增量备份] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex --user=root --p | | | assword=mypass --incremental /inn | | | obackup --incremental-basedir=/in | | | nobackup/2013-08-14_08-29-05/ |+———————————–+———————————–+ [ 第二次增量备份的执行命令和第一次大致相同，只有其–incremental-basedir应该指向上一次的增量备份所在的目录。] [第三次改动数据还未进行增量备份] +———————————–+———————————–+| 1 | mysql&gt; delete from coc where || | id || | =14; |+———————————–+———————————–+ [4.7、使用innobackupex基于完全+增量+二进制日志恢复数据] [ （1）由于笔者这里将二进制日志和数据文件写在了同一个文件目录下所以在模拟数据库崩溃前必须先复制出二进制日志文件，所以[建议看客们将数据目录和二进制目录分开存放] [[前提是在刚刚建立服务器尚未启动服务器之前做如下操作] +———————————–+———————————–+| 1 | mkdir || | /mybinlog || 2 | || | #建立一目录用于存放二进制日志 || 3 | || | chown || 4 | mysql:mysql || | /mybinlog || | #更改权限 || | || | vim || | /etc/my || | .cnf || | #修改配置文件 || | || | log-bin= || | /mybinlog/mysql-bin || | || | #二进制日志目录及文件名前缀，添加之 |+———————————–+———————————–+ [[好了言归正传[复制二进制日志文件]\ +———————————–+———————————–+| 1 | [root@stu18 data] || | # cp mysql-bin.000001/innoback | | | up/ |+———————————–+———————————–+ [ （2）模拟服务器崩溃] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # service mysqld stop || 2 | || | [root@stu18 ~] || 3 | # cd /mydata/data/ || | || | [root@stu18 data] || | # rm -rf * |+———————————–+———————————–+ [ （3）准备备份]\ [首先注意“准备”增量备份与整理完全备份有着一些不同，尤其要注意的是：] [ 1)] [ 2)] [完全备份“准备”] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex --apply-log --r | | | edo-only/innobackup/2013-08-14_08 | | | -14-12/ |+———————————–+———————————–+ [第一次增量备份“准备”也就是说将第一次增量备份合并到了完全备份中]\ +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex --apply-log--re | | | do-only /innobackup/2013-08-14_08 | | | -14-12/--incremental-dir=/innobac | | | kup/2013-08-14_08-29-05/ |+———————————–+———————————–+ [第二次增量备份“准备”也就是说将第二次增量备份也合并到了完全备份中]\ +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex --apply-log--re | | | do-only /innobackup/2013-08-14_08 | | | -14-12/ --incremental-dir=/innoba | | | ckup/2013-08-14_09-08-39/ |+———————————–+———————————–+ [[ 其中–redo-only是只将已提交的事务同步到数据文件中，未提交的事务日志不在进行回滚了] [ （4）恢复数据（基于innobackupex基于完全+增量）] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # innobackupex --copy-back/inn | | | obackup/2013-08-14_08-14-12/ |+———————————–+———————————–+ [ （5）更改属组属主] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # cd /mydata/data/ || 2 | || | [root@stu18 data] || | # chown -R mysql:mysql * |+———————————–+———————————–+ [ （6）启动查看] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # mysql -uroot -pmypas || 2 | || | mysql&gt; || 3 | select || | * from coc; || 4 | || | +----+---------+----------+ || 5 | || | | ID | ClassID | CourseID | || 6 | || | +----+---------+----------+ || 7 | || | | 1| 1 | 2 | || 8 | || | | 2| 1 | 5 | || 9 | || | | 3| 2 | 2 | || 10 | || | | 4| 2 | 6 | || 11 | || | | 5| 3 | 1 | || 12 | || | | 6| 3 | 7 | || 13 | || | | 7| 4 | 5 | || 14 | || | | 8| 4 | 2 | || 15 | || | | 9| 5 | 1 | || 16 | || | | 10 | 5 | 9 | || 17 | || | | 11 | 6 | 3 | || 18 | || | | 12 | 6 | 4 | || 19 | || | | 13 | 7 | 4 | || 20 | || | | 14 | 7 | 3 | || 21 | || | +----+---------+----------+ || | || | 14 rows in || | set || | (0.00 sec) |+———————————–+———————————–+ [ 结果显示数据正确完整，但是第三次的改动信息未生效。]\ [ （7）基于二进制日志实现数据恢复] [ 查看最后一次增量备份二进制日志所在的位置：] +———————————–+———————————–+| 1 | [root@stu18 data] || | # cd /innobackup/2013-08-14_09 | | 2 | -08-39/ || | || 3 | [root@stu18 2013-08-14_09-08-39] | | | || | || | # cat xtrabackup_binlog_info || | || | mysql-bin.000001 780 |+———————————–+———————————–+ [ 查看二进制日志文件将未备份数据的二进制日志导出] +———————————–+———————————–+| 1 | [root@stu18 innobackup] || | || 2 | # mysqlbinlog mysql-bin.000001 | | | || 3 | || | # at 780 || 4 | || | #130814 9:20:19 server id 1 en | | 5 | d_log_pos 851 Query thread_id | | | =7 exec_time=0 error_code=0 || 6 | || | SET TIMESTAMP=1376443219/*!*/; || 7 | || | BEGIN || 8 | || | /*!*/; || 9 | || | # at 851 || 10 | || | #130814 9:20:19 server id 1 en | | 11 | d_log_pos 944 Query thread_id | | | =7 exec_time=0 error_code=0 || 12 | || | SET TIMESTAMP=1376443219/*!*/; || 13 | || | delete from coc where || 14 | id || | =14 || 15 | || | /*!*/; || 16 | || | # at 944 || 17 | || | #130814 9:20:19 server id 1 en | | 18 | d_log_pos 1016 Query thread_id | | | =7 exec_time=0 error_code=0 || 19 | || | SET TIMESTAMP=1376443219/*!*/; || 20 | || | COMMIT || 21 | || | /*!*/; || 22 | || | DELIMITER ; || | || | # End of log file || | || | ROLLBACK /* added by mysqlbinlog | | | */; || | || | /*!50003 SET COMPLETION_TYPE=@OL | | | D_COMPLETION_TYPE*/; || | || | /*!50530 SET @@SESSION.PSEUDO_SL | | | AVE_MODE=0*/; || | || | [root@stu18 innobackup] || | || | # mysqlbinlog --start-position | | | =780 mysql-bin.000001 &gt; ./all.sql | | | #导出数据 |+———————————–+———————————–+ [ 恢复数据] +———————————–+———————————–+| 1 | [root@stu18 ~] || | # mysql -uroot –pmypass || 2 | || | mysql&gt; SET SQL_LOG_BIN=0; | | 3 | || | #关闭二进制日志 || 4 | || | mysql&gt; || 5 | source || | /innobackup/all || 6 | .sql || | #导入数据 || 7 | || | mysql&gt; SET SQL_LOG_BIN=1; | | 8 | || | #开启二进制日志 || 9 | || | mysql&gt; || 10 | select || | * from coc; || 11 | #查看数据，恢复完成 || | || 12 | +----+---------+----------+ || | || 13 | | ID | ClassID | CourseID | || | || 14 | +----+---------+----------+ || | || 15 | | 1 | 1 | 2 | || | || 16 | | 2 | 1 | 5 | || | || 17 | | 3 | 2 | 2 | || | || 18 | | 4 | 2 | 6 | || | || 19 | | 5 | 3 | 1 | || | || 20 | | 6 | 3 | 7 | || | || 21 | | 7 | 4 | 5 | || | || 22 | | 8 | 4 | 2 | || | || 23 | | 9 | 5 | 1 | || | || | | 10 | 5 | 9 | || | || | | 11 | 6 | 3 | || | || | | 12 | 6 | 4 | || | || | | 13 | 7 | 4 | || | || | +----+---------+----------+ || | || | 13 rows in || | set || | (0.00 sec) |+———————————–+———————————–+ [ 这种备份恢复方式完全以热备的形式实现完全备份和增量备份和二进制日志还原数据，并且恢复速度也很快，是最佳的备份恢复方式！！] [\] [ 总结：以上三种备份恢复都是可以基于二进制日志文件进行的，因而体现出了二进制日志的重要性，从而映射出了日志的重要性；所以学习查看使用日志文件是学习Mysql的重中之重！] \ 五、MYSQL的基本操作:增删查改 [1、创建数据库： create database&lt;数据库名&gt;；]\[如：create databasestudent;]\[2、连接到一个已经存在的数据库： use&lt;数据库名&gt;；]\[如：usestudent;]\[3、删除数据库：drop database&lt;数据库名&gt;；]\[如： drop databasestudent;]\[4、创建表：create table&lt;表名&gt;(&lt;列名&gt;&lt;列的数据类型&gt;[&lt;列的约束&gt;])]\[如：create table stuInfo(stuId int primary key,stuName varchar(20) notnull)]\[5、删除表： drop table&lt;表名&gt;]\[如: drop tablestuInfo;]\[6、修改表：altertable ]\[给表添加新列： alter table &lt;表名&gt; add&lt;列名&gt;&lt;列的数据类型&gt;；]\[添加多列，中间用逗号隔开]\[如：alter table stuInfo add stuGendervarchar(10)]\[修改某列的数据类型：alter table &lt;表名&gt; modify&lt;列名&gt;&lt;新数据类型&gt;]\[如：alter table stuInfo modify stuGenderint]\[修改列名：alter table &lt;表名&gt; change&lt;老列名&gt;&lt;新列名&gt;&lt;数据类型&gt;]\[如：alter table stuInfo change stuName stuAddressvarchar(30)]\[删除列：alter table &lt;表名&gt; drop&lt;列名&gt;]\[如： alter table stuInfo dropstuGender]\[7、将创建的表的语句反向导出： show create table&lt;表名&gt;]\[8、查询表的所有内容：select * from&lt;表名&gt;]\[查询表的部分内容： select &lt;列名列表&gt; from&lt;表名&gt;]\[9、查询表结构：show columns from&lt;表名&gt;]\[10、插入单行数据：insert into &lt;表名&gt;(&lt;列名列表&gt;)values(&lt;值列表&gt;)]\[11、插入多行数据：作用相当于将数据从一个表复制到另一个表]\[insert into &lt;表名&gt; (列名列表) select&lt;select语句&gt;]\[如将stuInfo表中的所有的学生姓名复制到students表中的stuName列中：insertinto students(stuName) select stuName fromstuInfo]\[12、删除数据：delete from &lt;表名&gt;where&lt;过滤条件&gt;]\[如删除stuID为4的人的数据：delete from stuInfo wherestuId=4] \ \ 六、MYSQL的基本故障判断与处理 以下的文章主要介绍的是MySQL常见问题集锦，我们一共分成七大块对其进行说明，我们大家都知道MySQL数据库在是实际应用中的比例远少于Oracle，之所是这样的，肯定有它的不足之处 。 MySQL常见问题集锦之一： MySQL(和PHP搭配之最佳组合)总是崩溃 首先你应该试着找出问题MySQL(和PHP搭配之最佳组合)d守护进程是否死掉或你的问题是否与你的客户有关 。你可以用MySQL(和PHP搭配之最佳组合)admin version检查你的MySQL(和PHP搭配之最佳组合)d服务器正常执行了多长时间，如果MySQL(和PHP搭配之最佳组合)d死了，你可以在文件“MySQL(和PHP搭配之最佳组合)-data-directory/hostname.err”中找到其原因 。 使用MySQL(和PHP搭配之最佳组合)时的一些常见错误 MySQL(和PHP搭配之最佳组合) server has gone away 常见的原因是服务器超时了并且关闭了连接 。缺省地，如果没有事情发生，服务器在8个小时后关闭连接 。你可在启动MySQL(和PHP搭配之最佳组合)d时通过设置wait_timeout变量改变时间限制 。 如果MySQL(和PHP搭配之最佳组合)d得到一个太大或不正常的包，它认为客户出错了并关闭连接 。 Cant connect to [local] MySQL(和PHP搭配之最佳组合) server 通常意味着没有一个MySQL(和PHP搭配之最佳组合)服务器运行在系统上或当试图连接MySQL(和PHP搭配之最佳组合)d服务器时，你正在使用一个错误的套接字文件或TCP/IP端口 。 检查(使用ps)服务器上是否有一个名为MySQL(和PHP搭配之最佳组合)d的进程启动 如果一个MySQL(和PHP搭配之最佳组合)d进程正在运行，可以通过尝试这些不同的连接来检查服务器 shell&gt; MySQL(和PHP搭配之最佳组合)admin version shell&gt; MySQL(和PHP搭配之最佳组合)admin variables shell&gt; MySQL(和PHP搭配之最佳组合)admin -h `hostname` versionvariables shell&gt; MySQL(和PHP搭配之最佳组合)admin -h `hostname`–port=3306 version shell&gt; MySQL(和PHP搭配之最佳组合)admin -h ip for your hostversion shell&gt; MySQL(和PHP搭配之最佳组合)admin–socket=/tmp/MySQL(和PHP搭配之最佳组合).sock version 注意hostname命令使用反引号“`”而非正引号“”；这些导致hostname输出（即，当前主机名）被代替进MySQL(和PHP搭配之最佳组合)admin命令中 。 Host … is blocked错误 Host hostname is blocked because of many connection errors. Unblock with MySQL(和PHP搭配之最佳组合)admin flush-hosts 这意味着，MySQL(和PHP搭配之最佳组合)d已经得到了大量(max_connect_errors)的主机hostname的在中途被中断了的连接请求 。在max_connect_errors次失败请求后，MySQL(和PHP搭配之最佳组合)d认定出错了(象来字一个黑客的攻击)，并且阻止该站点进一步的连接，直到某人执行命令MySQL(和PHP搭配之最佳组合)adminflush-hosts 。 缺省地，MySQL(和PHP搭配之最佳组合)d在10个连接错误后阻塞一台主机 。你可以通过象这样启动服务器很容易地调整它： shell&gt; safe_MySQL(和PHP搭配之最佳组合)d -O max_connect_errors=10000 &amp; MySQL常见问题集锦之二：Too many connections错误 意味着已经有max_connections个客户连接了MySQL(和PHP搭配之最佳组合)d服务器 。 如果你需要比缺省(100)更多的连接，那么你应该重启MySQL(和PHP搭配之最佳组合)d，用更大的max_connections 变量值 。 MySQL常见问题集锦之三：Out ofmemory错误 MySQL(和PHP搭配之最佳组合): Out of memory at line 42, malloc.c MySQL(和PHP搭配之最佳组合): needed8136 byte (8k), memory inuse: 12481367 bytes (12189k) ERROR 2008:MySQL(和PHP搭配之最佳组合) client ran out of memory 注意，错误指向了MySQL(和PHP搭配之最佳组合)客户MySQL(和PHP搭配之最佳组合) 。这个错误的原因很简单，客户没有足够的内存存储全部结果 。 首先检查你的查询是否正确 MySQL常见问题集锦之四：Packet too large错误 一个MySQL(和PHP搭配之最佳组合)客户或MySQL(和PHP搭配之最佳组合)d服务器得到一个比max_allowed_packet个字节长的包 可以通过用MySQL(和PHP搭配之最佳组合)–set-variable=max_allowed_packet=8M指定一个更大的缓冲区来启动客户程序 。 MySQL常见问题集锦之五：The table isfull错误 这个错误发生在内存临时表变得比tmp_table_size字节大时 。 Commands out of sync in client错误 正在以错误的次序调用客户函数！ MySQL常见问题集锦之六：Ignoring user错误 Found wrong password for user: some_user@some_host; Ignoring user 这意味着在MySQL(和PHP搭配之最佳组合)d启动时或在它再次装载权限表时，它在user表中找到了一个有一个无效口令的条目 。结果，条目简单地被权限系统忽略 。 MySQL常见问题集锦之七：Table xxxdoesnt exist错误 数据库和表名件是区分大小写的！可以用SHOW TABLES检b查你在当前数据库中有哪个表 。 从一个文本文件运行SQL命令 可以把SQL命令放在一个文件中并且告诉MySQL(和PHP搭配之最佳组合)从该文件读取其输入：创造一个文本文件“text_file”，它包含要执行的命令 。然后如下调用MySQL(和PHP搭配之最佳组合)： shell&gt; MySQL(和PHP搭配之最佳组合) database &lt; text_file 或 shell&gt; MySQL(和PHP搭配之最佳组合) &lt; text_file 启动有USEdb_name语句的文本文件 。 怎样重新设置一个忘记的口令 如果忘记了MySQL(和PHP搭配之最佳组合)的root用户的口令，可以使用如下方法恢复： 通过发送一个kill（不是kill-9)到MySQL(和PHP搭配之最佳组合)d服务器来关闭MySQL(和PHP搭配之最佳组合)d服务器 。pid 被保存在一个.pid文件中，通常在MySQL(和PHP搭配之最佳组合)数据库目录中： kill `cat /MySQL(和PHP搭配之最佳组合)-data-directory/hostname.pid` 你必须是一个UNIX root用户或运行服务器的相同用户做这个 。 使用–skip-grant-tables选项重启MySQL(和PHP搭配之最佳组合)d 。 用MySQL(和PHP搭配之最佳组合) -h hostnameMySQL(和PHP搭配之最佳组合)连接MySQL(和PHP搭配之最佳组合)d服务器并且用一条GRANT命令改变口令 。见7.26GRANT和REVOKE句法 。也可以用MySQL(和PHP搭配之最佳组合)admin -h hostname-u user password new password 进行 。 用MySQL(和PHP搭配之最佳组合)admin -h hostnameflush-privileges或用SQL命令FLUSH PRIVILEGES来装载权限表 。 使用DATE列的问题 DATE值的格式是YYYY-MM-DD 。 改变一张表中列的顺序 在一个应用程序中，应该决不基于他们的位置使用SELECT*检索列，因为被返回的列的顺序永远不能保证；对数据库的一个简单改变可能导致应用程序相当有戏剧性地失败 。 可以使用如下方法改变： 以正确的列顺序创建一张新表 。 执行INSERT INTO new_table SELECT fields-in-new_table-order FROM old_table. 删除或改名old_table 。 ALTER TABLE new_table RENAME old_table 。 数据库复制 MySQL(和PHP搭配之最佳组合)(至今)没有数据库复制，但是有一些如何实现的信息 。 复制一个数据库最一般的方法是使用更新日志 。 \ 七、MYSQL的调优 \ MySQL调优\ \调优思路：\1.数据库设计与规划–以后再修该很麻烦，估计数据量，使用什么存储引擎\2.数据的应用–怎样取数据，sql语句的优化\3.mysql服务优化–内存的使用，磁盘的使用\4.操作系统的优化–内核、tcp连接数量\5.升级硬件设备\ \ \磁盘io规划\raid技术：raid0[xfs]\swap分区：最好使用raid0\磁盘分区：一个库放到一个分区上或一个磁盘上\物理分区\create table t1(id int,name char(20)) data directory=\’/data/\’ indexdirectory =\’/data\’;\mkdir /data\chown mysql.mysql /data\ \mysql&gt; show variables like \’%part%\’;\ \ \4.操作系统的优化\网卡bonding技术，\tcp连接数量限制\优化系统打开文件的最大限制\关闭操作系统不必要的服务\ \5.mysql服务优化\show status 看系统的资源\show variables 看变量，在my.cnf配置文件里定义的\showwarnings 查看最近一个sql语句产生的错误警告，看其他的需要看.err日志\show processlist显示系统中正在运行的所有进程。\show errors\ \启用mysql慢查询：—分析sql语句，找到影响效率的SQL\ \log-slow-queries=/var/lib/mysql/slow.log这个路径对mysql用户具有可写权限\long_query_time=2 查询超过2秒钟的语句记录下来\上面的2 是查询的时间，即当一条SQL执行时间超过5秒的时候才记录，/var/lib/mysql/slow.log 是日志记录的位置。\然后重新启动MySQL服务\ \对查询进行缓存\query_cache_size 使用多大内存来缓存查询语句[+8M]\mysql&gt; show variables like\’%query%\’\query_cache_size=8M\[root@st mysql]# vim /etc/my.cnf\ \ \mysql&gt; show status like \’%Qcache%\’;\Qcache_free_blocks：说明缓存太大了。缓存中相邻内存的个数。数目大说明可能有碎片。FLUSHQUERY CACHE会对缓存中的碎片进行整理，从而得到一个空闲块。[+8M]\Qcache_free_memory缓存中的空闲内存\Qcache_hits每次查询在缓存中命中时就增大\Qcache_inserts每插入一个查询时就增大。命中次数除以插入次数就是命中率。\Qcache_lowmen_prunes缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间看；如果这个数字在不断增长就表示可能碎片非常严重，或者内存很少\Qcache_hits/Qcache_inserts 命中率\ \关键字缓冲区\mysql&gt; show status like \’%key%\’;\mysql&gt; show variables like\’key_buffer_size\’;\ \key_buffer_size 指定索引缓冲区的大小，它决定索引处理的速度，尤其是索引读的速度。[+8M]\key_read_requests 请求总数\key_reads 代表命中磁盘的请求个数\(key_read_requests-key_read)/key_read_requests：命中率\key_buffer_size只对MyISAM表起作用。即使你不使用MyISAM表，但是内部的临时磁盘表是MyISAM表，也要使用该值。可以使用检查状态值created_tmp_disk_tables得知详情。\对于1G内存的机器，如果不使用MyISAM表，推荐值是16M（8-64M）。\ \临时表空间大小：order by和group by时把数据放到临时表里。\tmp_table_size 占的是内存的大小，如果太小在排序时会出错\created_tmp_tables 创建临时表的数量\max_tmp_tables=32\tmpdir=/tmp 硬盘上临时表所在的位置\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\innodb表：\创建表空间文件\[mysqld]\innodb_data_file_path=ibdata1:10M:autoextend\这个设置配置一个可扩展大小的尺寸为10MB的单独文件，名为ibdata1。没有给出文件的位置，所以默认的是在MySQL的数据目录内。\如果你对最后的数据文件指定autoextend选项。如果数据文件耗尽了表空间中的自由空间，InnoDB就扩展数据文件。扩展的幅度是每次8MB。\要为一个自动扩展数据文件指定最大尺寸，请使用max属性。下列配置允许ibdata1涨到极限的500MB：\[mysqld]\innodb_data_file_path=ibdata1:10M:autoextend:max:500M\InnoDB默认地在MySQL数据目录创建表空间文件。要明确指定一个位置，请使用innodb_data_home_dir选项。比如，要使用两个名为ibdata1和ibdata2的文件，但是要把他们创建到/ibdata，像如下一样配置InnoDB：\[mysqld]\innodb_data_home_dir = /ibdata\innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend\ \mysql&gt; show variables like \’innodb_buffer_pool_size\’;\innodb_buffer_pool_size\对于InnoDB表来说，innodb_buffer_pool_size的作用就相当于key_buffer_size对于MyISAM表的作用一样。InnoDB使用该参数指定大小的内存来缓冲数据和索引。对于单独的MySQL数据库服务器，最大可以把该值设置成物理内存的80%。\根据MySQL手册，对于2G内存的机器，推荐值是1G（50%）。\ \mysql&gt; show variables like \’innodb_%per%\’;［建议打开］\innodb_file_per_table =1 为每一个表单独创建一个表空间文件。\其他参数\skip-locking\取消文件系统的外部锁，减少出错几率增强稳定性\ \skip-name-resolve\关闭mysql的dns反查功能。这样速度就快了!\选项就能禁用DNS解析，连接速度会快很多。不过，这样的话就不能在MySQL的授权表中使用主机名了而只能用ip格式。\ \wait_timeout=10 终止空闲时间超过10秒的链接，避免长连接［默认8个小时］\ \max_connect_errors=10 //10次连接失败就锁定，使用flush hosts 解锁，\或mysqladmin flush-hosts解锁\ \~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\SQL语句调优：\explain命令：查询select。\.type\这列很重要,显示了连接使用了哪种类别,有无使用索引\从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL\ \MySQL性能诊断与调优 LAMP 系统性能调优，第 3 部分: MySQL 服务器调优\http://www.ibm.com/developerworks/cn/linux/l-tune-lamp-3.html LoadRunner监控MySQL\http://www.docin.com/p-92272846.html Advanced MySQL Performance Optimization\http://www.mysqlperformanceblog.com/files/presentations/UC2005-Advanced-MySQL- Performance-Optimization.pdf Improving MySQL Server Performance with Intel C++ Compiler\http://www.mysqlperformanceblog.com/files/presentations/LinuxWorld2005-Intel.pdf MySQL性能诊断与调优相关工具：\http://www.mysqlperformanceblog.com/tools/\http://hackmysql.com/mysqlreport Spotlight On MySQL:\http://www.quest.com/spotlight-on-mysql/ Mysql Administator http://downloads.mysql.com/archives.php?p=MySQLAdministrationSuite phpMyAdmin http://www.phpmyadmin.net/home_page/index.php mysql slow log分析工具\http://hackmysql.com/\http://www.willamowius.de/mysql-tools.html\http://code.google.com/p/mysql-log-filter/\http://myprofi.sourceforge.net/ mysql网络协议嗅探工具 - mysqlsniffer http://hackmysql.com/mysqlsniffer MySQL性能诊断与调优相关书籍：\《High Performance MySQL Second Edition》 优化mysql数据库性能的十个参数\ (1)、max_connections：\允许的同时客户的数量。增加该值增加 mysqld要求的文件描述符的数量。这个数字应该增加，否则，你将经常看到 too manyconnections 错误。 默认数值是100，我把它改为1024 。\(2)、record_buffer：\每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描，你可能想要增加该值。默认数值是131072(128k)，我把它改为16773120(16m)\(3)、key_buffer_size：\索引块是缓冲的并且被所有的线程共享。key_buffer_size是用于索引块的缓冲区大小，增加它可得到更好处理的索引(对所有读和多重写)，到你能负担得起那样多。如果你使它太大，系统将开始换页并且真的变慢了。默认数值是8388600(8m)，我的mysql主机有2gb内存，所以我把它改为402649088(400mb)。\4)、back_log：\要求 mysql能有的连接数量。当主要mysql线程在一个很短时间内得到非常多的连接请求，这就起作用，然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。\back_log值指出在mysql暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接，你需要增加它，换句话说，这值对到来的tcp/ip连接的侦听队列的大小。你的操作系统在这个队列大小上有它自己的限制。试图设定back_log高于你的操作系统的限制将是无效的。\当你观察你的主机进程列表，发现大量 264084 | unauthenticated user |xxx.xxx.xxx.xxx | null | connect | null | login | null的待连接进程时，就要加大 back_log的值了。默认数值是50，我把它改为500。\(5)、interactive_timeout：\服务器在关闭它前在一个交互连接上等待行动的秒数。一个交互的客户被定义为对mysql_real_connect()使用 client_interactive 选项的客户。默认数值是28800，我把它改为7200。\(6)、sort_buffer：\每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速orderby或group by操作。默认数值是2097144(2m)，我把它改为 16777208 (16m)。\(7)、table_cache：\为所有线程打开表的数量。增加该值能增加mysqld要求的文件描述符的数量。mysql对每个唯一打开的表需要2个文件描述符。默认数值是64，我把它改为512。\(8)、thread_cache_size：\可以复用的保存在中的线程的数量。如果有，新的线程从缓存中取得，当断开连接的时候如果有空间，客户的线置在缓存中。如果有很多新的线程，为了提高性能可以这个变量值。通过比较connections 和 threads_created状态的变量，可以看到这个变量的作用。我把它设置为 80。\(9)mysql的搜索功能\用mysql进行搜索，目的是能不分大小写，又能用中文进行搜索\只需起动mysqld时指定 –default-character-set=gb2312\(10)、wait_timeout：\服务器在关闭它之前在一个连接上等待行动的秒数。默认数值是28800，我把它改为7200。\注：参数的调整可以通过修改 /etc/my.cnf 文件并重启 mysql实现。这是一个比较谨慎的工作，上面的结果也仅仅是我的一些看法，你可以根据你自己主机的硬件情况（特别是内存大小）进一步修改。 \ \ 八、MYSQL主主、主从复制的实现 \ 见SVN文档 \ 九、MYSQL大数据备份和恢复 \ 见SVN文档 \ 十、数据文件的损坏与修复 表损坏的原因分析\以下原因是导致mysql 表毁坏的常见原因：\1、 服务器突然断电导致数据文件损坏。\2、 强制关机，没有先关闭mysql 服务。\3、 mysqld 进程在写表时被杀掉。\4、 使用myisamchk 的同时，mysqld 也在操作表。\5、 磁盘故障。\6、 服务器死机。\7、 mysql 本身的bug 。\ 表损坏的症状\一个损坏的表的典型症状如下：\1 、当在从表中选择数据之时，你得到如下错误：\Incorrect key file for table: \’…\’. Try to repair it\2 、查询不能在表中找到行或返回不完全的数据。\3 、Error: Table \’p\’ is marked as crashed and should be repaired 。\4 、打开表失败： Can’t open file: ‘×××.MYI’ (errno: 145) 。\5 、\ 预防 MySQL表损坏\可以采用以下手段预防mysql 表损坏：\1 、定期使用myisamchk 检查MyISAM 表（注意要关闭mysqld ），推荐使用checktable 来检查表（不用关闭mysqld ）。\2 、在做过大量的更新或删除操作后，推荐使用OPTIMIZE TABLE来优化表，这样既减少了文件碎片，又减少了表损坏的概率。\3 、关闭服务器前，先关闭mysqld （正常关闭服务，不要使用kill -9来杀进程）。\4 、使用ups 电源，避免出现突然断电的情况。\5 、使用最新的稳定发布版mysql ，减少mysql 本身的bug 导致表损坏。\6 、对于InnoDB 引擎，你可以使用innodb_tablespace_monitor来检查表空间文件内文件空间管理的完整性。\7 、对磁盘做raid ，减少磁盘出错并提高性能。\8 、数据库服务器最好只跑mysqld和必要的其他服务，不要跑其他业务服务，这样减少死机导致表损坏的可能。\9 、不怕万一，只怕意外，平时做好备份是预防表损坏的有效手段。\ MySQL表损坏的修复\MyISAM 表可以采用以下步骤进行修复 ：\1、 使用 reapair table 或myisamchk 来修复。\2、 如果上面的方法修复无效，采用备份恢复表。\ 具体可以参考如下做法：\阶段1 ：检查你的表\如果你有很多时间，运行myisamchk *.MYI 或myisamchk -e *.MYI 。使用-s（沉默）选项禁止不必要的信息。\如果mysqld 服务器处于宕机状态，应使用–update-state 选项来告诉myisamchk将表标记为\’ 检查过的\’ 。\你必须只修复那些myisamchk 报告有错误的表。对这样的表，继续到阶段2 。\如果在检查时，你得到奇怪的错误( 例如out of memory 错误)，或如果myisamchk 崩溃，到阶段3 。\阶段2 ：简单安全的修复\注释：如果想更快地进行修复，当运行myisamchk 时，你应将sort_buffer_size和Key_buffer_size 变量的值设置为可用内存的大约25% 。\首先，试试myisamchk -r -q tbl_name(-r -q 意味着“ 快速恢复模式”)。这将试图不接触数据文件来修复索引文件。如果数据文件包含它应有的一切内容和指向数据文件内正确地点的删除连接，这应该管用并且表可被修复。开始修复下一张表。否则，执行下列过程：\在继续前对数据文件进行备份。\使用myisamchk -r tbl_name(-r 意味着“ 恢复模式”)。这将从数据文件中删除不正确的记录和已被删除的记录并重建索引文件。\如果前面的步骤失败，使用myisamchk –safe-recover tbl_name。安全恢复模式使用一个老的恢复方法，处理常规恢复模式不行的少数情况(但是更慢) 。\如果在修复时，你得到奇怪的错误( 例如out of memory 错误)，或如果myisamchk 崩溃，到阶段3 。\阶段3 ：困难的修复\只有在索引文件的第一个16K块被破坏，或包含不正确的信息，或如果索引文件丢失，你才应该到这个阶段。在这种情况下，需要创建一个新的索引文件。按如下步骤操做：\把数据文件移到安全的地方。\使用表描述文件创建新的( 空) 数据文件和索引文件：\shell&gt; mysql db_name\mysql&gt; SET AUTOCOMMIT=1;\mysql&gt; TRUNCATE TABLE tbl_name;\mysql&gt; quit\如果你的MySQL 版本没有TRUNCATE TABLE ，则使用DELETE FROM tbl_name 。\将老的数据文件拷贝到新创建的数据文件之中。（不要只是将老文件移回新文件之中；你要保留一个副本以防某些东西出错。）\回到阶段2 。现在myisamchk -r -q应该工作了。（这不应该是一个无限循环）。\你还可以使用REPAIR TABLE tbl_name USE_FRM ，将自动执行整个程序。\阶段4 ：非常困难的修复\只有.frm描述文件也破坏了，你才应该到达这个阶段。这应该从未发生过，因为在表被创建以后，描述文件就不再改变了。\从一个备份恢复描述文件然后回到阶段3 。你也可以恢复索引文件然后回到阶段2。对后者，你应该用myisamchk -r 启动。\如果你没有进行备份但是确切地知道表是怎样创建的，在另一个数据库中创建表的一个拷贝。删除新的数据文件，然后从其他数据库将描述文件和索引文件移到破坏的数据库中。这样提供了新的描述和索引文件，但是让.MYD数据文件独自留下来了。回到阶段2 并且尝试重建索引文件。\ InnoDB 表可以采用下面的方法修复：\如果数据库页被破坏，你可能想要用SELECT INTO OUTFILE从从数据库转储你的表，通常以这种方法获取的大多数数据是完好的。即使这样，损坏可能导致SELECT* FROM tbl_name 或者InnoDB 后台操作崩溃或断言，或者甚至使得InnoDB前滚恢复崩溃。 尽管如此，你可以用它来强制InnoDB存储引擎启动同时阻止后台操作运行，以便你能转储你的表。例如：你可以在重启服务器之前，在选项文件的[mysqld]节添加如下的行：\ [mysqld]innodb_force_recovery = 4innodb_force_recovery被允许的非零值如下。一个更大的数字包含所有更小数字的预防措施。如果你能够用一个多数是4的选项值来转储你的表，那么你是比较安全的，只有一些在损坏的单独页面上的数据会丢失。一个为6的值更夸张，因为数据库页被留在一个陈旧的状态，这个状态反过来可以引发对B树和其它数据库结构的更多破坏。\ 1 (SRV_FORCE_IGNORE_CORRUPT)\即使服务器检测到一个损坏的页，也让服务器运行着；试着让SELECT * FROMtbl_name 跳过损坏的索引记录和页，这样有助于转储表。\ 2 (SRV_FORCE_NO_BACKGROUND)\阻止主线程运行，如果崩溃可能在净化操作过程中发生，这将阻止它。\ 3 (SRV_FORCE_NO_TRX_UNDO)\恢复后不运行事务回滚。\ 4 (SRV_FORCE_NO_IBUF_MERGE)\也阻止插入缓冲合并操作。如果你可能会导致一个崩溃。最好不要做这些操作，不要计算表统计表。\ 5 (SRV_FORCE_NO_UNDO_LOG_SCAN)\启动数据库之时不查看未完成日志：InnoDB 把未完成的事务视为已提交的。\ 6 (SRV_FORCE_NO_LOG_REDO)\不要在恢复连接中做日志前滚。\ 数据库不能另外地带着这些选项中被允许的选项来使用。作为一个安全措施，当innodb_force_recovery被设置为大于0 的值时，InnoDB 阻止用户执行INSERT, UPDATE 或DELETE 操作.\ 即使强制恢复被使用，你也可以DROP 或CREATE表。如果你知道一个给定的表正在导致回滚崩溃，你可以移除它。你也可以用这个来停止由失败的大宗导入或失败的ALTERTABLE 导致的失控回滚。你可以杀掉mysqld进程，然后设置innodb_force_recovery 为3，使得数据库被挂起而不需要回滚，然后舍弃导致失控回滚的表。\ [\]]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[ftp自动下载]]></title>
    <url>%2F2015%2F05%2F26%2F36%2F</url>
    <content type="text"><![CDATA[123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动添加秘钥认证用户#缺省的配置如下 logdir=/data/log/shell #日志路径log=$logdir/shell.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=1 #是否记录日志: 1记录 0不记录basedir="/data/ehuzhu"yes=$(date -d yesterday +%Y-%m-%d)yesmonth=$(date -d yesterday +%Y-%m)host=x.x.x.xuser=adminpass=xxxxxxx datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;download()&#123;if [[ $host == "" ]];thenprint_log "ftp的服务器IP不能为空."exitfi if [[ $user == "" ]];thenprint_log "ftp的用户名不能为空."exitfiif [[ $pass == "" ]];thenprint_log "ftp的密码不能为空."exitfiif [[ ! -d $basedir/$yesmonth/$yes ]];thenmkdir -p $basedir/$yesmonth/$yesfiprint_log "开始下载...$host:$yes目录到=&gt;$basedir/$yesmonth/$yes."ftp -v -n &lt;&lt;!open $hostuser $user $passbinarycd $yeslcd $basedir/$yesmonth/$yespromptmget *closebye!print_log "下载完成...$host:$yes目录到=&gt;$basedir/$yesmonth/$yes."&#125;download#for i in &#123;1..160&#125;#do#yes=$(date -d "$i days ago" +%Y-%m-%d)#yesmonth=$(date -d "$i days ago" +%Y-%m)#print_log "$yes ==&gt; $yesmonth"#download#done]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[expect定期远程登录Juniper防火墙实现定期重新拨号]]></title>
    <url>%2F2015%2F05%2F21%2F37%2F</url>
    <content type="text"><![CDATA[123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133#!/bin/bash#author: GaoMing#date: 2015-05-20#qq: 530035210#blog: http://my.oschina.net/pwd/blog #pppoe 定期重新拨号logdir=/data/log/shell #日志路径log=$logdir/log.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=1 #是否记录日志: 1记录 0不记录User=adminHost=192.168.1.253Password="cccccc!@#xxxxxxxx748."#Cmd="get pppoe name ADSL-callcenter"Cmd="get interface" from_name="运维组"from="530035210@qq.com"to="huanggm@baoxian.com"datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;run()&#123;if [[ $1 == "" ]];thenprint_log "cmd命令不能为空"exitfi expect -c " spawn /usr/bin/ssh -o StrictHostKeyChecking=no $User@$Host set timeout -1 expect \"\*password\*:\" send \"$Password\r\" expect \"\*\&gt;\" send \"$1 \r\" expect \"\*\&gt;\" send \"exit\r\" expect eof "&#125;sendmail()&#123;email_title=$1email_content=$2email_subject=$3if [[ $email_title == "" ]];thenemail_title="这是一封测试邮件."fiif [[ $email_content == "" ]];thenemail_content="这是测试邮件的内容."fiif [[ $email_subject == "" ]];thenemail_subject="这是测试邮件的主题."fiecho -e "To: \"$&#123;email_title&#125;\" &lt;$&#123;to&#125;&gt; \nFrom: \"$&#123;from_name&#125;\" &lt;$&#123;from&#125;&gt;\nSubject: $&#123;email_subject&#125;\n\n`echo $&#123;email_content&#125;`" | /usr/sbin/sendmail -t&#125;#获取拨号前接口的外网地址run_res1=$(run "get interface")interface_1=$(echo "$run_res1" |grep "eth0\/1" |awk '&#123;print $2&#125;' |sed "s/\/32//g")interface_2=$(echo "$run_res1" |grep "eth0\/2" |awk '&#123;print $2&#125;'|sed "s/\/32//g")interface_3=$(echo "$run_res1" |grep "eth0\/3" |awk '&#123;print $2&#125;'|sed "s/\/32//g")print_log "重启前,各接口的外网地址如下: eth0/1:$interface_1 eth0/2:$interface_2 eth0/3:$interface_3"#开始拨号run_int1=$(run "exec pppoe name ADSL-bw2 disconnect")run_int2=$(run "exec pppoe name BW-GuangXian-2 disconnect")run_int3=$(run "exec pppoe name ADSL-callcenter disconnect")#获取拨号后接口的外网地址run2_res1=$(run "get interface")interface2_1=$(echo "$run2_res1" |grep "eth0\/1" |awk '&#123;print $2&#125;' |sed "s/\/32//g")interface2_2=$(echo "$run2_res1" |grep "eth0\/2" |awk '&#123;print $2&#125;'|sed "s/\/32//g")interface2_3=$(echo "$run2_res1" |grep "eth0\/3" |awk '&#123;print $2&#125;'|sed "s/\/32//g")print_log "重启后,各接口的外网地址如下: eth0/1:$interface2_1 eth0/2:$interface2_2 eth0/3:$interface2_3"if [[ $interface2_1 == "" ]];thenprint_log "eth0/1: 拨号已经断开!"sendmail "" "eth0/1:重新拨号断开." "ppoe-eth1-重新拨号已经断开"fiif [[ $interface2_2 == "" ]];thenprint_log "eth0/2: 拨号已经断开!"sendmail "" "eth0/2:重新拨号断开." "ppoe-eth2-重新拨号已经断开"fiif [[ $interface2_3 == "" ]];thenprint_log "eth0/3: 拨号已经断开!"sendmail "" "eth0/3:重新拨号断开." "ppoe-eth3-重新拨号已经断开"fiif [[ $interface2_1 != "$interface_1" ]];thenprint_log "eth0/1:重新拨号成功!"elseprint_log "eth0/1:重新拨号失败,拨号前后外网IP没有发生变化!"sendmail "" "eth0/1:重新拨号失败,IP没有发生变化." "ppoe-eth1-重新拨号失败"fi if [[ $interface2_2 != "$interface_2" ]];thenprint_log "eth0/2:重新拨号成功!"elseprint_log "eth0/2:重新拨号失败,拨号前后外网IP没有发生变化!"sendmail "" "eth0/2:重新拨号失败,IP没有发生变化." "ppoe-eth2-重新拨号失败"fiif [[ $interface2_3 != "$interface_3" ]];thenprint_log "eth0/3:重新拨号成功!"elseprint_log "eth0/3:重新拨号失败,拨号前后外网IP没有发生变化!"sendmail "" "eth0/3:重新拨号失败,IP没有发生变化." "ppoe-eth3-重新拨号失败"fi]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[持续部署，并不简单！]]></title>
    <url>%2F2015%2F05%2F14%2F38%2F</url>
    <content type="text"><![CDATA[这几年，持续集成随着敏捷在国内的推广而持续走热，与之相伴的持续部署也一直备受关注。自前两年，持续交付这个延续性概念又闯进了国内IT圈，慢慢开始在社区和会议中展露头角。许多不明真相的群众跟风哭着喊着要“上”，而许多前CI的半吊子玩家换件衣服就接着干，有的甚至衣服都来不及换……国内的这些土财主如果不巧请了某些所谓的战略家，除了建了一堆持续集成环境，以及每天嚷嚷着要这个要那个，混乱的状况在根本上没有得到改善。本文无意费力探讨持续集成和持续交付的概念，而是打算谈谈对于大型软件企业，以持续集成为基础实现持续部署（交付）时，所要面对的问题以及可行的解决方案。地主老财们，夜黑风正猛，山高路又远，注意脚下…… And God Said, Let there be light: and there wa— GENSIS, Charpter1, King James 一、起步 先来讲个故事…… 几年前，一对留美的夫妇通过朋友找到我，让我帮忙在国内组建一个开发团队，该团队负责为其开发一款基于社交网络的客户关系管理软件,（暂且称之为项目A）。这个项目除了尚不清晰的需求范围和很紧的期限外，作为业内人士的老公Richard根据眼下流行的软件开发过程还提了诸多额外的要求： ● 功能要及早交付（以便拿去和潜在的投资人洽谈） **● 功能在部署到生产环境前要先部署的一个测试环境**（Richard要试用后给予反馈） **● 功能必须经过测试**（长期作为软件外包的甲方，对质量要求严格） **● 要减少后期维护的工作**（美国人精贵，少雇一个是一个） **● 支持协同开发**（以便维护人员及早介入） ● …… 这正是持续集成所要解决的典型场景。针对Richard的要求，我们只要建立一个基于Hudson（现在叫Jenkins）+Maven+SVN的持续集成环境（再加上持续集成所要求的测试和过程）就可以很好地满足上述要要求，此方案的结构如下： {width=”545”height=”566”} 对于上述方案，让我们近距离看看各个服务器的内部情况，以及人员在这种方案下的分工协作： {width=”518”height=”345”} 我们先谈谈上面的图中涉及的一些概念性问题： 1.1）编译时依赖和运行时依赖 从字面上不难理解这两种依赖的类型。但要注意虽然编译时依赖常常也是运行时依赖，但并不能推断出一方必然是另一方。比如，在开发的过程中需要某些提供API的Jar包，而运行时可能是具体API实现的Jar包。再者，被依赖的包会有其自身的依赖，因此,项目对这些包产生间接依赖（运行时依赖），依此类推，最终形成一个依赖树。当项目运行时，这些依赖树上的包必须全部就位。 Maven在POM中通scope来界定依赖的类型，从而帮助开发和运维人员摆脱手动处理依赖树的工作，然而运行时所依赖包最终是要安装到生产环境的，这部分工作Maven并不能自动完成。因此，一个常用方式是将运行时所依赖的包拷贝到项目文件中，比如JavaWeb应用的WEB-INF/lib，然后将项目总的打一个包。在安装项目包后，修改环境变量，将这些包所在的路径加入相应的环境变量中，如ClassPath。 再看个例子，现代的操作系统和其它系统框架都考虑到了运行时依赖树的处理问题，比如Ubuntu的apt-get，CentOS的yum，Ruby的RubyGem，Node的npm等等。 1.2）依赖时的复杂度 项目除了对程序包的依赖，对于运行环境也有些具体的要求，比如，Web应用需要安装和配置Web服务器，应用服务器，数据服务器等，企业应用中可能需要消息队列，缓存，定时作业，或是对其它系统以WebService方式暴露的服务。这些可以看做项目在系统层面对外部的依赖。这些依赖有些可以由项目自行处理，而有些则是项目无法处理的，比如运行容器，操作系统等，这些是项目的运行环境。 总之，依赖的复杂度主要有两个： 1. 依赖包间的版本兼容性问题。兼容性问题是软件开发的恶梦 2.间接依赖，或多重依赖问题。这个问题可以类比想像一下C++中的多重继续种出现的很多问题。 比如：Ａ依赖于python 2.7，A还依赖于B，但是B却依赖于python 3，而Python2.7和Python 3不兼容。这是依赖中最恶心的事。 1.3）任务分工 由于项目简单，因此并不需要专门的运维人员。以一个100人左右以交付为主业（恩，就是做外包）的公司为例，由于没有任何历史项目和代码的拖累，且各个项目间也没有任何关联，故而只需要配备一个IT支持人员进行资源方面的管理：分配机器，报修，初始化系统，分配IP地址等。各个项目的运行环境、数据库、开发环境等都由具体项目的开发人员手动完成。环境出问题怎么办？很简单，凉拌——重装系统。实际的运行效果不错。 1.4）自动化部署 由于Hudson这样的持续集成环境提供了自动编译（定时或触发式）的功能，而且可以在编译过程中提供了一些扩展点，因此通过提供一个部署用的脚本，就可以非常容易实现简单的自动化部署。 毫无疑问，持续集成就是敏捷的魔法药，它见效快、副作用小、业界的争论少。每每运用在混乱的项目中时，几周内项目就开始持续的产出经过测试的功能。对于独立项目，以持续集成为中心的持续部署绝对是不二选择。 但是，我们有没有想过，这会是一个自动化部署的通用解决方案吗？持续集成应该位于持续交付的中心吗？ 二、困境 回到我们的故事：项目A上线两年后，运营业绩不错，投资人第一轮注资后，Richard的公司进行了扩张，他们对项目进行了重构，而且随着用户数量的增长，公司分别在美国、英国和日本等地建立了运营中心，并且对亚洲市场进行的定制功能开发（项目A+），接下来，公司又投入开发了团购系统（项目B）。在获得了新一轮投资后，各条本来比较简单的业务和功能线上越来越复杂，需要不断地细分，于是公司再度扩张（开发人员达到了300人，国内200多人，而运维团队主要在美国），随后又为项目A/A+的高级用户开发了问答系统（项目C）。目前，他们正准备开发手机系统。看看下面的图，公司增长的过程中，整个项目环境也变得复杂。（注意，这里是一种逻辑结构，而在物理层面项目B和项目A的生产环境可能部署在相同的机器上）。 {width=”553”height=”285”} 同时，原本单一的项目软件结构随着业务系统的增加也不再简单： {width=”503”height=”274”} 而软件间的版本依赖使这个问题变得更为复杂： {width=”501”height=”274”} 现在，Richard的公司已经不再是一条快乐的小鱼，而是渐渐成为一直庞大的巨兽。虽然只有四个产品，但公司却要支持几百台开发机，几十台生产服务器，还有对应的测试环境，数据库服务器，以及几十个开发小组，和一大堆的内部项目。我们尽可以使用持续集成来为我们完成自动化部署。但，当我们为各个项目建立起持续集成环境后，它能满足我们对于持续部署的要求吗？我们前期的工作可以简化我们今后项目的持续交付的工作的难度吗？它需要我们为之建立一个庞大的运维团队，还是可以让我们能节省下每一毛钱来投入到真正的业务价值中去？ 让我们先来看看复杂的项目环境中的几个场景： 场景1：环境升级 项目A和项目B都依赖于Web容器，公司决定升级Web容器版本，而公司要升级的机器有上百台，依赖人肉升级已不现实，维护团队因此针对各种软件开发了相应的自动化脚本，但当新的软件出现时，必须要开发新的脚本。而且当同时升级若干环境软件时，则难度随之增大，手工调度的方式极易出错，当升级失败时仍需要大量人工处理。由于存在大量升级脚本，有一定的维护成本。 场景2：依赖于环境的软件升级与回滚 针对环境升级，公司为项目A和项目B开发了新的版本。但环境的升级和软件的升级不是同步进行，出错的可能性非常大（想一想间接依赖和多重依赖的情况）。当新版本部署到生产系统时，发现问题，需要回滚到之前的版本——所有运行时版本都需要回滚，而且环境也需要同步回滚。几百台机器…… 场景3：运行时依赖 在第一节的方案中，我们将所有的运行时依赖都打包到一起。当项目依赖关系复杂时，这样产生的包将非常臃肿，潜在地延长了部署的时间（想一想全世有几百台服务器，一个部署计划需要部署几百兆文件的情况），而且产生冲突的可能性非常大，而且对于不同类型的项目（Java和Ruby项目）缺乏通用性。06年左右，Nortel可是拿Excel统计过运行时依赖的，牵涉若干项目组，反复多次，没有个把月真搞不定。 场景4：泛滥的部署 每个项目相关的持续集成环境都需要开发自己的部署脚本，重复投入大，而且各个项目的部署过程不一致，并且对于同一个项目无法同时满足不同目的部署要求，例如，环境或系统配置参数改变后，无需安装包，只需做清理和激活的工作。最后，持续集成只是支持了和代码修改有关的部署。 场景5：不一致的环境 简单项目中，开发环境和运行环境都由开发人员搭建，当公司变大时，系统的运行环境将由运维人员搭建，而开发环境如果由运维人员搭建则工作量太大，由开发人员自己搭建则操作复杂又容易产生不一致的情况。 场景6：热切换 对于某些部署，需要尽量减少服务的停止时间，需要在服务的同时进行部署。 这些场景只是以持续集成为中心的持续部署在面对大型企业时所遇到的部分问题。大型企业，人多，项目多，机器多，项目环境复杂，部署维护工作繁多。以持续集成为基础的部署可以解决各个项目的集成问题，却无法帮助企业应对复杂的项目环境和各种不同的部署要求。究其更本，大型企业中的部署不再是一个简单的问题，而是一个交付生态圈，基础设施和环境管理必须要纳入考虑之中。要实现真正意义上的持续部署，我们就必须把环境和项目同等对待，通通纳入管理之中。同时，部署本身要得到统一。一个好的部署机制，应该是易于建立，易于使用，易于维护。 三、任脉——环境管理 什么是环境？ 系统运行所依赖和包含的一切就是其环境：硬件、操作系统，网络资源（IP地址、域名），服务容器，服务器软件配置，环境亦是，运行时依赖的命令和包，项目本身的包和配置都是环境的一部分。对于部署而言，广义上，这些通通应该纳入环境管理的范畴，但狭义上，从软件系统的角度看，一个环境就是其运行需要的软件及其配置（我们先把操作系统和网络资源当做基础设施，其在部署时已处于就位的情况）。因此： 项目A的生产环境 = 项目A本身的软件包 + 项目A运行时依赖的软件包 +项目A运行时依赖的其它软件 + 项目A的配置信息 由于，项目本身的软件包、项目运行时依赖的软件包，以及项目运行时依赖的其它软件在本质上没有区别——都是软件，上面的定义可以进一步抽象为： 环境 = 软件包 + 配置信息 在这个定义下，我们就必须将运行环境的软件解构，并以包的形式导入到公司的整个项目资源库中，比如Apache将作为一个包被导入，而Apache依赖的其它包也将依次被导入，并建立起正确的依赖关系。而且，在导入的过程中还必须做些相应的调整，如，环境变量的读取和设置，必须来自于环境配置模块，而不要修改系统的环境变量，防止不同环境在系统环境配置上相互影响和依赖。 再回头审视我们的示例，项目A的生产环境可以部署在不同的区域，对于各个区域可能有定制化的设定。这就像面向对象中的类，可以通过继承使子类重用父类的公有属性和行为并添加自己特有的信息。因此，环境的概念模型如图： {width=”523”height=”118”} 通过这样的关系，我们很容易为示例的复杂环境建立一种简单的结构，对于项目A： {width=”539”height=”467”} 这里，环境依然是处于知识层面（KnowledgeLevel），它并未与具体的基础设施相关联。当我们将一个环境“具现化”成一个运行系统时，我们就产生了一个真正的环境实例。在这两者之间，我们还必须要考虑环境实例的使用目的（开发？测试？……）以及安装所依赖的其它信息（如机器），因此，我们需要增加一个环境目标来集中这些信息，而且由于不同目标的环境可能会有所差别，因此，环境目标也需要配置的能力。概念模型如图： {width=”523”height=”438”} 图中的环境实例是如何产生的呢？部署，一次部署可能会产生一个环境实例。一系列部署将产生对应于环境目标的多个环境实例，除去当前起作用的环境实例外（最新的），其它的是历史环境实例。通过在历史环境实例中切换，我们自然而然的就可以使整个环境回滚，因为项目所依赖的一切都已经成为的环境中的软件包，而且环境依赖的包的版本会随着部署具体确定下来。如此一来，我们便可以给每个环境实例分配一个版本号，再通过环境实例的版本号与软件包的版本对应起来，从而得知一次部署时应用的具体软件包，如图： {width=”520”height=”307”} 目前的环境管理结构，已经可以解决场景1、2和5的问题。那么对于场景2，运行时依赖，环境管理应该如何解决呢？ 细心的朋友，可能已经发现，在环境层面上我们确定了环境依赖的软件包，这里有两个隐藏的含义： ● 环境定义的是对软件包的运行时依赖 ● 由于环境是一个逻辑上的概念，因此其所用的软件包也是一个逻辑上的概念（相对于版本控制系统中的软件包） 我们也已经知道，在部署时，一个环境实例将具体的确定其依赖的软件包的版本。某个版本的软件包最终与代码库中的物理的软件包相关联。但软件包是运行时的安装包，因此，它应该是代码库中包编译的结果。在对代码库的包编译时，既要将结果打上版本保存起来，也好在两者的版本间建立关系，最后，编译结果应该是某种既定的安装包目录文件结构。 另外，当环境包含的包比较多时，运行时版本树会非常大，手动的指定全部的包的版本将是一个非常大的体力劳动，这部分工作也要得到简化。由此，我们必须 **● 建立逻辑软件包版本和版本库中软件包版本间的关系** **● 为相互依赖的包编译并打上统一的标签** **● 简化运行时包依赖关系的生产** **● 简化运行时包依赖的指定（可参考apt-get和RubyGem，环境只需指定直接依赖的包，间接依赖的包从运行时依赖树中自动导入）** 一个可能的简单结构如下： {width=”548”height=”137”} 上述讨论还没有涉及操作系统，如果我们的运行机器要支持多个系统，我们又该怎么办？？？ 配置信息也是个大问题，大家可以思考 **● 环境配置和应用配置如何区分？** **● 如何简化环境配置工作？** **● 如何使环境配置的效果只对具体环境有效，而不会泄露到环境外部？** 再者， **● 如何使应用支持多运行目标？** **● 环境管理如何能方便开发环境的调试？** **● 要如何简化版本的选择?** **● 在多个包有编译和运行时依赖时，编译时如何检查以减少引入兼容性问题的风险？** 这些都留待大家思考。 四、督脉——部署系统 《持续集成》和《持续交付》中都对部署有详细的讨论，不在赘述。在我看来，部署其就是按照其目的执行一系列步骤将环境置于其目的所指向的状态中。我们一会再回国头来看这段文绉绉的话，先看看第一部分持续集成的环境下，我们部署的步骤可能会是下面这个样子： 1.登陆目标机（ssh） 2.停止服务 3.清理环境 4.准备安装环境（创建文件夹等） 5.安装项目包（rsync，解压，权限设置等） 6.配置环境变量 7.启动服务 8……. 而在第二部分的情景4中，我们看到如果对不同的持续集成环境建立不同的部署脚本和环境维护脚本，这部署过程的维护会非常繁琐。基于第三部分的环境管理，我们可以将部署过程抽象为： {width=”566”height=”351”} 现在回到开头那个文绉绉的描述：部署其就是按照其目的执行一系列步骤将环境置于其目的所指向的状态中。 由于我们已经将部署作为环境管理的一部分，而环境又是对外提供服务的最小实体，因此，对环境的部署就是要根据部署的类型，在环境上按一定的步骤执行一系列操作，从而使环境置于部署类型所要的状态，这个过程中可能会生成对应的环境实例。举例来说，我们可能会修改环境相关的一些配置，然后重启环境，显然，这种情况下不需要下载安装软件包（没有改变），因此也就不需要生成环境实例。 对于标准的部署——安装软件包并启动环境，可能的步骤将会是： 1. 选择将要部署的软件包的版本 2.生成新的环境实例（确定环境实例的版本和其依赖包的版本，确定环境配置等） 3.清理和准备目标机环境 4.下载包 5.设置环境配置 6.环境实例切换 7.生成部署报告 8……. 好，部署系统和环境管理各就各位，我们可以将各个项目环境纳入我们的环境管理之中，甚至是持续集成环境本身。再补充一句，要让部署系统和环境管理能很好的发挥作用，我们即需要一个简单一致的UI界面（为开发人员），也需要提供一个清晰明了的服务接口（供外部系统调用，如持续部署系统）。对于与环境管理相关的机器状态管理，网络资源的配置等等，本文不再涉及，大家可以自己思考。环境管理的实现、编译系统改造以及持续部署的具体实现，另作文章探讨。 就技术而言（不考虑围绕持续部署的过程实践），环境管理、部署系统以及我们没有提及的编译系统改造才是生产线的真正引擎，持续部署不过是水到渠成的传送带而已。 五、没完 打通了任督二脉后，事还还没有完，还有很多细节上的问题。你想，这个工具实在是太好用了，于是公司里成百上千的工程师们都在使用这个自动化部署系统，我们又会面对很多很多问题： **● 部署系统的性能问题**。几百号人不停地在把他们的软件部署到自己的机器上，部署到测试环境，部署到生产环境，一天之内一个人可能会要部署N次，回滚N次，不但有大量部署请求，还有大量的文件在网络上传输。你得想想这套部署系统如何解决这些性能问题，还得考虑未来更大规模的性能水平扩展问题。 **● 目标机环境的管理。**在目标运行机上需要解决几个问题：1）两个环境间如果有一些的一样的包，那就没有必要再下载了，这样可以节约时间。2）每次部署都需要把老的部署环境给保留下来，这样方便在新旧环境下的切换。这两点对于在生产环境下部署非常关键。（这需要环境内所有软件的绿色安装才能更容易达到这个目标，因些，Unix/Linux会比Windows更容易做到这点） **● 部署一致性事务问题**。有时候，我们需要同时部署若干台服务器，比如：包A到机器MA，包B到机器MB，包C到机器MC，……（WebService的SOA架构），这些包之间有运行依赖性和兼容性问题，要么一次性全部完成，要么就全部失败。回滚也是一样的，这是一个部署事务或部署一致性的问题。如何解决呢？ **● 部署环境的版本控制问题**。前面说过，我们的一个环境就会和若干个包的版本耦合，环境必需管理要部署的包的版本。于是，当你的部署越来越多的时候，各个环境的包的版本开始出现混乱，各种依赖间的版本也会出现不统一的情况，也就是说，就算你有这样的一个工具，在一个高速开发的环境下，我们的部署环境的管理还是会出现很多混乱的情况，需要你不断地统一大家的开发、测试环境。 **● 部署计划**。我们可能会有很多部署计划，比如：设定定时部署，提升或降低部署优先级，部署事务定义，部署策略（如：先部署10%的机器，如果没有问题，再把剩下的系统部署了），热切计划和策略……等等 ，等等 。 **● 部署的监控和维护**。任何软件和系统都会有这样的问题，当规模上去了以后，我们的自动化部署系统的监控和维护的复杂度并不亚于一个大型的互联网应用。 这样的问题会有很多，基本上来说，这样一个持续集成持续部署的自动化系统并不是那么简单的事，其开发工作量和一个标准的大型互联网业务系统没什么两样。 六、总结 这里只谈一点自己的看法，从传统的持续集成到面向大型软件的持续部署，我们将系统所依赖的软件环境和软件包抽象为一致的实体纳入到管理之中，并将运维人员的工作真正的分摊到开发人员身上。而云计算的出现，使得计算机本身也可以自动化的创建和回收，这样环境管理的范畴将进一步扩充。相应的，部署的能力和灵活性也是一次质的飞跃，将再一次减轻运维人员的工作压力。 说了这么多废话，总结一下自己的观点，对于向大型软件企业推销基于持续集成的持续部署（交付）的哥们： **● 你就是在耍流氓**，如果你不解决环境管理！！！ **● 你就是在耍流氓**，如果你不建立部署系统！！！ **● 你就是在耍流氓**，如果你不扩展编译系统！！！ **● 你就是在耍流氓**，如果你只是推销小团队的实践而不考虑改造大环境！！！ **● 你就是个流氓**，如果你只是不断地告诉别人怎么做，自己却从来不动手写一个测试或建立一个持续集成环境！！！ 最后，用Linus最经典的话来结束本文——“ Talk is Cheap, Show me theCode！”]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[cmd、dos如何恢复默认设置]]></title>
    <url>%2F2015%2F05%2F13%2F39%2F</url>
    <content type="text"><![CDATA[具体方法如下：(首先打开注册表编辑器) XP: 开始 – 运行 – 输入regedit 2.WIN7: win+R – 输入regedit 这时会弹出 注册表编辑器 然后在注册表编辑器左边的文件夹目录里面找到: HKEY_CURRENT_USER \ Console \ %SystemRoot%_system32_cmd.exe 删除文件夹 %SystemRoot%_system32_cmd.exe 就好了 (右键这个文件夹 有删除选项) 然后重启cmd 就恢复了默认设置]]></content>
      <categories>
        <category>Windows</category>
      </categories>
      <tags>
        <tag>Windows</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[生产mongodb 分片与集群 方案]]></title>
    <url>%2F2015%2F05%2F06%2F40%2F</url>
    <content type="text"><![CDATA[生产mongodb 分片与集群 方案 一、 mongodb分片与集群拓扑图 二、分片与集群的部署 1.Mongodb的安装 分别在以上3台服务器安装好mongodb 安装方法见安装脚本。 2.Mongod 创建单个分片的副本集 10.68.4.209 ①建立数据文件夹和日志文件夹 mdkir /data/{master,slave,arbiter} mkdir /data/log/mongodb/{master,slave,arbiter} -p ②建立配置文件 #master.conf dbpath=/data/master logpath=/data/log/mongodb/master/mongodb.log pidfilepath=/var/run/mongo_master.pid #directoryperdb=true logappend=true replSet=policydb port=10002 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 #slave.conf dbpath=/data/slave logpath=/data/log/mongodb/slave/mongodb.log pidfilepath=/var/run/mongo_slave.pid #directoryperdb=true logappend=true replSet=policydb port=10001 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 #arbiter.conf dbpath=/data/arbiter logpath=/data/log/mongodb/arbiter/mongodb.log pidfilepath=/var/run/mongo_arbiter.pid #directoryperdb=true logappend=true replSet=policydb port=10000 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 ③启动mongodb /etc/init.d/mongodb_master start /etc/init.d/mongodb_slave start /etc/init.d/mongodb_arbiter start ④配置主、备、仲裁节点 主节点: /usr/local/mongodb/bin/mongo 10.68.4.209:10002MongoDB shell version: 2.4.9 connecting to: 10.68.4.209:10002/test use admin switched to db admin config={ _id:”policydb”, members:[ {_id:0,host:’10.68.4.209:10002’,priority:2}, {_id:1,host:’10.68.4.209:10001’,priority:1}, … {_id:2,host:’10.68.4.209:10000’,arbiterOnly:true}] }; { &quot;_id&quot; : &quot;policydb&quot;, &quot;members&quot; : [ { &quot;_id&quot; : 0, &quot;host&quot; : &quot;10.68.4.209:10002&quot;, &quot;priority&quot; : 2 }, { &quot;_id&quot; : 1, &quot;host&quot; : &quot;10.68.4.209:10001&quot;, &quot;priority&quot; : 1 }, { &quot;_id&quot; : 2, &quot;host&quot; : &quot;10.68.4.209:10000&quot;, &quot;arbiterOnly&quot; : true } ] } rs.initiate(config) #初始化 rs.status() #查看集群状态 10.68.4.29 ①建立数据文件夹和日志文件夹 mdkir /data/{master,slave,arbiter} mkdir /data/log/mongodb/{master,slave,arbiter} -p ②建立配置文件 #master.conf dbpath=/data/master logpath=/data/log/mongodb/master/mongodb.log pidfilepath=/var/run/mongo_master.pid #directoryperdb=true logappend=true replSet=policydb2 port=10002 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 #slave.conf dbpath=/data/slave logpath=/data/log/mongodb/slave/mongodb.log pidfilepath=/var/run/mongo_slave.pid #directoryperdb=true logappend=true replSet=policydb2 port=10001 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 #arbiter.conf dbpath=/data/arbiter logpath=/data/log/mongodb/arbiter/mongodb.log pidfilepath=/var/run/mongo_arbiter.pid #directoryperdb=true logappend=true replSet=policydb2 port=10000 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 ③启动mongodb /etc/init.d/mongodb_master start /etc/init.d/mongodb_slave start /etc/init.d/mongodb_arbiter start ④配置主、备、仲裁节点 主节点: /usr/local/mongodb/bin/mongo 10.68.4.209:10002MongoDB shell version: 2.4.9 connecting to: 10.68.4.209:10002/test use admin switched to db admin config={ _id:”policydb2”, members:[ {_id:0,host:’10.68.4.29:10002’,priority:2}, {_id:1,host:’10.68.4.29:10001’,priority:1}, … {_id:2,host:’10.68.4.209:10000’,arbiterOnly:true}] }; { &quot;_id&quot; : &quot;policydb&quot;, &quot;members&quot; : [ { &quot;_id&quot; : 0, &quot;host&quot; : &quot;10.68.4.29:10002&quot;, &quot;priority&quot; : 2 }, { &quot;_id&quot; : 1, &quot;host&quot; : &quot;10.68.4.29:10001&quot;, &quot;priority&quot; : 1 }, { &quot;_id&quot; : 2, &quot;host&quot; : &quot;10.68.4.29:10000&quot;, &quot;arbiterOnly&quot; : true } ] } rs.initiate(config) #初始化 rs.status() #查看集群状态 10.68.4.30 ①建立数据文件夹和日志文件夹 mdkir /data/{master,slave,arbiter} mkdir /data/log/mongodb/{master,slave,arbiter} -p ②建立配置文件 #master.conf dbpath=/data/master logpath=/data/log/mongodb/master/mongodb.log pidfilepath=/var/run/mongo_master.pid #directoryperdb=true logappend=true replSet=policydb3 port=10002 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 #slave.conf dbpath=/data/slave logpath=/data/log/mongodb/slave/mongodb.log pidfilepath=/var/run/mongo_slave.pid #directoryperdb=true logappend=true replSet=policydb3 port=10001 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 #arbiter.conf dbpath=/data/arbiter logpath=/data/log/mongodb/arbiter/mongodb.log pidfilepath=/var/run/mongo_arbiter.pid #directoryperdb=true logappend=true replSet=policydb3 port=10000 oplogSize=10000 fork=true noprealloc=true profile=1 slowms=200 ③启动mongodb /etc/init.d/mongodb_master start /etc/init.d/mongodb_slave start /etc/init.d/mongodb_arbiter start ④配置主、备、仲裁节点 主节点: /usr/local/mongodb/bin/mongo 10.68.4.209:10002MongoDB shell version: 2.4.9 connecting to: 10.68.4.209:10002/test use admin switched to db admin config={ _id:”policydb3”, members:[ {_id:0,host:’10.68.4.30:10002’,priority:2}, {_id:1,host:’10.68.4.30:10001’,priority:1}, … {_id:2,host:’10.68.4.30:10000’,arbiterOnly:true}] }; { &quot;_id&quot; : &quot;policydb&quot;, &quot;members&quot; : [ { &quot;_id&quot; : 0, &quot;host&quot; : &quot;10.68.4.30:10002&quot;, &quot;priority&quot; : 2 }, { &quot;_id&quot; : 1, &quot;host&quot; : &quot;10.68.4.30:10001&quot;, &quot;priority&quot; : 1 }, { &quot;_id&quot; : 2, &quot;host&quot; : &quot;10.68.4.30:10000&quot;, &quot;arbiterOnly&quot; : true } ] } rs.initiate(config) #初始化 rs.status() #查看集群状态 2.Mongod 创建单个分片的配置服务器 ① 创建配置目录 10.68.4.209 mkdir /data/config 10.68.4.29 mkdir /data/config 10.68.4.30 mkdir /data/config ②准备配置服务器的配置文件 3个服务器的配置服务器的配置文件一致 #config.conf dbpath=/data/config logpath=/data/log/mongodb/config/mongodb.log pidfilepath=/var/run/mongo_config.pid directoryperdb=true logappend=true port=10003 fork=true configsvr=true ③启动配置服务器 /etc/init.d/mongodb_config start 3.Mongod 创建并配置mongos和开启分片模式 ① 创建日志目录 Mkdir -p /data/log/mongodb/mongos/ ② 准备mongos的配置文件 #mongos.conf logpath=/data/log/mongodb/mongos/mongodb.log pidfilepath=/var/run/mongo_mongos.pid logappend=true port=10004 fork=true configdb=10.68.4.209:10003,10.68.4.29:10003,10.68.4.30:1000 ③ 启动mongos /etc/init.d/mongodb_mongos start ④ 配置分片 sh.addShard(“policydb/10.68.4.209:10002”) sh.addShard(“policydb2/10.68.4.29:10002”) sh.addShard(“policydb3/10.68.4.30:10002”) sh.enableSharding(“policydb”) db.runCommand({“shardcollection”:”policydb.fullPolicyTextInfo_history”, “key”:{“key”:1}}) db.printShardingStatus() #查看分片状态 sh.status({verbose:true}) sh.status() 3.快速创建副本集和配置服务脚本 上图 1.图1 2.图2 config.conf配置文件 3.图3 附mongodb一键安装脚本: http://pan.baidu.com/s/1c0zvP7M 附mongodb副本集和配置服务器一键配置脚本: http://pan.baidu.com/s/1GuQ0A]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[自动监控url是否可用,如不可用则重启应用,并做相应的报警策略。]]></title>
    <url>%2F2015%2F05%2F04%2F41%2F</url>
    <content type="text"><![CDATA[先上图\ 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动监控url是否可用,如不可用则重启应用,并做相应的报警策略。#缺省的配置如下 logdir=/data/log/check #日志路径log=$logdir/log.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录key="data-camp" #进程关键字exec_stop="/etc/init.d/data-camp stop" #停应用命令exec_start="/etc/init.d/data-camp start" #启动应用命令 datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;#定义重启derestart()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():应用关键字不能为空"exitfiif [[ $2 == "" ]];thenprint_log "$FUNCNAME():启动文件不能为空"exitfiif [[ $2 == "" ]];thenprint_log "$FUNCNAME():启动参数口不能为空"exitfippid=0ppid=$(ps axu |grep "$1" |grep -v grep |grep -v "$0" |wc -l)$2 $3 ppid=$(ps axu |grep "$1" |grep -v grep |grep -v "$0" |wc -l)echo $ppid &gt; /tmp/restart.numprint_log "$FUNCNAME(): $1的进程数为:$ppid"&#125;#场景一: 当网站返回码不为200,则重启应用.check_code()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():服务器地址不能为空"exitfiif [[ $2 == "" ]];thenprint_log "$FUNCNAME():服务器端口不能为空"exitfiprint_log "$FUNCNAME():开始检测-[$1:$2]服务器的网站状态返回码."code=$(curl -m 8 -o /dev/null -s -w %&#123;http_code&#125; http://$1:$2/verdict/session/LSGJA52U7CH055974/latest/result)if [[ $code -ne 200 ]];thenprint_log "$FUNCNAME():[$1:$2]服务器的网站状态返回码不正常,开始重启应用--$code."print_log "$FUNCNAME():执行命令: $exec_stop"derestart "$key" "$exec_stop"num2=$(cat /tmp/restart.num)if [[ $num2 -ne 0 ]];thenprint_log "$FUNCNAME():停应用失败."fi print_log "$FUNCNAME():执行命令: $exec_start"sleep 3derestart "$key" "$exec_start"num2=$(cat /tmp/restart.num)if [[ $num2 -eq 0 ]];thenprint_log "$FUNCNAME():启动应用失败."fiprint_log "$FUNCNAME():重启应用成功."elseprint_log "$FUNCNAME():[$1:$2]服务器的网站状态返回码正常--$code."fi &#125;#场景二: 检测网站http返回的时间check_timeout()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():服务器地址不能为空"exitfiif [[ $2 == "" ]];thenprint_log "$FUNCNAME():服务器端口不能为空"exitfiprint_log "$FUNCNAME():开始检测-[$1:$2]服务器的网站超时时间."httptime=`curl -o /dev/null -s -w "time_connect: %&#123;time_connect&#125;\ntime_starttransfer:%&#123;time_starttransfer&#125;\ntime_total: %&#123;time_total&#125;\n" "http://$1:$2/verdict/session/LSGJA52U7CH055974/latest/result" |grep time_total|awk -F ":" '&#123;print $2*1000&#125;'`taketime=$(expr $httptime / 1000)if [[ $httptime -gt 60000 ]];thenprint_log "$FUNCNAME():[$1:$2]服务器的网站响应时间不正常,开始重启应用--$httptime ms."print_log "$FUNCNAME():执行命令: $exec_stop"derestart "$key" "$exec_stop"num2=$(cat /tmp/restart.num)if [[ $num2 -ne 0 ]];thenprint_log "$FUNCNAME():停应用失败."fiprint_log "$FUNCNAME():执行命令: $exec_start"sleep 3derestart "$key" "$exec_start"num2=$(cat /tmp/restart.num)if [[ $num2 -eq 0 ]];thenprint_log "$FUNCNAME():启动应用失败."fiprint_log "$FUNCNAME():重启应用成功."elseprint_log "$FUNCNAME():[$1:$2]服务器的网站响应时间正常--$httptime ms/$taketime s."fi&#125;check_code "localhost" "6500"check_timeout "localhost" "6500"]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[解决TCP连接数过多的问题]]></title>
    <url>%2F2015%2F05%2F01%2F42%2F</url>
    <content type="text"><![CDATA[解决TCP连接数过多的问题 TCP状态迁移，CLOSE_WAIT &amp; FIN_WAIT2 的问题 TCP状态迁移 大家对netstat-a命令很熟悉，但是，你有没有注意到STATE一栏呢，基本上显示着established,time_wait,close_wait等，这些到底是什么意思呢，在这篇文章，我将会详细的阐述。 大家很明白TCP初始化连接三次握手吧：发SYN包，然后返回SYN/ACK包，再发ACK包，连接正式建立。但是这里有点出入，当请求者收到SYS/ACK包后，就开始建立连接了，而被请求者第三次握手结束后才建立连接。但是大家明白关闭连接的工作原理吗？关闭连接要四次握手：发FIN包，ACK包，FIN包，ACK包，四次握手！！为什么呢，因为TCP连接是全双工，我关了你的连接，并不等于你关了我的连接。 客户端TCP状态迁移： CLOSED-&gt;SYN_SENT-&gt;ESTABLISHED-&gt;FIN_WAIT_1-&gt;FIN_WAIT_2-&gt;TIME_WAIT-&gt;CLOSED 服务器TCP状态迁移： CLOSED-&gt;LISTEN-&gt;SYN收到-&gt;ESTABLISHED-&gt;CLOSE_WAIT-&gt;LAST_ACK-&gt;CLOSED 当客户端开始连接时，服务器还处于LISTENING， 客户端发一个SYN包后，他就处于SYN_SENT状态,服务器就处于SYS收到状态, 然后互相确认进入连接状态ESTABLISHED. 当客户端请求关闭连接时,客户端发送一个FIN包后,客户端就进入FIN_WAIT_1状态,等待对方的确认包, 服务器发送一个ACK包给客户,客户端收到ACK包后结束FIN_WAIT_1状态,进入FIN_WAIT_2状态,等待服务器发过来的关闭请求, 服务器发一个FIN包后,进入CLOSE_WAIT状态, 当客户端收到服务器的FIN包,FIN_WAIT_2状态就结束,然后给服务器端的FIN包给以一个确认包,客户端这时进入TIME_WAIT, 当服务器收到确认包后,CLOSE_WAIT状态结束了, 这时候服务器端真正的关闭了连接.但是客户端还在TIME_WAIT状态下, 什么时候结束呢.我在这里再讲到一个新名词:2MSL等待状态,其实TIME_WAIT就是2MSL等待状态, 为什么要设置这个状态,原因是有足够的时间让ACK包到达服务器端,如果服务器端没收到ACK包，超时了，然后重新发一个FIN包，直到服务器收到ACK包. TIME_WAIT状态等待时间是在TCP重新启动后不连接任何请求的两倍. 大家有没有发现一个问题:如果对方在第三次握手的时候出问题,如发FIN包的时候,不知道什么原因丢了这个包,然而这边一直处在FIN_WAIT_2状态,而且TCP/IP并没有设置这个状态的过期时间,那他一直会保留这个状态下去,越来越多的FIN_WAIT_2状态会导致系统崩溃. 上面我碰到的这个问题主要因为TCP的结束流程未走完，造成连接未释放。现设客户端主动断开连接，流程如下 如上图所示， Client 消息 Server close() —— FIN ——-&gt; FIN_WAIT1CLOSE_WAIT &lt;—– ACK ——- FIN_WAIT2 close() &lt;—— FIN —— TIME_WAITLAST_ACK ------ ACK -------&amp;gt; CLOSED CLOSED 由于Server的Socket在客户端已经关闭时而没有调用关闭， 造成服务器端的连接处在“挂起”状态，而客户端则处在等待应答的状态上。 此问题的典型特征是： 一端处于FIN_WAIT2 ，而另一端处于CLOSE_WAIT. 不过，根本问题还是程序写的不好，有待提高 CLOSE_WAIT，TCP的癌症，TCP的朋友。 CLOSE_WAIT状态的生成原因 首先我们知道，如果我们的服务器程序APACHE处于CLOSE_WAIT状态的话，说明套接字是被动关闭的！ 因为如果是CLIENT端主动断掉当前连接的话，那么双方关闭这个TCP连接共需要四个packet： Client —&gt; FIN —&gt; Server Client &lt;— ACK &lt;— Server 这时候Client端处于FIN_WAIT_2状态；而Server 程序处于CLOSE_WAIT状态。 Client &lt;— FIN &lt;— Server 这时Server 发送FIN给Client，Server 就置为LAST_ACK状态。 Client —&gt; ACK —&gt; Server Client回应了ACK，那么Server 的套接字才会真正置为CLOSED状态。 Server程序处于CLOSE_WAIT状态，而不是LAST_ACK状态，说明还没有发FIN给Client，那么可能是在关闭连接之前还有许多数据要发送或者其他事要做，导致没有发这个FIN packet。 通常来说，一个CLOSE_WAIT会维持至少2个小时的时间。如果有个流氓特地写了个程序，给你造成一堆的CLOSE_WAIT，消耗你的资源，那么通常是等不到释放那一刻，系统就已经解决崩溃了。 只能通过修改一下TCP/IP的参数，来缩短这个时间：修改tcp_keepalive_*系列参数有助于解决这个问题。 解决这个问题的方法是修改系统的参数，系统默认超时时间的是7200秒，也就是2小时，这个太大了，可以修改如下几个参数： sysctl -w net.ipv4.tcp_keepalive_time=30 sysctl -w net.ipv4.tcp_keepalive_probes=2 sysctl -w net.ipv4.tcp_keepalive_intvl=2 然后，执行sysctl命令使修改生效。 连接进程是通过一系列状态表示的，这些状态有： LISTEN，SYN-SENT，SYN-RECEIVED，ESTABLISHED，FIN-WAIT-1，FIN-WAIT-2，CLOSE-WAIT，CLOSING，LAST-ACK，TIME-WAIT和CLOSED。 各个状态的意义如下： LISTEN - 侦听来自远方TCP端口的连接请求； SYN-SENT -在发送连接请求后等待匹配的连接请求； SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认； ESTABLISHED- 代表一个打开的连接，数据可以传送给用户； FIN-WAIT-1 - 等待远程TCP的连接中断请求，或先前的连接中断请求的确认； FIN-WAIT-2 - 从远程TCP等待连接中断请求； CLOSE-WAIT - 等待从本地用户发来的连接中断请求； CLOSING -等待远程TCP对连接中断的确认； LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认； TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认； CLOSED - 没有任何连接状态； TCP连接过程是状态的转换，促使发生状态转换的是用户调用： OPEN，SEND，RECEIVE，CLOSE，ABORT和STATUS； 传送过来的数据段，特别那些包括以下标记的数据段SYN，ACK，RST和FIN； 还有超时，上面所说的都会时TCP状态发生变化。 TCP连接的状态转换图 这个图n多人都 知道，它对排除和定位网络或系统故障时大有帮助，但是怎样牢牢地将这张图刻在脑中呢？那么你就一定要对这张图的每一个状态，及转换的过程有深刻地认识，不能只停留在一知半解之中。下面对这张图的11种状态详细解释一下，以便加强记忆！不过在这之前，先回顾一下TCP建立连接的三次握手过程，以及关闭连接的四次握手过程。 1、建立连接协议（三次握手） （1）客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。 （2）服务器端回应客户端的，这是三次握手中的第2个报文，这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应；同时又标志SYN给客户端，询问客户端是否准备好进行数据通讯。 （3） 客户必须再次回应服务段一个ACK报文，这是报文段3。 2、连接终止协议（四次握手） 由于TCP连接是全双工的，因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动，一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭，而另一方执行被动关闭。 （1） TCP客户端发送一个FIN，用来关闭客户到服务器的数据传送（报文段4）。 （2）服务器收到这个FIN，它发回一个ACK，确认序号为收到的序号加1（报文段5）。和SYN一样，一个FIN将占用一个序号。 （3） 服务器关闭客户端的连接，发送一个FIN给客户端（报文段6）。 （4）客户段发回ACK报文确认，并将确认序号设置为收到序号加1（报文段7）。 CLOSED: 这个没什么好说的了，表示初始状态。 LISTEN: 这个也是非常容易理解的一个状态，表示服务器端的某个SOCKET处于监听状态，可以接受连接了。 SYN_RCVD: 这个状态表示接受到了SYN报文，在正常情况下，这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态，很短暂，基本上用netstat你是很难看到这种状态的，除非你特意写了一个客户端测试程序，故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时，当收到客户端的ACK报文后，它会进入到ESTABLISHED状态。 SYN_SENT:这个状态与SYN_RCVD遥想呼应，当客户端SOCKET执行CONNECT连接时，它首先发送SYN报文，因此也随即它会进入到了SYN_SENT状态，并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。 ESTABLISHED：这个容易理解了，表示连接已经建立了。 FIN_WAIT_1:这个状态要好好解释一下，其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是：FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时，它想主动关闭连接，向对方发送了FIN报文，此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后，则进入到FIN_WAIT_2状态，当然在实际的正常情况下，无论对方何种情况下，都应该马上回应ACK报文，所以FIN_WAIT_1状态一般是比较难见到的，而FIN_WAIT_2状态还有时常常可以用netstat看到。 FIN_WAIT_2：上面已经详细解释了这种状态，实际上FIN_WAIT_2状态下的SOCKET，表示半连接，也即有一方要求close连接，但另外还告诉对方，我暂时还有点数据需要传送给你，稍后再关闭连接。 TIME_WAIT: 表示收到了对方的FIN报文，并发送出了ACK报文，就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下，收到了对方同时带FIN标志和ACK标志的报文时，可以直接进入到TIME_WAIT状态，而无须经过FIN_WAIT_2状态。 CLOSING:这种状态比较特殊，实际情况中应该是很少见，属于一种比较罕见的例外状态。正常情况下，当你发送FIN报文后，按理来说是应该先收到（或同时收到）对方的ACK报文，再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后，并没有收到对方的ACK报文，反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢？其实细想一下，也不难得出结论：那就是如果双方几乎在同时close一个SOCKET的话，那么就出现了双方同时发送FIN报文的情况，也即会出现CLOSING状态，表示双方都正在关闭SOCKET连接。 CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢？当对方close一个SOCKET后发送FIN报文给自己，你系统毫无疑问地会回应一个ACK报文给对方，此时则进入到CLOSE_WAIT状态。接下来呢，实际上你真正需要考虑的事情是察看你是否还有数据发送给对方，如果没有的话，那么你也就可以close这个SOCKET，发送FIN报文给对方，也即关闭连接。所以你在CLOSE_WAIT状态下，需要完成的事情是等待你去关闭连接。 LAST_ACK: 这个状态还是比较容易好理解的，它是被动关闭一方在发送FIN报文后，最后等待对方的ACK报文。当收到ACK报文后，也即可以进入到CLOSED可用状态了。 最后有2个问题 的回答，我自己分析后的结论（不一定保证100%正确） 1、为什么建立连接协议是三次握手，而关闭连接却是四次握手呢？ 这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后，它可以把ACK和SYN（ACK起应答作用，而SYN起同步作用）放在一个报文里来发送。但关闭连接时，当收到对方的FIN报文通知时，它仅仅表示对方没有数据发送给你了；但未必你所有的数据都全部发送给对方了，所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后，再发送FIN报文给对方来表示你同意现在可以关闭连接了，所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。 2、为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状 态？ 这是因为：虽然双方都同意关闭连接了，而且握手的4个报文也都协调和发送完毕，按理可以直接回到CLOSED状态（就好比从SYN_SEND状态到ESTABLISH状态那样）；但是因为我们必须要假想网络是不可靠的，你无法保证你最后发送的ACK报文会一定被对方收到，因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文，而重发FIN报文，所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文，并保证于此。 断开连接的时候， 当发起主动关闭的左边这方发送一个FIN过去后， 右边被动关闭的这方要回应一个ACK，这个ACK是TCP回应的，而不是应用程序发送的， 此时，被动关闭的一方就处于CLOSE_WAIT状态了。 如果此时被动关闭的这一方不再继续调用closesocket,那么他就不会发送接下来的FIN，导致自己老是处于CLOSE_WAIT。 只有被动关闭的这一方调用了closesocket,才会发送一个FIN给主动关闭的这一方，同时也使得自己的状态变迁为LAST_ACK。 比如被动关闭的是客户端. 当对方调用closesocket的时候，你的程序正在 int nRet = recv(s,….); if (nRet == SOCKET_ERROR) { // closesocket(s); return FALSE; } 很多人就是忘记了那句closesocket，这种代码太常见了。 我的理解， 当主动关闭的一方发送FIN到被动关闭这边后，被动关闭这边的TCP马上回应一个ACK过去，同时向上面应用程序提交一个ERROR， 导致上面的SOCKET的send或者recv返回SOCKET_ERROR. 正常情况下，如果上面在返回SOCKET_ERROR后调用了closesocket,那么被动关闭的者一方的TCP就会发送一个FIN过去，自己的状态就变迁到LAST_ACK. 服务器上出现大量的close_wait的例子和解决方法（例子从网上找的，基本差不多） oracle9i@RHEL3oracle9i]\$ /usr/sbin/lsof -i | grep 6800 oracle 22725 oracle9i 3u IPv4 18621468 TCP RHEL3:6800(LISTEN) oracle 22725 oracle9i 4u IPv4 18621469 TCPRHEL3:6800-&gt;RHEL3:2174 (CLOSE_WAIT) oracle 22725 oracle9i 8u IPv4 18621568 TCPRHEL3:6800-&gt;RHEL3:2175 (CLOSE_WAIT) oracle 22725 oracle9i 9u IPv4 18621578 TCPRHEL3:6800-&gt;RHEL3:2176 (CLOSE_WAIT) oracle 22726 oracle9i 3u IPv4 18621468 TCP RHEL3:6800(LISTEN) oracle 22726 oracle9i 4u IPv4 18621469 TCPRHEL3:6800-&gt;RHEL3:2174 (CLOSE_WAIT) oracle 22726 oracle9i 8u IPv4 18621568 TCPRHEL3:6800-&gt;RHEL3:2175 (CLOSE_WAIT) oracle 22726 oracle9i 9u IPv4 18621578 TCPRHEL3:6800-&gt;RHEL3:2176 (CLOSE_WAIT) [oracle9i@RHEL3 oracle9i]\$ kill -9 22725 # 22725, 22726就是使用该6800端口的进程号(PID)。 [oracle9i@RHEL3 oracle9i]\$ /usr/sbin/lsof -i | grep 6800 进程被kill时，会释放占用的所有链接句柄。 该问题的出现原因网上到处都是，也就是Socket的Client端出现异常没有Close就退出了。 //上面这句话不太准确，应该是被动关闭连接一端没有closesocket就退出了，此时被动关闭一端就处于close_wait状态]]></content>
      <categories>
        <category>日常记录</category>
      </categories>
      <tags>
        <tag>日常记录</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[mongodb.conf配置文件详解]]></title>
    <url>%2F2015%2F04%2F13%2F43%2F</url>
    <content type="text"><![CDATA[启动MongoDB有2种方式，一是直接指定配置参数，二是指定配置文件。这里先介绍配置文件，启动方式如下： 1.mongod –config /etc/mongodb.conf 配置如下： verbose：日志信息冗余。默认false。提高内部报告标准输出或记录到logpath配置的日志文件中。要启用verbose或启用verbosity用vvvv参数，如： 1.verbose = true\2.vvvv = true ps：启动verbose冗长信息，它的级别有vv~vvvvv，v越多级别越高，在日志文件中记录的信息越详细。 port：端口。默认27017，MongoDB的默认服务TCP端口，监听客户端连接。要是端口设置小于1024，比如1021，则需要root权限启动，不能用mongodb帐号启动，（普通帐号即使是27017也起不来）否则报错：[mongo–port=1021 连接] 1.ERROR: listen(): bind() failed errno:13 Permission denied for socket:127.0.0.1:1021 1.port = 27017 bind_ip：绑定地址。默认127.0.0.1，只能通过本地连接。进程绑定和监听来自这个地址上的应用连接。要是需要给其他服务器连接，则需要注释掉这个或则把IP改成本机地址，如192.168.200.201[其他服务器用mongo –host=192.168.200.201 连接]，可以用一个逗号分隔的列表绑定多个IP地址。 1.bind_ip = 127.0.0.1 maxConns：最大连接数。默认值：取决于系统（即的ulimit和文件描述符）限制。MongoDB中不会限制其自身的连接。当设置大于系统的限制，则无效，以系统限制为准。这对于客户端创建很多“表”，允许连接超时而不关闭“表”的时候很有用。设置该值的高于连接池和总连接数的大小，以防止尖峰时候的连接。注意：不能设置该值大于20000。 1.maxConns = 100 objcheck:强制验证客户端请求。2.4的默认设置为objcheck成为true，在早期版本objcheck默认为false。因为它强制验证客户端请求，确保客户端绝不插入无效文件到数据库中。对于嵌套文档的对象，会有一点性能影响。设置noobjcheck关闭。 1.objcheck = true\2.#noobjcheck = false noobjcheck：同上，默认关闭false。 1.#noobjcheck = false logpath：指定日志文件，该文件将保存所有的日志记录、诊断信息。除非另有指定，mongod将所有的日志信息输出到标准输出。如果没有指定logappend，重启则日志会进行覆盖操作。 1.logpath=/var/log/mongodb/mongodb.log logappend：写日志的模式：设置为true为追加。默认是覆盖。如果未指定此设置，启动时MongoDB的将覆盖现有的日志文件。 1.logappend=true syslog：日志输出都发送到主机的syslog系统，而不是标准输出到logpath指定日志文件。syslog和logpath不能一起用，会报错： 1.Cant use both a logpath and syslog 1.syslog = true pidfilepath：进程ID，没有指定则启动时候就没有PID文件。默认缺省。 1.pidfilepath = /var/run/mongo.pid keyFile：指定存储身份验证信息的密钥文件的路径。默认缺省。详情见：\” word-spacing: 0px; display: inline; white-space: normal; orphans: 2;widows: 2; font-size-adjust: none; font-stretch: normal;background-color: #ffffff; -webkit-text-size-adjust: auto;-webkit-text-stroke-width: 0px;\”&gt;Replica Set Security\” and “ReplicaSet Administration.” 1.keyFile = /srv/mongodb/keyfile nounixsocket：套接字文件，默认为false，有生成socket文件。当设置为true时，不会生成socket文件。 1.nounixsocket = false unixSocketPrefix：套接字文件路径，默认/tmp 1.unixSocketPrefix = /tmp fork：是否后台运行，设置为true 启动进程在后台运行的守护进程模式。默认false。 1.fork = true auth：用户认证，默认false。不需要认证。当设置为true时候，进入数据库需要auth验证，当数据库里没有用户，则不需要验证也可以操作。直到创建了第一个用户，之后操作都需要验证。 1.auth = true 比如：通过db.addUser(\’sa\’,\’sa\’)在admin库下面创建一个超级用户，只能在在admin库下面先认证完毕了：ab.auth(\’sa\’,\’sa\’)，才能去别的库操作，不能在其他库验证。这样连接数据库也需要指定库： 1.mongo -usa -psa admin #sa 帐号连接admin 1.mongo -uaa -paa test #aa 帐号连接test noauth：禁止用户认证，默认true。同上 1.noauth = true cpu：设置为true会强制mongodb每4s报告cpu利用率和io等待，把日志信息写到标准输出或日志文件。默认为false。 1.cpu = true 开启日志会出现： 1.Mon Jun 10 10:21:42.241 [snapshotthread] cpu: elapsed:4000writelock: 0% dbpath：数据存放目录。默认： word-spacing: 0px; white-space: normal;orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal;background-color: #ffffff; -webkit-text-size-adjust: auto;-webkit-text-stroke-width: 0px;\”&gt;/data/db/ 1.dbpath=/var/lib/mongodb diaglog：创建一个非常详细的故障排除和各种错误的诊断日志记录。默认0。设置为1，为在dbpath目录里生成一个diaglog.开头的日志文件，他的值如下： 1.Value Setting\2.0 off. No logging. #关闭。没有记录。\3.1 Log write operations. #写操作\4.2 Log read operations. #读操作\5.3 Log both read and write operations. #读写操作\6.7 Log write and some read operations. #写和一些读操作 设置不等于0，日志会每分钟flush 一次： 1.Mon Jun 10 11:16:17.504 [DataFileSync] flushing diag log\2.Mon Jun 10 11:17:17.442 [DataFileSync] flushing diag log 产生的日志可以用mongosniff来查看：要是mongosniff[类似于tcpdump的作为一个MongoDB的特定的TCP/IP网络流量]出现报错和具体用法，请见这里，之前先执行：apt-get installlibpcap-dev 1.root@m3:/var/lib/mongodb# mongosniff –source DIAGLOGdiaglog.51b542a9 注意：当重新设置成0，会停止写入文件，但mongod还是继续保持打开该文件，即使它不再写入数据文件。如果你想重命名，移动或删除诊断日志，你必须完全关闭mongod实例。 1.diaglog = 3 directoryperdb：设置为true，修改数据目录存储模式，每个数据库的文件存储在DBPATH指定目录的不同的文件夹中。使用此选项，可以配置的MongoDB将数据存储在不同的磁盘设备上，以提高写入吞吐量或磁盘容量。默认为false。\注意：要是在运行一段时间的数据库中，开启该参数，会导致原始的数据都会消失（注释参数则会回来）。因为数据目录都不同了，除非迁移现有的数据文件到directoryperdb产生的数据库目录中，如：\root@m3:/var/lib/mongodb# mv test.* test/\把test数据文件迁移到directoryperdb产生的数据库test目录中。所以需要在规划好之后确定是否要开启。 1.directoryperdb = ture 01.原始数据结构：\02.journal\03.mongod.lock\04.local.0\05.local.1\06.local.ns\07.test.0\08.test.1\09.test.ns\10.\11.开启 directoryperdb，并把数据文件迁移到相关的数据目录后的结构：\12.\13.journal\14.mongod.lock\15.local/local.0\16.local/local.1\17.local/local.ns\18.test/test.0\19.test/test.1\20.test/test.ns journal：日志，（redo log，更多的介绍请看这里和这里）\默认值：（在64位系统）true。\默认值：（32位系统）false。\设置为true，启用操作日志，以确保写入持久性和数据的一致性，会在dbpath目录下创建journal目录。\设置为false，以防止日志持久性的情况下，并不需要开销。为了减少磁盘上使用的日志的影响，您可以启用nojournal，并设置为true。\注意：在64位系统上禁用日志必须使用带有nojournal的。 1.#journal=true\2.journal=false 32位OS： 1.Tue Jun 11 12:17:09.628 [initandlisten] ** NOTE: This is a 32 bitMongoDB binary.\2.Tue Jun 11 12:17:09.628 [initandlisten] ** 32 bit builds arelimited to less than 2GB of data (or less with –journal). 64位OS： 1.Tue Jun 11 12:29:34 [initandlisten] journaldir=/var/lib/mongodb/journal\2.Tue Jun 11 12:29:34 [initandlisten] recover : no journal filespresent, no recovery needed nojournal:禁止日志\默认值：（在64位系统）false。\默认值：（32位系统）true。\设置nojournal为true关闭日志，64位，2.0版本后的mongodb默认是启用journal日志。 1.nojournal=true journalCommitInterval：刷写提交机制，默认是30ms或则100ms。较低的值，会更消耗磁盘的性能。\此选项接受2和300毫秒之间的值：\如果单块设备提供日志和数据文件，默认的日记提交时间间隔为100毫秒。\如果不同的块设备提供的日志和数据文件，默认的日记提交的时间间隔为30毫秒。 1.journalCommitInterval=100 ipv6：是否支持ipv6，默认false。 jsonp：是否允许JSONP访问通过一个HTTP接口，默认false。 nohttpinterface：是否禁止http接口，即28017端口开启的服务。默认false，支持。 1.nohttpinterface = false noprealloc：预分配方式。\默认false：使用预分配方式来保证写入性能的稳定，预分配在后台进行，并且每个预分配的文件都用0进行填充。这会让MongoDB始终保持额外的空间和空余的数据文件，从而避免了数据增长过快而带来的分配磁盘空间引起的阻塞。\设置noprealloc=true来禁用预分配的数据文件，会缩短启动时间，但在正常操作过程中，可能会导致性能显著下降。 1.noprealloc = false noscripting：是否禁止脚本引擎。默认是false：不禁止。ture：禁止\要是设置成true：运行一些脚本的时候会出现： 1.JavaScript execution failed: group command failed: { \”ok\” : 0,\”errmsg\” : \”server-side JavaScript execution is disabled\” } 1.#noscripting = true &lt;====&gt; noscripting = false notablescan：是否禁止表扫描操作。默认false：不禁止，ture：禁止 禁止要是执行表扫描会出现： 1.error: { \”\$err\” : \”table scans not allowed:test.emp\”, \”code\” :10111 } 可以动态修改设置： 1.db.adminCommand({setParameter:1, notablescan:false}) 1.#notablescan = true &lt;====&gt; notablescan = false nssize:命名空间的文件（即NS）的默认大小，默认16M，最大2G。\所有新创建的默认大小命名空间的文件（即NS）。此选项不会影响现有的命名空间的文件的大小。默认值是16M字节，最大大小为2GB。让小数据库不让浪费太多的磁盘空间，同时让大数据在磁盘上有连续的空间。 1.-rwxrwxrwx 1 mongodb zhoujy 16M 6月 11 14:44 test.0\2.-rwxrwxrwx 1 mongodb zhoujy 32M 6月 1 21:36 test.1\3.-rwxrwxrwx 1 mongodb zhoujy 16M 6月 11 14:44 test.ns\4.drwxr-xr-x 2 root root 4.0K 6月 10 11:57 _tmp 1.nssize = 16 profile：数据库分析等级设置。记录一些操作性能到标准输出或则指定的logpath的日志文件中，默认0:关闭。 1.级别 设置\2.0 关。无分析。\3.1 开。仅包括慢操作。\4.2 开。包括所有操作。 控制 Profiling 的开关和级别：2种\第一种是直接在启动参数里直接进行设置或则启动MongoDB时加上–profile=级别，其信息保存在生成的system.profile 中。 1.profile = 2 第二种是在客户端用db.setProfilingLevel(级别)命令来实时配置，其信息保存在生成的system.profile 中。 1.[initandlisten] creating profile collection: local.system.profile 1.&gt; db.setProfilingLevel(2)\2.{ \”was\” : 0, \”slowms\” : 100, \”ok\” : 1 }\3.&gt; db.getProfilingStatus()\4.{ \”was\” : 2, \”slowms\” : 100 } 默认情况下，mongod的禁用分析。数据库分析可以影响数据库的性能，因为分析器必须记录和处理所有的数据库操作。所以在需要的时候用动态修改就可以了。 slowms：记录profile分析的慢查询的时间，默认是100毫秒。具体同上。 1.slowms = 200 1.&gt; db.getProfilingStatus()\2.{ \”was\” : 2, \”slowms\” : 200 } quota：配额，默认false。是否开启配置每个数据库的最多文件数的限制。当为true则用quotaFiles来配置最多文件的数量。 1.quota = true quotaFiles：配额数量。每个数据库的数据文件数量的限制。此选项需要quota为true。默认为8。 1.quotaFiles = 8 rest： 默认false，设置为true，使一个简单的 REST API。 1.rest = true 设置为true，开启后，在MongoDB默认会开启一个HTTP协议的端口提供REST的服务（nohttpinterface=false），这个端口是你Server端口加上1000，即28017，默认的HTTP端口是数据库状态页面，（开启后，web页面的Commands行中的命令都可以点进去）。mongodb自带的REST，不支持增、删、改，同时也不支持 权限认证。\详细信息见这里和这里。\repair：修复数据库操作，默认是false。\设置为true时，启动后修复所有数据库，设置这个选项最好在命令行上，而不是在配置文件或控制脚本。如：\命令行修复： 1.&gt; db.repairDatabase(\’xxx\’)\2.{ \”ok\” : 1 }\3.&gt; db.repairDatabase()\4.{ \”ok\” : 1 } 启动时修复： 1.repair = true 1.root@m3:/var/log/mongodb# mongod –repair 启动时修复，需要关闭journal，否则报错: 1.Can\’t specify both –journal and –repair options. 并且启动时，用控制文件指定参数和配置文件里指定参数的方式进行修复之后，（修复信息见log），需要再禁用repair参数才能启用mongodb。\注意：mongod修复时，需要重写所有的数据库文件。如果在同一个帐号下不能运行修复，则需要运行chown修改数据库文件的权限。 repairpath：修复路径，默认是在dbpath路径下的_tmp 目录。 1.drwxr-xr-x 2 root root 4.0K 6月 11 20:23 _tmp smallfiles：是否使用较小的默认文件。默认为false，不使用。\设置为true，使用较小的默认数据文件大小。smallfiles减少数据文件的初始大小，并限制他们到512M，也减少了日志文件的大小，并限制他们到128M。\如果数据库很大，各持有少量的数据，会导致mongodb创建很多文件，会影响性能。 1.smallfiles = true syncdelay：刷写数据到日志的频率，通过fsync操作数据。默认60秒。 1.syncdelay = 60 默认就可以，不需要设置。不会对日志文件（journal files）有影响 警告：如果设置为0，SYNCDELAY不会同步到磁盘的内存映射文件。在生产系统上，不要设置这个值。 sysinfo：系统信息，默认false。 设置为true，mongod会诊断系统有关的页面大小，数量的物理页面，可用物理??页面的数量输出到标准输出。 1.Tue Jun 11 21:07:15.031 sysinfo:\2.Tue Jun 11 21:07:15.035 page size: 4096\3.Tue Jun 11 21:07:15.035 _SC_PHYS_PAGES: 256318\4.Tue Jun 11 21:07:15.035 _SC_AVPHYS_PAGES: 19895 当开启sysinfo参数的时候，只会打印上面的信息，不会启动mongodb的程序。所以要关闭该参数，才能开启mongodb。 upgrade:升级。默认为false。\当设置为true，指定DBPATH，升级磁盘上的数据格式的文件到最新版本。会影响数据库操作，更新元数据。大部分情况下，不需要设置该值。 traceExceptions：是否使用内部诊断。默认false。 1.traceExceptions = false quiet：安静模式。 1.quiet = true setParameter：2.4的新参数，指定启动选项配置。想设置多个选项则用一个setParameter选项指定，可以setParameter的参数请见这里，详情请见这里\声明setParameter设置在这个文件中，使用下面的格式： 1.setParameter = &lt;parameter&gt;=&lt;value&gt; 如配置文件里设置syncdelay： 1.setParameter = syncdelay= 55,notablescan = true,journalCommitInterval= 50,traceExceptions = true\Replication Options 复制选项 replSet：使用此设置来配置复制副本集。指定一个副本集名称作为参数，所有主机都必须有相同的名称作为同一个副本集。 oplogSize：指定的复制操作日志（OPLOG）的最大大小。mongod创建一个OPLOG的大小基于最大可用空间量。对于64位系统，OPLOG通常是5％的可用磁盘空间。\一旦mongod第一次创建OPLOG，改变oplogSize将不会影响OPLOG的大小。 fastsync：默认为false。在副本集下，设置为true，从一个dbpath里启用从库复制服务，该dbpath的数据库是主库的快照，可用于快速启用同步，否则的mongod将尝试执行初始同步。注意：如果数据不完全同步，mongod指定fastsync开启，secondary或slave与主永久不同步，这可能会导致显着的一致性问题。 replIndexPrefetch：2.2版本出现的新参数，默认是all。可以设置的值有：all,none, and_id_only。只能在副本集（replSet）中使用。默认情况下，secondary副本集的成员将加载所有索引到内存中（从OPLOG之前的操作有关的）。您可以修改此行为，使secondary只会加载_id索引。指定_id_或none，防止mongod的任何索引加载到内存。 Master/Slave Replication：主从复制的相关设置 master：默认为false，当设置为true，则配置当前实例作为主实例。 1.master = true slave：默认为false，当设置为true，则配置当前实例作为从实例。 1.slave = true source：默认为空，格式为：&lt;host&gt;&lt;:port&gt;。用于从实例的复制：设置从的时候指定该选项会让从复制指定主的实例 1.source = 127.0.0.1:30001 only：默认为空，用于从选项，指定一个数据库进行复制。 1.only = abc #只同步abc集合（库） slavedelay：设置从库同步主库的延迟时间，用于从设置，默认为0。 1.slavedelay = 60 #延迟60s同步主数据 autoresync：默认为false，用于从设置。是否自动重新同步。设置为true，如果落后主超过10秒，会强制从自动重新同步。如果oplogSize太小，此设置可能有问题。如果OPLOG大小不足以存储主的变化状态和从的状态变化之间的差异，这种情况下强制重新同步是不必要的。当设置autoresync选项设置为false，10分钟内从不会进行大于1次的自动重新同步。 1.autoresync = false]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[mongodb安装脚本/启动脚本/配置文件]]></title>
    <url>%2F2015%2F04%2F10%2F44%2F</url>
    <content type="text"><![CDATA[安装脚本 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动安装mongodb和初始化配置#缺省的配置如下 logdir=/data/log/shell #日志路径log=$logdir/shell.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录random_time=$(date +%Y%m%d_%H%M%S)PWD=`pwd`mongodb_pakges="$PWD/mongodb-linux-x86_64-2.4.9.tgz" mongodb_conf=$PWD/mongodb.confmongodb_init=$PWD/mongodbdatef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125; print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;if [[ ! -f $mongodb_conf ]];thenprint_log "mongodb配置文件不存在,退出:$mongodb_conf"exitelse. $mongodb_conffi install()&#123;if [[ -d /usr/local/mongodb ]];thenprint_log "mongodb已经安装,请不要再重复安装:/usr/local/mongodb"exitfiprint_log "解压文件中,请稍后..."tar -zxf $mongodb_pakges -C /usr/local/mv /usr/local/$(echo $mongodb_pakges|awk -F'/' '&#123;print $NF&#125;'|sed "s/.tgz//g") /usr/local/mongodbif [[ -d /usr/local/mongodb ]];thenprint_log "mongodb已经安装成功:/usr/local/mongodb"elseprint_log "mongodb已经安装失败:/usr/local/mongodb"fiif [[ -d $dbpath ]];thenprint_log "mongodb: 数据目录:$dbpath已经存在"elsemkdir -p $dbpath fi lastname=$(echo "$logpath" |awk -F'/' '&#123;print $NF &#125;')mongodblog=$(echo $logpath | sed "s/$lastname//g")if [[ -d $mongodblog ]];thenprint_log "mongodb: 日志目录:$mongodblog已经存在"elsemkdir -p $mongodblogfi if [[ ! -d /usr/local/mongodb/conf ]];thenmkdir -p /usr/local/mongodb/confcp $mongodb_conf /usr/local/mongodb/conffiprofile_num=$(cat /etc/profile |grep mongodb |wc -l)if [[ $profile_num -eq 0 ]];thenecho "MONGODBPATH=/usr/local/mongodb/bin:\$PATH" &gt;&gt; /etc/profileecho "export MONGODBPATH" &gt;&gt; /etc/profilefiif [[ ! -f $mongodb_init ]];thenprint_log "mongodb: 启动脚本已经存在."elsecp $mongodb_init /etc/init.d/chmod a+x /etc/init.d/mongodbchkconfig --add mongodbchkconfig mongodb onfi print_log "初始化配置完成."print_log "数据目录为:$dbpath 日志文件为:$mongodblog"print_log "配置目录为:/usr/local/mongodb/conf"print_log "启动脚本为:/etc/init.d/$mongodb_init"&#125; install 启动脚本 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384#!/bin/sh # chkconfig: 2345 93 18 # author:QingFeng # description:MongoDB(MongoDB-2.4.9) #默认参数设置#mongodb 家目录 MONGODB_HOME=/usr/local/mongodb#mongodb 启动命令 MONGODB_BIN=$MONGODB_HOME/bin/mongod#mongodb 配置文件MONGODB_CONF=$MONGODB_HOME/conf/mongodb.conf#mongodb PIDMONGODB_PID=/var/run/mongo.pid#最大文件打开数量限制SYSTEM_MAXFD=65535#mongodb 名字 MONGODB_NAME="mongodb". /etc/rc.d/init.d/functionsif [ ! -f $MONGODB_BIN ]then echo "$MONGODB_NAME startup: $MONGODB_BIN not exists! " exitfistart()&#123; ulimit -HSn $SYSTEM_MAXFD $MONGODB_BIN --config="$MONGODB_CONF" ret=$? if [ $ret -eq 0 ]; then action $"Starting $MONGODB_NAME: " /bin/true else action $"Starting $MONGODB_NAME: " /bin/false fi &#125;stop()&#123; PID=$(ps aux |grep "$MONGODB_NAME" |grep "$MONGODB_CONF" |grep -v grep |wc -l) if [[ $PID -eq 0 ]];then action $"Stopping $MONGODB_NAME: " /bin/false exit fi kill -HUP `cat $MONGODB_PID` ret=$? if [ $ret -eq 0 ]; then action $"Stopping $MONGODB_NAME: " /bin/true rm -f $MONGODB_PID else action $"Stopping $MONGODB_NAME: " /bin/false fi&#125;restart() &#123; stop sleep 2 start&#125;case "$1" in start) start ;; stop) stop ;; status) status $prog ;; restart) restart ;; *) echo $"Usage: $0 &#123;start|stop|status|restart&#125;"esac mongodb配置文件 123456789101112131415161718dbpath=/data/db #数据目录存在位置logpath=/data/logs/mongodb/mongodb.log #日志文件存放目录port=27017 #端口fork=true #以守护程序的方式启用，即在后台运行#auth=true #开始认证verbose=truevvvv=true #启动verbose冗长信息，它的级别有 vv~vvvvv，v越多级别越高，在日志文件中记录的信息越详细.maxConns=20000 #默认值：取决于系统（即的ulimit和文件描述符）限制。MongoDB中不会限制其自身的连接。logappend=true #写日志的模式:设置为true为追加。pidfilepath=/var/run/mongo.pid#cpu=true #设置为true会强制mongodb每4s报告cpu利用率和io等待，把日志信息写到标准输出或日志文件。directoryperdb=ture #数据目录存储模式,如果直接修改原来的数据会不见了#nohttpinterface=false #28017 端口开启的服务。默认false，支持#notablescan=false#不禁止表扫描操作profile=0 #数据库分析等级设置,0 关 2 开。包括所有操作。 1 开。仅包括慢操作.slowms=200 #记录profile分析的慢查询的时间，默认是100毫秒.quiet=true syncdelay=60 #刷写数据到日志的频率，通过fsync操作数据。默认60秒]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[笔记本电脑启用虚拟WIFI共享上网]]></title>
    <url>%2F2015%2F03%2F23%2F45%2F</url>
    <content type="text"><![CDATA[方案: 笔记本电脑启用虚拟WIFI共享上网 1.确定是否你的笔记本是否支持“启动承载网络” 操作方法: cmd执行-&gt;: netsh wlan show drivers 下图代表可以,如果是否代表不可以 2.开始启动虚拟wifi 操作方法: cmd执行-&gt;:netsh wlan set hostednetwork mode=allowssid=baobei key=baobei2015 （ssid是将来无线连接的名字和baobei2015就是密码了【8位以上】，大家可以设自己习惯的ssid，将来搜索无线网络，就是搜这个名字）。 3.更改虚拟wifi名字,开启共享上网 操作方法: ①执行上面的语句后，可以查看“网络共享中心”-“更改适配器设置”，里面会多出一个“MicrosoftVirtual WiFi MiniportAdapter”，你也可以重命名这个网络连接，当然这个对于网络连接是没有任何影响的，我重命名改成了VirtualWiFi，主要是便于识别。 ②打开“网络共享中心”-“更改适配器设置”【在左侧的栏里面】-找到你现在上网用的连接，右键属性，点击共享的标签，勾选第一个选项卡【如下图】，在下面的输入框点击，弹出列表，选择你的MicrosoftVirtual WiFi MiniportAdapter网络连接，我这里刚刚重命名了，所以选择Virtual WiFi，确定。 4.启动无线网 操作方法: cmd执行-&gt;:netsh wlan start hostednetwork]]></content>
      <categories>
        <category>Windows</category>
      </categories>
      <tags>
        <tag>Windows</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[秘钥认证用户自动控制]]></title>
    <url>%2F2015%2F03%2F18%2F46%2F</url>
    <content type="text"><![CDATA[先上图 再上代码 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动添加秘钥认证用户#缺省的配置如下logdir=/data/log/shell #日志路径log=$logdir/shell.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录random_time=$(date +%Y%m%d_%H%M%S)datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125;print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;#自动生成keyaddautoKey()&#123;if [[ ! -f /usr/bin/expect ]];thenprint_log "$FUNCNAME():不存在expect函数:开始安装."yum install tcl-devel tcl expect -y -qprint_log "$FUNCNAME():expect函数:安装完成."fimkdir -p /tmp/ssh_$random_timecd /tmp/ssh_$random_timeexpect -c " spawn /usr/bin/ssh-keygen -t rsa set timeout -1 expect \"\*id_rsa)\*:\" send \"$1\r\" expect \"\*no passphrase)\*:\" send \"$1\r\" expect \"\*again\*:\" send \"$1\r\" expect eof " &gt; /dev/nullnum=$(ls /tmp/ssh_$random_time/$1* -l |wc -l)if [[ $num -eq 2 ]];thenprint_log "$FUNCNAME():该用户$1秘钥自动生成完成,路径: /tmp/ssh_$random_time"elseprint_log "$FUNCNAME():\033[31m该用户$1秘钥自动生成失败,退出\033[0m"exitfi&#125;#添加用户addUser()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():\033[31m用户名不能为空\033[0m"exitfistrlength=$(expr length $1)if [[ $strlength -lt 5 ]];thenprint_log "$FUNCNAME():\033[31m用户名的长度最少大于4,退出\033[0m"exitfiUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;' |grep "$1")if [[ -z $User ]];thenprint_log "$FUNCNAME():不存在非系统用户:$1,开始添加用户操作."adduser $1 -g 10[[ -d /home/$1/.ssh ]] || mkdir /home/$1/.ssh addautoKey $1cp /tmp/ssh_$random_time/$1.pub /home/$1/.ssh/authorized_keys chmod 600 /home/$1/.ssh/authorized_keyschown $1:wheel /home/$1/ -Rcp /etc/ssh/sshd_config /etc/ssh/sshd_config_$(date +%Y%m%d_%H%M%S)sshdUser=$(cat /etc/ssh/sshd_config |grep "$1")if [[ -z $sshdUser ]];thensed -i "s/AllowUsers/AllowUsers $1/" /etc/ssh/sshd_config/etc/init.d/sshd restartprint_log "$FUNCNAME():更新sshd_config文件并重启sshd完成."elseprint_log "$FUNCNAME():sshd_config文件中已经存在$1."fielse print_log "$FUNCNAME():已经存在非系统用户:$1,请确认后在添加."fi &#125;#查找用户lookUp()&#123;loginUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;')print_log "$FUNCNAME():如下用户拥有登陆系统权限:\n\033[32m$loginUser\033[0m"&#125;#删除用户deleteUser()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():\033[31m用户名不能为空\033[0m"exitfiUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;' |grep "$1")if [[ ! -z $User ]];thenprint_log "$FUNCNAME():存在非系统用户:$1"elseprint_log "$FUNCNAME():\033[31m不存在非系统用户:$1,退出\033[0m"exitfi userdel -rf $1if [[ $? -eq 0 ]];thenprint_log "$FUNCNAME():删除非系统用户:$1成功."elseprint_log "$FUNCNAME():\033[31m删除非系统用户:$1失败.\033[0m"ficp /etc/ssh/sshd_config /etc/ssh/sshd_config_$random_timesed -i "s/$1//g" /etc/ssh/sshd_config /etc/init.d/sshd restartprint_log "$FUNCNAME():更新sshd_config文件并重启sshd完成."&#125;case $1 in add) addUser $2;; look) lookUp;; delete) deleteUser $2;; *) echo -e "秘钥认证用户自动控制\n用法示例: \n1.添加/删除秘钥认证用户: ./account.class.sh add/delete 用户名 \n2.查找可以登陆的用户 ./account.class.sh look";; esac 改进版,检测系统是否添加key认证,无则自动添加,批量添加key认证用户 上图：\ 批量添加用户图： 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动添加秘钥认证用户#缺省的配置如下logdir=/data/log/shell #日志路径log=$logdir/shell.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录random_time=$(date +%Y%m%d_%H%M%S)#定义默认公钥default_publicKey="ssh-dss CCCCB3NzaC1kc3MAAACBAJRKD+AyqOD2gtLSAPpbbMEy/VrMW8Z8fof1nyKA9OppiUWUWdVL9iJGDdBzvVB3hb9KZYX1bsns77KrD/VB+8jsCe/62rrsUmxJoUwvWyF2B+cvboxwe5cdXyTawt1bAMHNq8jiWrgSDaR7bplFXD3I6lwYk89I+ofxafXxmZE7AAAAFQCay8NRvgNMxkbExxhMLeRZBK2xpwAAAIEAhUpYCf0STqTUcTSTabQDmfizywG7+ZFSvppJCMrWdobG/+rZ61tN2xGWK4zRP13NJOVcIDaXsQwhhuZbGD8d1tEwGqldBAlTsouJWGiWPMJPhUfjKEFTIHn8ug2zDP/vE7yNgiuMalhn+Fglt+AMG78tiOCn1P7kYVjPeGklr8AAAACAWm3qmqYOiTIMtShfmcIJc06XOPPOjxXzwntN+c8rmy+gZbI6wx4vRwYbldaduMtPn7Q29BqJfcCAy/P7ymVyrX/a2ksWehddk7HdyUHnq9WAX1+MxE4BZq7nV4MHD3Fyn8bay+D76BgQdZjTta3dNXwbA5WdmJnZi68Bk5ZXcjM="#定义whell组可以无密码登陆default_Wheel="%wheel ALL=(ALL) NOPASSWD: ALL"#定义sshd配置文件default_user="zhangsan"default_sshdConfig="Protocol 2SyslogFacility AUTHPRIVStrictModes noRSAAuthentication yesPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keysPermitEmptyPasswords noPasswordAuthentication noChallengeResponseAuthentication noGSSAPIAuthentication yesGSSAPICleanupCredentials yesUsePAM yesAcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT AcceptEnv LC_IDENTIFICATION LC_ALLX11Forwarding yesUseDNS noSubsystem sftp /usr/libexec/openssh/sftp-serverAllowUsers $default_user"datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125;print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho -e "[ $(datef) ] $1"fi&#125;#自动生成keyaddautoKey()&#123;if [[ ! -f /usr/bin/expect ]];thenprint_log "$FUNCNAME():不存在expect函数:开始安装."yum install tcl-devel tcl expect -y -qprint_log "$FUNCNAME():expect函数:安装完成."fimkdir -p /tmp/ssh_$random_timecd /tmp/ssh_$random_timeexpect -c " spawn /usr/bin/ssh-keygen -t rsa set timeout -1 expect \"\*id_rsa)\*:\" send \"$1\r\" expect \"\*no passphrase)\*:\" send \"$1\r\" expect \"\*again\*:\" send \"$1\r\" expect eof " &gt; /dev/nullnum=$(ls /tmp/ssh_$random_time/$1* -l |wc -l)if [[ $num -eq 2 ]];thenprint_log "$FUNCNAME():该用户$1秘钥自动生成完成,路径: /tmp/ssh_$random_time"elseprint_log "$FUNCNAME():\033[31m该用户$1秘钥自动生成失败,退出\033[0m"exitfi&#125;#添加用户addUser()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():\033[31m用户名不能为空\033[0m"exitfistrlength=$(expr length $1)if [[ $strlength -lt 5 ]];thenprint_log "$FUNCNAME():\033[31m用户名的长度最少大于4,退出\033[0m"exitfiUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;' |grep "$1")if [[ -z $User ]];thenprint_log "$FUNCNAME():不存在非系统用户:$1,开始添加用户操作."adduser $1 -g 10addautoKey $1[[ -d /home/$1/.ssh ]] || mkdir -p /home/$1/.ssh cp /tmp/ssh_$random_time/$1.pub /home/$1/.ssh/authorized_keys chmod 600 /home/$1/.ssh/authorized_keyschown $1:wheel /home/$1/ -Rcp /etc/ssh/sshd_config /etc/ssh/sshd_config_$(date +%Y%m%d_%H%M%S)sshdUser=$(cat /etc/ssh/sshd_config |egrep -v "^$|^#" |grep "$1")if [[ -z $sshdUser ]];thensed -i "s/AllowUsers/AllowUsers $1/" /etc/ssh/sshd_config/etc/init.d/sshd restartprint_log "$FUNCNAME():更新sshd_config文件并重启sshd完成."elseprint_log "$FUNCNAME():sshd_config文件中已经存在$1."fielse print_log "$FUNCNAME():已经存在非系统用户:$1,请确认后在添加."fi &#125;#查找用户lookUp()&#123;loginUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;')print_log "$FUNCNAME():如下用户拥有登陆系统权限:\n\033[32m$loginUser\033[0m"&#125;#删除用户deleteUser()&#123;if [[ $1 == "" ]];thenprint_log "$FUNCNAME():\033[31m用户名不能为空\033[0m"exitfiUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;' |grep "$1")if [[ ! -z $User ]];thenprint_log "$FUNCNAME():存在非系统用户:$1"elseprint_log "$FUNCNAME():\033[31m不存在非系统用户:$1,退出\033[0m"exitfi userdel -rf $1if [[ $? -eq 0 ]];thenprint_log "$FUNCNAME():删除非系统用户:$1成功."elseprint_log "$FUNCNAME():\033[31m删除非系统用户:$1失败.\033[0m"ficp /etc/ssh/sshd_config /etc/ssh/sshd_config_$random_timesed -i "s/$1//g" /etc/ssh/sshd_config /etc/init.d/sshd restartprint_log "$FUNCNAME():更新sshd_config文件并重启sshd完成."&#125;#检查key认证checkUser()&#123;if [[ $default_user == "" ]];thenprint_log "$FUNCNAME():\033[31m用户名不能为空\033[0m"exitfistrlength=$(expr length $default_user)if [[ $strlength -lt 5 ]];thenprint_log "$FUNCNAME():\033[31m用户名的长度最少大于4,退出\033[0m"exitfiUser=$(cat /etc/passwd |grep -v "nologin" |awk -F':' '&#123;if ($3&gt; 500) print $1 &#125;' |grep "$default_user")if [[ -z $User ]];thenprint_log "$FUNCNAME():不存在非系统用户:$default_user,开始添加用户操作."adduser $default_user -g 10[[ -d /home/$default_user/.ssh ]] || mkdir /home/$default_user/.ssh echo $default_publicKey &gt; /home/$default_user/.ssh/authorized_keys chmod 600 /home/$default_user/.ssh/authorized_keyschown $default_user:wheel /home/$default_user/ -Rcp /etc/ssh/sshd_config /etc/ssh/sshd_config_$(date +%Y%m%d_%H%M%S)sshdUser=$(cat /etc/ssh/sshd_config |egrep -v "^$|^#"|grep "$default_user")if [[ -z $sshdUser ]];thenecho -e "$default_sshdConfig" &gt; /etc/ssh/sshd_configsed -i "s/^$//g" /etc/ssh/sshd_config check_suders=$(cat /etc/sudoers |egrep -v "^#|^$"|grep "%wheel")if [[ -z $check_suders ]];thenecho -e "$default_Wheel" &gt;&gt; /etc/sudoersfi /etc/init.d/sshd restartprint_log "$FUNCNAME():添加key认证,更新sshd_config文件并重启sshd完成."elseprint_log "$FUNCNAME():sshd_config文件中已经存在$default_user."fielse check_sshdnum=1check_sudersnum=1check_sshd=$(cat /etc/ssh/sshd_config |egrep -v "^#|^$" |grep "$default_user")if [[ -z $check_sshd ]];thencheck_sshdnum=0print_log "已经添加$default_user用户,但是没有配置sshd_config"ficheck_suders=$(cat /etc/sudoers |egrep -v "^#|^$" |grep "wheel" |grep "NOPASSWD")if [[ -z $check_suders ]];thencheck_sudersnum=0print_log "已经添加$default_user用户,但是没有配置sudoers"fi if [[ $check_sshdnum -ne 0 &amp;&amp; $check_sudersnum -ne 0 ]];thenprint_log "该服务器已经配置秘钥认证."fifi&#125;case $1 in add) addUser $2;; look) lookUp;; delete) deleteUser $2;; check) checkUser ;; *) echo -e "秘钥认证用户自动控制\n用法示例: \n1.添加/删除秘钥认证用户: ./account.class.sh add/delete 用户名 \n2.查找可以登陆的用户 ./account.class.sh look\n3.检测系统是否是key认证,不是则添加key认证 ./account.class.sh check\n(默认增加一个[$default_user]的认证用户)";; esac]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Converting slapd.conf to a Directory Based Configu]]></title>
    <url>%2F2015%2F03%2F13%2F47%2F</url>
    <content type="text"><![CDATA[OpenLDAP 2.4OpenLDAP 2.4 provides some great new features over 2.3. Notableamong them are the ability to store configuration data in the directoryand change values on the fly. Adding aSchema Converting slapd.conf to a Directory Based ConfigurationOpenLDAP 2.4 maintains an LDIF-based online directory in/etc/openldap/slapd.d/ (or otherwise specified location). In order touse this, you must seed the directory one of two ways. One way is toconvert an existing slapd.conf file, which is illustrated below. Notethat to access the newly minted cn=config, you should create an entry inyour slapd.conf to provide a root password to this entry, or otherwiseprovide a useful ACL/ACI which gives a user access. To convert a standard slapd.conf file to the new format, issue thefollowing command (re: man slapd-config): slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d Note that the directory /etc/openldap/slapd.d must exist prior to thiscommand successfully completing. After importing the config file, start the OpenLDAP server: /etc/init.d/ldap start Verify that the server is running: ldapsearch -x -b ‘’ -s base ‘(objectclass=*)’ namingContexts After validating that the server will start and stop, import some datawith an LDIF file: slapadd -l &lt;file&gt;.ldif When attempting this, I get an error about an invalid attribute for an objectclass: # slapadd -l slapcat.out str2entry: invalid value for attributeType objectClass #1 (syntax 1.3.6.1.4.1.1466.115.121.1.38) slapadd: could not parse entry (line=1) Missing a schema, had to add cosine schema to get this to work. When attempting to add the schema ldif, I get this error: # ldapadd -x -H ldap://locahost -D &quot;cn=manager,dc=example,dc=org&quot; -W -f core.ldif Enter LDAP Password: ldap_sasl_bind(SIMPLE): Can&apos;t contact LDAP server (-1) I switched back to using the slapd.conf file to get this to work, and emptying out the /var/lib/openldap-data directory, reattempting the slapadd, I get the following: # slapadd -l backup.ldif bdb_db_open: warning - no DB_CONFIG file found in directory /var/lib/openldap-data: (2). Expect poor performance for suffix &quot;dc=example,dc=org&quot;. &lt;= str2entry: str2ad(pwdHistory): attribute type undefined slapadd: could not parse entry (line=79) Missing ppolicy overlay. `` Adding some schemas: # ldapadd -x -H ldap://localhost/ -D &quot;cn=config&quot; -W -f schema/archive/cosine.ldif Enter LDAP Password: adding new entry &quot;cn=cosine,cn=schema,cn=config&quot; # ldapadd -x -H ldap://localhost/ -D &quot;cn=config&quot; -W -f schema/archive/inetorgperson.ldif Enter LDAP Password: adding new entry &quot;cn=inetorgperson,cn=schema,cn=config&quot; # ldapadd -x -H ldap://localhost/ -D &quot;cn=config&quot; -W -f schema/archive/nis.ldif Enter LDAP Password: adding new entry &quot;cn=nis,cn=schema,cn=config&quot; # ldapadd -x -H ldap://localhost/ -D &quot;cn=config&quot; -W -f schema/archive/openldap.ldif Enter LDAP Password: adding new entry &quot;cn=openldap,cn=schema,cn=config&quot; `` Note that you cannot (as of version 2.4.7) use slapindex to generate the cn=config configuration, use slaptest: # cd /etc/openldap # mkdir slapd.d # /usr/sbin/slapindex -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d # echo $? 0 Program exits without error. # ls /etc/openldap/slapd.d Subsequently, running this command immediately after generates the appropriate cn=config: # slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d config file testing succeeded # ll slapd.d total 8 drwxr-x--- 4 root root 4096 Jan 10 13:07 cn=config -rw------- 1 root root 1097 Jan 10 13:07 cn=config.ldif I have filed an ITS with the OpenLDAP project for this (ITS#5321). `` Querying cn=configA sample query: ldapsearch -x -H ldap://localhost/ -D &quot;cn=config&quot; -b &apos;cn=config&apos; -W cn=config Enter LDAP Password: # extended LDIF # # LDAPv3 # base &lt;cn=config&gt; with scope subtree # filter: cn=config # requesting: ALL # # config dn: cn=config objectClass: olcGlobal cn: config olcConfigFile: /etc/openldap/slapd.conf.WORKING olcConfigDir: /etc/openldap/slapd.d olcArgsFile: /var/run/openldap/run/slapd.args olcAttributeOptions: lang- olcAuthzPolicy: none olcConcurrency: 0 olcConnMaxPending: 100 olcConnMaxPendingAuth: 1000 olcGentleHUP: FALSE olcIdleTimeout: 0 olcIndexSubstrIfMaxLen: 4 olcIndexSubstrIfMinLen: 2 olcIndexSubstrAnyLen: 4 olcIndexSubstrAnyStep: 2 olcLocalSSF: 71 olcLogLevel: Any olcPidFile: /var/run/openldap/run/slapd.pid olcReadOnly: FALSE olcSaslSecProps: noplain,noanonymous olcSockbufMaxIncoming: 262143 olcSockbufMaxIncomingAuth: 16777215 olcThreads: 16 olcToolThreads: 1 # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 `` Query cn=schema: ldapsearch -x -H ldap://localhost/ -D &quot;cn=config&quot; -b &apos;cn=schema,cn=config&apos; -W `` Query cn=config for olcDatabase entries: Note that this searches for the second database, which is of type bdb. ldapsearch -x -H ldap://localhost/ -D &quot;cn=config&quot; -b &apos;olcDatabase={1}bdb,cn=config&apos; -W -LLL ``]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[curl命令参数以及curl监控web是否OK自动重启应用脚本示例]]></title>
    <url>%2F2015%2F03%2F12%2F48%2F</url>
    <content type="text"><![CDATA[[先上curl监控web自动重启脚本(这个一个接口调用,只考虑返回码200的情况)] 123456789101112131415161718192021222324252627282930313233343536#!/bin/bash check_ip="x.x.x.x"check_port="6500"logdir="/data/log/check/"LOG="$logdir/check_interface.log"#指定json格式post的方式去提交到服务器#check_status=$(curl -i -H 'content-type: application/json' -X POST -d '&#123;"imei": "123456","plate": "OS_ANDROID","brand": "sumsung"&#125;' -w -I -m 10 -o /dev/null -s -w %&#123;http_code&#125; http://$check_ip:$check_port/online/agentinfo/732459/MTQxNTYzNTI4OA==bW9i2d2312e82cf87e12easdasdasda6150)#默认get方式去提交到服务器check_status=$(curl -o /dev/null -s -w %&#123;http_code&#125; http://$check_ip:$check_port/verdict/session/LSGJA5SSDD55974/latest/result)datef() &#123; date "+%Y/%m/%d %H:%M:%S" ; &#125;print_to_log() &#123; echo "[$(datef)] $1" &gt;&gt; $LOG ; &#125;[[ -d $logdir ]] || mkdir -p $logdirif [[ $check_status -ne 200 ]];thenprint_to_log "xx服务已经停止响应."cd /data/www/apps/data-camp/bin sh boxrun stoppid=$(ps aux |grep jrdt-online |grep -v grep |wc -l)if [[ $pid -eq 0 ]];thenprint_to_log "=&gt;1.xx服务正常停止"sh boxrun start pidnext=$(ps aux |grep jrdt-online |grep -v grep |wc -l) if [[ $pidnext -ne 0 ]];then /usr/bin/cagent_tools alarm "生产环境:xx服务停止响应,重启OK" print_to_log "=&gt;2.xx服务启动正常!" else /usr/bin/cagent_tools alarm "生产环境:xx服务停止响应,重启不OK,请马上登陆服务器查看." print_to_log "&lt;=&gt;2.xx服务启动失败!" fi fielse print_to_log "xx服务正常."fi Curl命令使用示例[] 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051##基本用法（配合sed/awk/grep） $curl http: //s.worthsee.com##下载保存 $curl http://s.worthsee.com &gt; index.html $curl -o index.html http://s.worthsee.com $curl -O http://s.worthsee.com/target.tar.gz##通过代理 $curl -x 123.45.67.89:1080 -o page.html http://s.worthsee.com##保存cookie $curl -x 123.45.67.89:1080 -o page1.html -D cookie0001.txt http://s.worthsee.com##使用cookie $curl -x 123.45.67.89:1080 -o page1.html -D cookie0002.txt -b cookie0001.txt http://s.worthsee.com##模仿浏览器 $curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x123.45.67.89:1080 -o page.html -D cookie0001.txt http://s.worthsee.com##伪造referer $curl -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -x123.45.67.89:1080 -e"mail.worthsee.com" -o page.html -D cookie0001.txt http://s.worthsee.com##循环下载 $curl -O http://s.worthsee.com/~zzh/screen[1-10].JPG##循环（匹配）下载 $curl -O http://s.worthsee.com/~&#123;zzh,nick&#125;/[001-201].JPG # &gt;like zzh/001.JPG##循环（引用）下载 $curl -o #2_#1.jpg http://s.worthsee.com/~&#123;zzh,nick&#125;/[001-201].JPG # like &gt;001_zzh.jpg##断点续传 $curl -c -O http://s.worthsee.com/~zzh/screen1.JPG##分块下载 $curl -r 0 -10240 -o "zhao.part1" http://s.worthsee.com/~zzh/zhao1.mp3 &amp;\ $curl -r 10241 -20480 -o "zhao.part1" http://s.worthsee.com/~zzh/zhao1.mp3 &amp;\ $curl -r 20481 -40960 -o "zhao.part1" http://s.worthsee.com/~zzh/zhao1.mp3 &amp;\ $curl -r 40961 - -o "zhao.part1" http://s.worthsee.com/~zzh/zhao1.mp3 ... $cat zhao.part* &gt; zhao.mp3##GET 上传 $curl http://www.worthsee.com/login.cgi?user=nickwolfe&amp;password=12345##POST 上传 $curl -d "user=nickwolfe&amp;password=12345" http://www.worthsee.com/login.cgi##POST 文件上传 $curl -F upload=@localfile -F btn_name=btn_value http://s.worthsee.com/~zzh/up_file.cgi Curl命令参数详解 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113-a/--append 上传文件时，附加到目标文件 -A/--user-agent &lt;string&gt; 设置用户代理发送给服务器 - anyauth 可以使用“任何”身份验证方法 -b/--cookie &lt;name=string/file&gt; cookie字符串或文件读取位置 - basic 使用HTTP基本验证 -B/--use-ascii 使用ASCII /文本传输 -c/--cookie-jar &lt;file&gt; 操作结束后把cookie写入到这个文件中 -C/--continue-at &lt;offset&gt; 断点续转 -d/--data &lt;data&gt; HTTP POST方式传送数据 --data-ascii &lt;data&gt; 以ascii的方式post数据 --data-binary &lt;data&gt; 以二进制的方式post数据 --negotiate 使用HTTP身份验证 --digest 使用数字身份验证 --disable-eprt 禁止使用EPRT或LPRT --disable-epsv 禁止使用EPSV -D/--dump-header &lt;file&gt; 把header信息写入到该文件中 --egd-file &lt;file&gt; 为随机数据(SSL)设置EGD socket路径 --tcp-nodelay 使用TCP_NODELAY选项 -e/--referer 来源网址 -E/--cert &lt;cert[:passwd]&gt; 客户端证书文件和密码 (SSL) --cert-type &lt;type&gt; 证书文件类型 (DER/PEM/ENG) (SSL) --key &lt;key&gt; 私钥文件名 (SSL) --key-type &lt;type&gt; 私钥文件类型 (DER/PEM/ENG) (SSL) --pass &lt;pass&gt; 私钥密码 (SSL) --engine &lt;eng&gt; 加密引擎使用 (SSL). "--engine list" for list --cacert &lt;file&gt; CA证书 (SSL) --capath &lt;directory&gt; CA目录 (made using c_rehash) to verify peer against (SSL) --ciphers &lt;list&gt; SSL密码 --compressed 要求返回是压缩的形势 (using deflate or gzip) --connect-timeout &lt;seconds&gt; 设置最大请求时间 --create-dirs 建立本地目录的目录层次结构 --crlf 上传是把LF转变成CRLF -f/--fail 连接失败时不显示http错误 --ftp-create-dirs 如果远程目录不存在，创建远程目录 --ftp-method [multicwd/nocwd/singlecwd] 控制CWD的使用 --ftp-pasv 使用 PASV/EPSV 代替端口 --ftp-skip-pasv-ip 使用PASV的时候,忽略该IP地址 --ftp-ssl 尝试用 SSL/TLS 来进行ftp数据传输 --ftp-ssl-reqd 要求用 SSL/TLS 来进行ftp数据传输 -F/--form &lt;name=content&gt; 模拟http表单提交数据 -form-string &lt;name=string&gt; 模拟http表单提交数据 -g/--globoff 禁用网址序列和范围使用&#123;&#125;和[] -G/--get 以get的方式来发送数据 -h/--help 帮助 -H/--header &lt;line&gt;自定义头信息传递给服务器 --ignore-content-length 忽略的HTTP头信息的长度 -i/--include 输出时包括protocol头信息 -I/--head 只显示文档信息 从文件中读取-j/--junk-session-cookies忽略会话Cookie - 界面&lt;interface&gt;指定网络接口/地址使用 - krb4 &lt;级别&gt;启用与指定的安全级别krb4 -j/--junk-session-cookies 读取文件进忽略session cookie --interface &lt;interface&gt; 使用指定网络接口/地址 --krb4 &lt;level&gt; 使用指定安全级别的krb4 -k/--insecure 允许不使用证书到SSL站点 -K/--config 指定的配置文件读取 -l/--list-only 列出ftp目录下的文件名称 --limit-rate &lt;rate&gt; 设置传输速度 --local-port&lt;NUM&gt; 强制使用本地端口号 -m/--max-time &lt;seconds&gt; 设置最大传输时间 --max-redirs &lt;num&gt; 设置最大读取的目录数 --max-filesize &lt;bytes&gt; 设置最大下载的文件总量 -M/--manual 显示全手动 -n/--netrc 从netrc文件中读取用户名和密码 --netrc-optional 使用 .netrc 或者 URL来覆盖-n --ntlm 使用 HTTP NTLM 身份验证 -N/--no-buffer 禁用缓冲输出 -o/--output 把输出写到该文件中 -O/--remote-name 把输出写到该文件中，保留远程文件的文件名 -p/--proxytunnel 使用HTTP代理 --proxy-anyauth 选择任一代理身份验证方法 --proxy-basic 在代理上使用基本身份验证 --proxy-digest 在代理上使用数字身份验证 --proxy-ntlm 在代理上使用ntlm身份验证 -P/--ftp-port &lt;address&gt; 使用端口地址，而不是使用PASV -Q/--quote &lt;cmd&gt;文件传输前，发送命令到服务器 -r/--range &lt;range&gt;检索来自HTTP/1.1或FTP服务器字节范围 --range-file 读取（SSL）的随机文件 -R/--remote-time 在本地生成文件时，保留远程文件时间 --retry &lt;num&gt; 传输出现问题时，重试的次数 --retry-delay &lt;seconds&gt; 传输出现问题时，设置重试间隔时间 --retry-max-time &lt;seconds&gt; 传输出现问题时，设置最大重试时间 -s/--silent静音模式。不输出任何东西 -S/--show-error 显示错误 --socks4 &lt;host[:port]&gt; 用socks4代理给定主机和端口 --socks5 &lt;host[:port]&gt; 用socks5代理给定主机和端口 --stderr &lt;file&gt; -t/--telnet-option &lt;OPT=val&gt; Telnet选项设置 --trace &lt;file&gt; 对指定文件进行debug --trace-ascii &lt;file&gt; Like --跟踪但没有hex输出 --trace-time 跟踪/详细输出时，添加时间戳 -T/--upload-file &lt;file&gt; 上传文件 --url &lt;URL&gt; Spet URL to work with -u/--user &lt;user[:password]&gt;设置服务器的用户和密码 -U/--proxy-user &lt;user[:password]&gt;设置代理用户名和密码 -v/--verbose -V/--version 显示版本信息 -w/--write-out [format]什么输出完成后 -x/--proxy &lt;host[:port]&gt;在给定的端口上使用HTTP代理 -X/--request &lt;command&gt;指定什么命令 -y/--speed-time 放弃限速所要的时间。默认为30 -Y/--speed-limit 停止传输速度的限制，速度时间'秒 -z/--time-cond 传送时间设置 -0/--http1.0 使用HTTP 1.0 -1/--tlsv1 使用TLSv1（SSL） -2/--sslv2 使用SSLv2的（SSL） -3/--sslv3 使用的SSLv3（SSL） --3p-quote like -Q for the source URL for 3rd party transfer --3p-url 使用url，进行第三方传送 --3p-user 使用用户名和密码，进行第三方传送 -4/--ipv4 使用IP4 -6/--ipv6 使用IP6 -#/--progress-bar 用进度条显示当前的传送状态]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[CMD命令下修改和查看ip地址,DNS,网关]]></title>
    <url>%2F2015%2F03%2F12%2F49%2F</url>
    <content type="text"><![CDATA[[ ]设置IP、DNS、网关 1234&gt;netsh interface ip set address name="本地连接" source=static addr=192.168.132.5 mask=255.255.255.0&gt;netsh interface ip set address name="本地连接" gateway=192.168.132.1 gwmetric=0&gt;netsh interface ip set dns name="本地连接" source=static addr=192.168.132.1 register=PRIMARY&gt;netsh interface ip set wins name="本地连接" source=static addr=none [ ]查看IP、DNS、网关 1&gt;netsh interface ip show address **\]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[redis集群（主从配置）]]></title>
    <url>%2F2015%2F03%2F02%2F50%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/381212]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[redis编译安装和常用操作]]></title>
    <url>%2F2015%2F03%2F02%2F51%2F</url>
    <content type="text"><![CDATA[[先去] [tar-xvf redis-2.6.13.tar.gz] [cd redis-2.6.13] [可以先扯下 vi READMIN这个文档，很不错的] [make ] [make test ] [报了一个错 You need tcl 8.5 or newer in order to run the Redistest] [缺tcl，我就不下载源码包了] [yum -y install tcl ] [再来 make clean ] [再来执行 make ] [make test这下就不报错了] [make install安装到本地服务器上] [ cd utils] [./install_server.sh 报服务器安装到本地机上] [ 报了个这个错] [./install_server.sh: line 178: update-rc.d: command not found\exists, process is already running orcrashed] [按着错误提示，我们对/etc/init.d/redis_6379进行修改，只有要“\n”删除并且输入回车，修改完毕后，保存] [==================] [还有解决方案是 ] .lang-bsh&#125;1vim install_server.sh##第一个点###修改前-if[!`which chkconfig`];then###修改后+if[!`which chkconfig`]; .lang-bsh&#125;12##第二个点###修改前-if[!`which chkconfig`];then###修改后+if[!`which chkconfig`];then也就是在 .lang-bsh&#125;12if[! `which chkconfig`];在！中间敲一个空格键还有错误是: [Selected default - /var/lib/redis/6379\which: no redis-server in (/sbin:/bin:/usr/sbin:/usr/bin)\Please select the redis executable path [] vim ins \^H\^H\^H\^H\^H\Mmmmm… it seems like you don\’t have a redis executable. Did you runmake install yet?] .lang-bsh&#125;123which redis找不能服加入一个软件链接ln -s /usr/local/redis/bin/redis-* /usr/local/bin/ .lang-bsh&#125;1 [service redis_6379 start 启动] [ps -ef | grepredis ] [基本操作 redis-cli ] [redis 127.0.0.1:6379&gt; info #查看server版本内存使用连接等信息 \ redis 127.0.0.1:6379&gt; client list #获取客户连接列表 \ redis 127.0.0.1:6379&gt; client kill 127.0.0.1:33441#终止某个客户端连接 \ redis 127.0.0.1:6379&gt; dbsize #当前保存key的数量 \ redis 127.0.0.1:6379&gt; save #立即保存数据到硬盘 \ redis 127.0.0.1:6379&gt; bgsave #异步保存数据到硬盘 \ redis 127.0.0.1:6379&gt; flushdb #当前库中移除所有key \ redis 127.0.0.1:6379&gt; flushall #移除所有key从所有库中 \ redis 127.0.0.1:6379&gt; lastsave #获取上次成功保存到硬盘的unix时间戳 \ redis 127.0.0.1:6379&gt; monitor #实时监测服务器接收到的请求 \ redis 127.0.0.1:6379&gt; slowlog len #查询慢查询日志条数 \(integer) 3 \ redis 127.0.0.1:6379&gt; slowlog get#返回所有的慢查询日志，最大值取决于slowlog-max-len配置 \ redis 127.0.0.1:6379&gt; slowlog get 2 #打印两条慢查询日志 \ redis 127.0.0.1:6379&gt; slowlog reset#清空慢查询日志信息] [这样基本上就安装完成了]]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[CMD命令实现批量修改文件名]]></title>
    <url>%2F2015%2F02%2F18%2F52%2F</url>
    <content type="text"><![CDATA[cmd命令批量修改文件名: (批量去掉下载电影后的前缀) 1234567@echo offfor /f "delims=" %%a in ('dir /b/s/a-d [阳光电影www.ygdy8.com].*') do ( set "str=%%~nxa" setlocal enabledelayedexpansion ren "%%a" "!str:~20!" endlocal) 批量删除文件名特定字符(含特定字符自身)前后的文字?(如:Movie_20_(528990).mpg,要求只保留528990.mpg这样的文件名) 12@echo offfor %%a in (*.mpg) do for /f "tokens=2 delims=()" %%b in ("%%a") do ren "%%a" "%%b.mpg" 批量添加文件名前缀 12345678910111213@echo off&amp;setlocal EnableDelayedExpansioncolor 0aecho %date% %time%echo 正在批量重命名文件......set a=1for /f "delims=" %%i in ('dir /b *.del') do ( ren "%%i" "文件名前缀%%i" set /a a+=1 ))set /a a-=1echo 重命名完成，共重命名%a%个文件。pause]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[监控日志文件的md5值/更新时间,如果N分钟后无变化则重启应用]]></title>
    <url>%2F2015%2F02%2F10%2F53%2F</url>
    <content type="text"><![CDATA[[执行语句如下:（可添加计划任务）] [[ ] 1 /bin/bash check_modify.sh /data/log/policy-root-new-5/policy-root-new-5.$(date +%Y-%m-%d).log 10 policy-root-new-5 policy-root-new-5 '/data/www/apps/policy-root-new-5/bin/boxrun' restart [**]\ 监控md5值: .true; .auto-links: .false;&#125;1/bin/bash check_md5sum.sh /data/log/policy-root-new-2/policy-root-new-2.$(date +%Y-%m-%d).log 300 policy-root-new-2 policy-root-new-2 &apos;/data/www/apps/policy-root-new-2/bin/boxrun&apos; restart 1 check_md5sum.sh 如下 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动检测文件的md5值,经过N分钟后,如果没变化就重启服务#缺省的配置如下logdir=/data/log/shell #日志路径log=$logdir/check.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=1 #是否记录日志: 1记录 0不记录restart_file=/data/scripts/run.sh #服务启动和关闭控制脚本end_string="所有导数已经结束" #监控文件结束标识#动态数据时间 datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125;#动态打印日志print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho "[ $(datef) ] $1"fi&#125;#检查目录check_dir()&#123;if [[ ! -d $basedir ]];thenprint_log "目录不存在: $basedir"exitfi&#125;#检查文件check_file()&#123;if [[ ! -f $firt_args ]];thenprint_log "文件不存在: $firt_args"exitfi&#125;#监控文件&amp;restartmonitor_file()&#123;content=$(grep "$end_string" $firt_args)if [[ -z $content ]];thenprint_log ""print_log "没有找到结束标识,开始监控文件"print_log "开始检测文件md5值."md5_value=$(md5sum $firt_args |awk '&#123;print $1&#125;')print_log "等待$second秒..."sleep $secondmd5_next_value=$(md5sum $firt_args |awk '&#123;print $1&#125;')if [[ $md5_next_value != $md5_value ]];thenprint_log "文件:$firt_args ------$second秒后发生了变化-&gt;退出操作"exitfiif [[ ! -f $restart_file ]];thenprint_log "服务控制脚本不存在:$restart_file "exitfiprint_log "文件:$firt_args ------$second秒后md5值相等."print_log "开始重启."/bin/bash $restart_file $third $fourth $five $sixprint_log "重启完成."elseprint_log "找到结束标识,不需要监控文件."fi&#125;#主函数run()&#123;#第一个参数的判断if [[ "$1" != "" ]];thenfirt_args=$1check_file elseecho -e " 自动检测文件的md5值,经过N秒钟后,如果没变化就重启服务 用法示例"echo -e "$0: /bin/bash $0 要监控的文件 监控的时间(单位:秒) 应用的名称 应用的关键字 '执行启动的命令' 要做的动作 exp: /bin/bash $0 "/data/log/policy-root-new-2/policy-root-new-2.\$\(date "+%Y-%m-%d"\).log" 10 policy-root-new-2 policy-root-new-2 '/data/www/apps/policy-root-new-2/bin/boxrun' restart/stop/start"exitfi #第二个参数的判断if [[ $2 != "" ]];thensecond=$2if [[ $second -eq 0 ]];thenprint_log "第二个参数,不能为0"exitfi elseprint_log "第二个参数,不能为空"exitfi #第三个参数的判断if [[ $3 != "" ]];thenthird=$3elseprint_log "第三个参数,不能为空"exitfi#第四个参数的判断if [[ $4 != "" ]];thenfourth=$4elseprint_log "第四个参数,不能为空"exitfiif [[ $5 != "" ]];thenfive=$5elseprint_log "第五个参数,不能为空"exitfiif [[ $6 != "" ]];thensix=$6elseprint_log "第六个参数,不能为空"exitfimonitor_file&#125;run $1 $2 $3 $4 $5 $6 1run.sh 如下 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174#!/bin/bash# chkconfig: 2345 93 11# description:$INS_APP Server. /etc/rc.d/init.d/functionsJAVA_HOME="/usr/local/jdk"PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:$JAVA_HOME/binis_font=1 #终端是否打印日志: 1打印 0不打印is_log=1 #是否记录日志: 1记录 0不记录logdir=/data/log/shell #日志路径log=$logdir/restart.log #日志文件basedir="/data/www/apps"baselogdir="/data/log/"export PATH#动态数据时间datef()&#123; date "+%Y-%m-%d %H:%M:%S"&#125;#动态打印日志print_log()&#123; if [[ $is_log -eq 1 ]];then [[ -d $logdir ]] || mkdir -p $logdir echo "[ $(datef) ] $1" &gt;&gt; $log fi if [[ $is_font -eq 1 ]];then echo "[ $(datef) ] $1" fi&#125;#检查文件check_file()&#123; if [[ ! -f $firt_args ]];then print_log "文件不存在: $firt_args" exit fi&#125;#查找进程idcheck_pid()&#123; ps aux |grep "$second"|grep -v grep |grep -v "cronolog" |grep -v "run.sh" |awk '&#123;print $2&#125;' | grep -v "$$"&#125;start() &#123; if [[ ! -f /usr/sbin/cronolog ]];then yum install cronolog* -qy fi if [[ ! -d $basedir/$first ]];then print_log "目录不存在: $basedir/$first" exit fi nohup /bin/bash $third 2&gt;&amp;1 | /usr/sbin/cronolog $baselogdir/$first/$first.%Y-%m-%d.log &amp; ret=$? if [ $ret -eq 0 ]; then print_log "启动 $first: 成功" action $"启动 $first: " /bin/true pid=$(check_pid) echo $pid &gt; $pid_file else print_log "启动 $first: 失败" action $"启动 $first: " /bin/false fi # chmod 755 /etc/init.d/$INS_APP # chkconfig --add $INS_APP # chkconfig --level 3 $INS_APP on&#125;stop() &#123; pid_values=$(check_pid) if [[ -z $pid_values ]];then print_log "应用已经是处于停止的状态" else for i in $pid_values do kill -9 $i done if [[ -z $(check_pid) ]];then print_log "停止 $first: 成功" action $"停止应用 $first: " /bin/true rm -f $pid_file else print_log "停止 $first: 失败" action $"停止应用 $first: " /bin/false fi fi&#125;restart() &#123; stop sleep 2 start&#125;#主函数run()&#123; #第一个参数的判断 if [[ "$1" != "" ]];then first=$1 pid_file=/var/run/$first.pid prog=$first else echo -e " 自定义应用的启动和关闭 用法示例" echo -e " ./$0: ./$0 应用的名称 应用的关键字 '执行启动的命令' 要做的动作 exp: ./$0 policy-root-new-2 policy-root-new-2 "/data/www/apps/policy-root-new-2/bin/boxrun" start/stop/restart tips: 应用名称:policy-root-new-2 -&gt;应用的位置即为:/data/www/apps/policy-root-new-2 " exit fi #第二个参数的判断 if [[ $2 != "" ]];then second=$2 else print_log "第二个参数,不能为空" exit fi #第三个参数的判断 if [[ $3 != "" ]];then third=$3 else print_log "第三个参数,不能为空" exit fi #第四个参数的判断 if [[ $4 != "" ]];then forth=$4 case "$forth" in start) start ;; stop) stop;;status)status $prog;;restart)restart;;*)print_log "第三个参数,只能为:start/stop/restart/status"exit 1esacelseprint_log "第四个参数,不能为空"exitfi&#125;run $1 $2 $3 $4 效果图： 监控文件的更新时间： 1check_modify.sh 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #自动检测文件的最新更新时间,经过N分钟后,如果没变化就重启服务#缺省的配置如下logdir=/data/log/shell #日志路径log=$logdir/check.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=1 #是否记录日志: 1记录 0不记录restart_file=/data/scripts/run.sh #服务启动和关闭控制脚本end_string="所有导数已经结束" #监控文件结束标识#动态数据时间 datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125;#动态打印日志print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho "[ $(datef) ] $1"fi&#125;#检查目录check_dir()&#123;if [[ ! -d $basedir ]];thenprint_log "目录不存在: $basedir"exitfi&#125;#检查文件check_file()&#123;if [[ ! -f $firt_args ]];thenprint_log "文件不存在: $firt_args"exitfi&#125;#监控文件&amp;restartmonitor_file()&#123;content=$(grep "$end_string" $firt_args)if [[ -z $content ]];thenprint_log ""print_log "没有找到结束标识,开始监控文件"print_log "开始检测文件更改时间."utc_time=$(stat $firt_args |grep "Modify" |awk -F'Modify:' '&#123;print $2&#125;')microtime=$(date -d "$utc_time" +%s)print_log "等待$second秒..."sleep $secondutc_time2=$(stat $firt_args |grep "Modify" |awk -F'Modify:' '&#123;print $2&#125;')microtime2=$(date -d "$utc_time2" +%s)if [[ $microtime != $microtime2 ]];thenprint_log "文件:$firt_args ------$second秒后发生了变化-&gt;退出操作"exitfi if [[ ! -f $restart_file ]];thenprint_log "服务控制脚本不存在:$restart_file "exitfiprint_log "文件:$firt_args ------$second秒后文件更新时间相等."print_log "开始重启."/bin/bash $restart_file $third $fourth $five $six print_log "重启完成."elseprint_log "找到结束标识,不需要监控文件."fi&#125;#主函数run()&#123;#第一个参数的判断if [[ "$1" != "" ]];thenfirt_args=$1check_file elseecho -e " 自动检测文件的md5值,经过N秒钟后,如果没变化就重启服务 用法示例"echo -e "$0: /bin/bash $0 要监控的文件 监控的时间(单位:秒) 应用的名称 应用的关键字 '执行启动的命令' 要做的动作 exp: /bin/bash $0 "/data/log/policy-root-new-2/policy-root-new-2.\$\(date "+%Y-%m-%d"\).log" 10 policy-root-new-2 policy-root-new-2 '/data/www/apps/policy-root-new-2/bin/boxrun' restart/stop/start"exitfi #第二个参数的判断if [[ $2 != "" ]];thensecond=$2if [[ $second -eq 0 ]];thenprint_log "第二个参数,不能为0"exitfi elseprint_log "第二个参数,不能为空"exitfi #第三个参数的判断if [[ $3 != "" ]];thenthird=$3elseprint_log "第三个参数,不能为空"exitfi#第四个参数的判断if [[ $4 != "" ]];thenfourth=$4elseprint_log "第四个参数,不能为空"exitfiif [[ $5 != "" ]];thenfive=$5elseprint_log "第五个参数,不能为空"exitfiif [[ $6 != "" ]];thensix=$6elseprint_log "第六个参数,不能为空"exitfimonitor_file&#125;run $1 $2 $3 $4 $5 $6]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[关于mysql 删除数据后物理空间未释]]></title>
    <url>%2F2015%2F02%2F05%2F54%2F</url>
    <content type="text"><![CDATA[[OPTIMIZE TABLE当您的库中删除了大量的数据后，您可能会发现数据文件尺寸并没有减小。这是因为删除操作后在数据文件中留下碎片所致。OPTIMIZETABLE是指对表进行优化。如果已经删除了表的一大部分数据，或者如果已经对含有可变长度行的表（含有VARCHAR 、 BLOB 或 TEXT 列的表）进行了很多更改，就应该使用 [OPTIMIZETABLE命令来进行表优化。这个命令可以将表中的空间碎片进行合并，并且可以消除由于删除或者更新造成的空间浪费] 。[OPTIMIZETABLE 命令只对 MyISAM 、 BDB 和 InnoDB表起作用] [一，原始数据] [mysql&gt; select count(*) as total from ad_visit_history; ] [+———+ ] [| total | ] [+———+ ] [| [1187096] [+———+ ] [[1] [ 2，存放在硬盘中的表文件大小] [[root[@BlackGhost] [[382020] [[127116] [[12] [ 3，查看一下索引信息] [mysql&gt; show index from ad_visit_history from test1; [//查看一下该表的索引信息] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | ] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [| ad_visit_history | [0] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [[8] [索引信息中的列的信息说明。] [Table :表的名称。 Non_unique :如果索引不能包括重复词，则为0。如果可以，则为1。 Key_name :索引的名称。 Seq_in_index :索引中的列序列号，从1开始。 Column_name :列名称。 Collation :列以什么方式存储在索引中。在MySQLSHOWINDEX语法中，有值’A’（升序）或NULL（无分类）。 Cardinality :索引中唯一值的数目的估计值。通过运行ANALYZETABLE或myisamchk-a可以更新。基数根据被存储为整数的统计数据来计数，所以即使对于小型表，该值也没有必要是精确的。基数越大，当进行联合时，MySQL使用该索引的机会就越大。 Sub_part :如果列只是被部分地编入索引，则为被编入索引的字符的数目。如果整列被编入索引，则为NULL。 Packed :指示关键字如何被压缩。如果没有被压缩，则为NULL。 Null :如果列含有NULL，则含有YES。如果没有，则为空。Index_type ：存储索引数据结构方法（BTREE,FULLTEXT, HASH,RTREE）] [二，删除一半数据] [mysql&gt; delete from ad_visit_history where id&gt;[598000] [Query OK, [589096] [ ] [[root[@BlackGhost] [[382020] [[127116] [[12] [按常规思想来说，如果在数据库中删除了一半数据后，相对应的.MYD,.MYI文件也应当变为之前的一半。[但是删除一半数据后，.MYD.MYI尽然连1KB都没有减少 ] [我们在来看一看，索引信息] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | ] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [| ad_visit_history | [0] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [[8] [对比一下，这次索引查询和上次索引查询，里面的数据信息基本上是上次一次的一本，这点还是合乎常理。] [三，用optimizetable来优化一下] [mysql&gt; optimize table ad_visit_history; [//删除数据后的优化] [+————————+———-+———-+———-+ ] [| Table | Op | Msg_type | Msg_text | ] [+————————+———-+———-+———-+ ] [| test1.ad_visit_history | optimize | status | OK | ] [+————————+———-+———-+———-+ ] [[1] [ 1，查看一下.MYD,.MYI文件的大小] [[root[@BlackGhost] [[182080] [[66024] [[12] [ 2，查看一下索引信息] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | ] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [| ad_visit_history | [0] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [| ad_visit_history | [1] [+——————+————+——————-+————–+—————+———–+————-+———-+——–+——+————+———+ ] [[8] [从以上数据我们可以得出，ad_code，ad_code_ind，from_page_url_ind等索引机会差不多都提高了85％，这样效率提高了好多。] [四，小结] [结合mysql官方网站的信息，个人是这样理解的。当你删除数据时，mysql并不会回收，被已删除数据的占据的存储空间，以及索引位。而是空在那里，而是等待新的数据来弥补这个空缺，这样就有一个缺少，如果一时半会，没有数据来填补这个空缺，那这样就太浪费资源了。所以对于写比较频烦的表，要定期进行optimize，一个月一次，看实际情况而定了。] [举个例子来说吧。有100个php程序员辞职了，但是呢只是人走了，php的职位还在那里，这些职位不会撤销，要等新的php程序来填补这些空位。招一个好的程序员，比较难。我想大部分时间会空在那里。哈哈。] [五，手册中关于OPTIMIZE的一些用法和描述] [OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [,tbl_name] …] [如果您已经删除了表的一大部分，或者如果您已经对含有可变长度行的表（含有VARCHAR,BLOB或TEXT列的表）进行了很多更改，则应使用 OPTIMIZETABLE。被删除的记录被保持在链接清单中，后续的INSERT操作会重新使用旧的记录位置。您可以使用OPTIMIZETABLE来重新利用未使用的空间，并整理数据文件的碎片。] [在多数的设置中，您根本不需要运行OPTIMIZETABLE。即使您对可变长度的行进行了大量的更新，您也不需要经常运行，每周一次或每月一次即可，只对特定的表运行。] [OPTIMIZE TABLE只对MyISAM,BDB和InnoDB表起作用。] [注意，在OPTIMIZETABLE运行过程中，MySQL会锁定表。] [\] [] [innodb执行] [ALTER TABLE table.nameENGINE=\’InnoDB\’;]]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[linux修改max user processes limits]]></title>
    <url>%2F2015%2F01%2F29%2F55%2F</url>
    <content type="text"><![CDATA[说明：\这篇是网上看到的有关修改max user processeslimits，觉得还可以，就保留了下来！稍微加了点东西\ 具体：\最近新上了一批服务器，内核升级到了2.6.32版本，部署完MySQL实例后上到线上，直接负载冲到15，cpu使用达到700%。 .prettyprint .prettyprinted&#125;101:20:01 PM runq-sz plist-sz ldavg-1 ldavg-5 ldavg-1503:50:01 PM 34 1506 22.95 18.11 11.7801:20:01 PM CPU %user %nice %system %iowait %steal %idle03:50:01 PM all 95.13 0.00 3.31 0.06 0.00 1.49 当时就有点蒙，io并不是瓶颈，业务也米有变更，线上的服务器都运行正常，为什么这台新机器就变成这个模样了呢？\最后才发现又是一个ulimit的坑啊，之前对于ulimit-n已经碰了多次头，这次又差点碰的头破血流，万幸灰度上了1台slave，并没有影响到线上。\这次碰到的问题是ulimit -u，这个-u是做什么用的呢？ .prettyprint .prettyprinted&#125;123456core file size (blocks, -c) 0data seg size (kbytes, -d) unlimitedscheduling priority (-e) 0file size (blocks, -f) unlimitedpending signals (-i) 514875max locked memory (kbytes, -l) 64max memory size (kbytes, -m) unlimitedopen files (-n) 204800pipe size (512 bytes, -p) 8POSIX message queues (bytes, -q) 819200real-time priority (-r) 0stack size (kbytes, -s) 10240cpu time (seconds, -t) unlimitedmax user processes (-u) 204800virtual memory (kbytes, -v) unlimitedfile locks (-x) unlimited 可以从上面看出，用来限制max user processes的数量的。\但是这个user processes是什么呢？\Linux itself has a Max Processes per user limit. This feature allows usto control the number of processes an existing user on the server may beauthorized to have\这个ulimit -u是用来限制每个用户的最大processes数量。如果ulimit-u进行了限制那么每个linux用户可以派生出来的process就会被限制再这个数值之内。\那么这个限制和MySQL有什么关系呢，我们看如下的测试。\ 测试：\首先，在一台服务器上启两个MySQL实例，分别限制max connetcionts=1024 ，ulimit -u=1024\然后，在一台服务器上运行类似下面的脚本 .prettyprint .prettyprinted&#125;1234for i in `seq 1 2010`do echo $i mysqlha_login.sh -h 10.77.7.56 -P 3306 -e&apos;system sleep 60;&apos; &amp; mysqlha_login.sh -h 10.77.7.56 -P 3307 -e&apos;system sleep 60;&apos; &amp;done 当i的数值超过1009的时候就会出现如下报错\Can’t create a new thread (errno 11); if you are not out of availablememory, you can consult the manual for a possible OS-dependent bug\这就是无法再创建出新的process了。\如果我们将ulimit -u改为10240，再进行一次测试呢？\User myadmin already has more than ‘max_user_connections’ activeconnections\报错就变更为我们常见的超过最大连接数的报错了。\so，对于提供长链接的MySQL服务，建议都讲这个值调整为10240或者更大。对于提供短链接的服务，暂时并没有出现本次发现的错误。\ 修改：\不同内核参数的默认值也是不同的，请注意。 .prettyprint .prettyprinted&#125;1234562.6.18ore file size (blocks, -c) 0data seg size (kbytes, -d) unlimitedscheduling priority (-e) 0file size (blocks, -f) unlimitedpending signals (-i) 139264max locked memory (kbytes, -l) 32max memory size (kbytes, -m) unlimitedopen files (-n) 288000pipe size (512 bytes, -p) 8POSIX message queues (bytes, -q) 819200real-time priority (-r) 0stack size (kbytes, -s) 10240cpu time (seconds, -t) unlimitedmax user processes (-u) unlimitedvirtual memory (kbytes, -v) unlimitedfile locks (-x) unlimited .prettyprint .prettyprinted&#125;1234562.6.32core file size (blocks, -c) 0data seg size (kbytes, -d) unlimitedscheduling priority (-e) 0file size (blocks, -f) unlimitedpending signals (-i) 514875max locked memory (kbytes, -l) 64max memory size (kbytes, -m) unlimitedopen files (-n) 204800pipe size (512 bytes, -p) 8POSIX message queues (bytes, -q) 819200real-time priority (-r) 0stack size (kbytes, -s) 10240cpu time (seconds, -t) unlimitedmax user processes (-u) 1024virtual memory (kbytes, -v) unlimitedfile locks (-x) unlimited 然后，一般来说，修改ulimit的数值，只需要修改/etc/security/limits.conf即可，但是这个参数需要修改/etc/security/limits.d/90-nproc.conf。\至于为什么需要修改这里，请看褚霸的这篇blog：\但是，还有一个问题，这个参数需要在mysqld启动之前调整，如果mysqld已经启动，再动态调整是无效的。（大家都知道stopstart mysql是一件比较麻烦的事情，涉及线上业务就更麻烦了）\那么，有没有可以动态调整的方法呢？\echo -n ‘Max processes=SOFT_LIMITS:HARD_LIMITS’ &gt; /proc/`pidofmysqld`/limits\通过如上命令就可以动态调整已经存在的mysqld的processes限制了。\ 附录：\附录1：centos 6.*可以修改/etc/security/limits.d/90-nproc.conf\但，centos5.*并没有90-nproc.conf这个文件，我这边是通过修改/etc/security/limits.conf，在最后添加\* soft nproc 65535\* hard nproc 65535 Linux对于每个用户，系统限制其最大进程数。为提高性能，可以根据设备资源情况，设置各linux用户的最大进程数 可以用ulimit -a 来显示当前的各种用户进程限制。\下面我把某linux用户的最大进程数设为10000个：\ ulimit -u 10240\ 对于需要做许多 socket 连接并使它们处于打开状态的 Java应用程序而言，\ 最好通过使用 ulimit -n xx 修改每个进程可打开的文件数，缺省值是1024。\ ulimit -n 4096 将每个进程可以打开的文件数目加大到4096，缺省为1024\ 其他建议设置成无限制（unlimited）的一些重要设置是：\ 数据段长度：ulimit -d unlimited\ 最大内存大小：ulimit -m unlimited\ 堆栈大小：ulimit -s unlimited\ CPU 时间：ulimit -t unlimited\ 虚拟内存：ulimit -v unlimited\ \ 暂时地，适用于通过 ulimit 命令登录 shell 会话期间。\ 永久地，通过将一个相应的 ulimit 语句添加到由登录 shell读取的文件中， 即特定于 shell 的用户资源文件，如： 1)、解除 Linux 系统的最大进程数和最大文件打开数限制：\ vi /etc/security/limits.conf\ # 添加如下的行\ * soft noproc 11000\ * hard noproc 11000\ * soft nofile 4100\ * hard nofile 4100\ 说明：* 代表针对所有用户，noproc 是代表最大进程数，nofile是代表最大文件打开数\2)、让 SSH 接受 Login 程式的登入，方便在 ssh 客户端查看 ulimit -a资源限制：\ a、vi /etc/ssh/sshd_config\ 把 UserLogin 的值改为 yes，并把 # 注释去掉\ b、重启 sshd 服务：\ /etc/init.d/sshd restart\3)、修改所有 linux 用户的环境变量文件：\ vi /etc/profile\ ulimit -u 10000\ ulimit -n 4096\ ulimit -d unlimited\ ulimit -m unlimited\ ulimit -s unlimited\ ulimit -t unlimited\ ulimit -v unlimited 保存后运行#source /etc/profile 使其生效 /************************************** 有时候在程序里面需要打开多个文件，进行分析，系统一般默认数量是1024，（用ulimit-a可以看到）对于正常使用是够了，但是对于程序来讲，就太少了。\修改2个文件。 1./etc/security/limits.conf\vi /etc/security/limits.conf\加上：\* soft nofile 8192\* hard nofile 20480 2./etc/pam.d/login\session required /lib/security/pam_limits.so\/**********\另外确保/etc/pam.d/system-auth文件有下面内容\session required /lib/security/\$ISA/pam_limits.so\这一行确保系统会执行这个限制。 /***********\3.一般用户的.bash_profile\#ulimit -n 1024\重新登陆ok\ ulimit 的作用\ =======================\ \ulimit：显示（或设置）用户可以使用的资源的限制（limit），这限制分为软限制（当前限制）和硬限制（上限），其中硬限制是软限制的上限值，应用程序在运行过程中使用的系统资源不超过相应的软限制，任何的超越都导致进程的终止。 参数 描述\ulimited 不限制用户可以使用的资源，但本设置对可打开的最大文件数（maxopen files）\和可同时运行的最大进程数（max user processes）无效\-a 列出所有当前资源极限\-c 设置core文件的最大值.单位:blocks\-d 设置一个进程的数据段的最大值.单位:kbytes\-f Shell 创建文件的文件大小的最大值，单位：blocks\-h 指定设置某个给定资源的硬极限。如果用户拥有 root用户权限，可以增大硬极限。任何用户均可减少硬极限\-l 可以锁住的物理内存的最大值\-m 可以使用的常驻内存的最大值,单位：kbytes\-n 每个进程可以同时打开的最大文件数\-p 设置管道的最大值，单位为block，1block=512bytes\-s 指定堆栈的最大值：单位：kbytes\-S 指定为给定的资源设置软极限。软极限可增大到硬极限的值。如果 -H 和 -S标志均未指定，极限适用于以上二者\-t 指定每个进程所使用的秒数,单位：seconds\-u 可以运行的最大并发进程数\-v Shell可使用的最大的虚拟内存，单位：kbytes\-x 范例1： [root@localhost{.referer} proc]#ulimit -a\core file size (blocks, -c) 100\data seg size (kbytes, -d) unlimited\file size (blocks, -f) unlimited\pending signals (-i) 2047\max locked memory (kbytes, -l) 32\max memory size (kbytes, -m) unlimited\open files (-n) 1024\pipe size (512 bytes, -p) 8\POSIX message queues (bytes, -q) 819200\stack size (kbytes, -s) 8192\cpu time (seconds, -t) unlimited\max user processes (-u) 2047\virtual memory (kbytes, -v) unlimited\file locks (-x) unlimited\[root@localhost{.referer} proc]# 输出的每一行由资源名字、（单位，ulimit命令的参数）、软限制组成。详细解释：\参数 描述\core file size core文件的最大值为100 blocks，\data seg size 进程的数据段可以任意大\file size 文件可以任意大\pending signals 最多有2047个待处理的信号\max locked memory 一个任务锁住的物理内存的最大值为32kB\max memory size 一个任务的常驻物理内存的最大值\open files 一个任务最多可以同时打开1024的文件\pipe size 管道的最大空间为4096字节\POSIX message queues POSIX的消息队列的最大值为819200字节\stack size 进程的栈的最大值为8192字节\cpu time 进程使用的CPU时间\max user processes 当前用户同时打开的进程(包括线程)的最大个数为2047\virtual memory 没有限制进程的最大地址空间\file locks 所能锁住的文件的最大个数没有限制 范例2：通过ulimit命令来限制文件的大小，从而导致拷贝命令的失败 [root@localhost]ls temp.txt\ls: temp.txt: 没有那个文件或目录\[root@localhost]ulimit -f 1 #设置创建文件的最大块(一块=512字节)\[root@localhost]cat a.c &gt; temp.txt\文件大小超出限制 文件a.c的大小是5002字节,而我们设定的创建文件的大小是512字节x1块=512字节]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[win8.1磁盘使用率100解决方法]]></title>
    <url>%2F2015%2F01%2F23%2F56%2F</url>
    <content type="text"><![CDATA[1.关闭家庭组，因为这功能会导致硬盘和CPU处于高负荷状态。关闭方法：Win+C– 设置 – 更改电脑设置 – 家庭组 –离开如果用不到家庭组可以直接把家庭组服务也给关闭了：控制面板 – 管理工具– 服务 – HomeGroup Listener 和 HomeGroup Provider 禁用。 2.WindowsDefender全盘扫描下系统，否则打开文件夹会卡顿。然后可以排除信任的EXE程序，建议排除explorer.exe（资源管理器进程），如果你不用系统自带的杀毒软件，也可以直接关闭它。 Win+X – 控制面板 – Windows Defender – 设置 – 实施保护 -去掉勾 和管理员 – 启用 Windows Defender – 去掉勾。控制面板 – 管理工具 – 服务 Windows Defender Service 禁用。 3.用好索引选项，减少硬盘压力。控制面板 – 索引选项 – 选中索引项 – 修改– 取消不想索引的位置。（索引服务对系统性能的影响）如果习惯用 everything这款神器来搜索文件，可以关闭索引功能。控制面板 – 管理工具 – 服务 -Windows Search 禁用。 4.关闭磁盘碎片整理计划。用好磁盘碎片整理可以提高磁盘性能，如果习惯手动整理，可以关闭整理计划，避免在你工作的时候自动整理，影响性能。资源管理器，选中磁盘 属性 – 工具 – 对驱动器进行优化和碎片整理 – 优化 – 更改设置 –取消选择按计划运行。 5.设置Win8 自动登陆，省去输入密码步骤，开机更快快捷键Win+R – 输入netplwiz - 取消使用计算机必须输入用户名和密码的选项 –然后双击需要自动登录的账户 –输入你的密码。如果覆盖或者升级安装Win8，需要清理产生的Windows.old文件夹，腾出C盘空间。方法1：快捷键Win+X -命令提示符 – 输入 rd X:windows.old /s （X代表盘符）方法2（推荐）：C盘– 右键 – 属性 - 磁盘清理 - 选中 以前的 Windows 安装 复选框 –确定清理。 6.关闭ipv6部分网卡驱动开启ipv6会导致开机系统未响应，假死。如果你不是ipv6用户建议关闭，否则就更新网卡驱动试试看。网络共享中心– 网络连接 – 以太网 – 属性 – 取消 ipv6 。 7.开启 Hybrid BootWin8启动飞快。默认是启动的，如果没有启动，可以到控制面板 – 电源选项 –选择电源按钮的功能 – 更改当前不可用的设置 – 关机设置 –勾上启用快速启动。如果没有看到这功能，请先开启休眠：Win+X – 命令提示符– 输入 powercfg -h on 8.关闭性能特效。系统属性 – 高级 - 性能 - 设置 –关闭淡出淡入效果。打开文件夹，小软件之类的，唰唰的快！反正Win8都反璞归真，取消了Aero磨砂效果，不在乎这点特效了，直接关闭吧。通过以上的优化设置后，Win8飞一般的感觉，还可以关闭你不需要用的系统服务，这里就不介绍了，过度优化会出现各种毛病，需谨慎！ END 注意事项有的系统服务具有特定功能，请不要随意禁止或关闭 以上方法可以按需求挑选设置，可以不用全部都操作 [\]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[检测含有关键字的文件的总大小]]></title>
    <url>%2F2015%2F01%2F22%2F57%2F</url>
    <content type="text"><![CDATA[123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #检测含有关键字的文件的总大小logdir=/data/log/clear #日志路径log=$logdir/clear.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录 datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125;print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho "[ $(datef) ] $1"fi&#125;check_dir()&#123;if [[ ! -d $basedir ]];thenprint_log "[ $(datef) ] 需要检测的目录不存在: $basedir"exitfi&#125; static_sizes()&#123;size=$(du -sh $basedir |awk '&#123;print $1&#125;')print_log "现在该目录[$basedir]的大小为: $size"&#125; jisuan_sum()&#123;if [[ $file_key != "" ]];thenls $basedir/$file_key* |head -n 5 &gt; /dev/nullif [[ $? -ne 0 ]];thenprint_log "现在该目录[$basedir]不存在关键字为$file_key的文件."exitfidu -k $basedir/$file_key* |awk '&#123;print $1&#125;' &gt; /tmp/sum.txtprint_log "开始计算...请稍等"while read line donext=$( echo $line|sed "s/M//g")sum=`expr $sum + $next`done &lt; /tmp/sum.txtrm -f /tmp/sum.txtsum=$(expr $sum / 1000)if [[ $sum -gt 1000 ]];thensumG=$(expr $sum / 1000)elsesumG=0fiprint_log "[$basedir]目录下含有[ $file_key ]关键字的文件大小的总和: $sum M || $sumG G" fi&#125;if [[ "$1" = "" ]];thenecho -e " 检测含有关键字的文件的总大小 用法示例"echo -e "clean.class.sh: ./checksum.class.sh 要检测文件的所在目录 要检测文件的关键词exp: ./checksum.class.sh /data/backup/bdb-log log"exitfi if [[ $1 != "" ]];thenbasedir=$1check_dirif [[ $1 = "/" ]];thenprint_log "第一个参数[检测目录],不能选择根目录"exitfi elseprint_log "第一个参数[检测目录],不能为空"exitfi if [[ $2 != "" ]];thenfile_key=$2fistatic_sizesjisuan_sum 示例结果如下:]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[OpenLDAP使用BDB时的一些配置和维护方法]]></title>
    <url>%2F2015%2F01%2F22%2F59%2F</url>
    <content type="text"><![CDATA[[一、配置部份]\[在基本配置完成之后，可以在slapd.conf设置一些提高安全和效率的选项]\[ cachesize5000]\[ checkpoint 10245]\[ cachesize是ldap在内存中缓存的记录条数。这个缓存是openldap自己维护的，与bdb库无关。]\[ 为了提高效率bdb在修改数据库时，是先修改内存里面的，然后分批回写到数据库文件里面。Checkpoint操作就是把内存中的数据回写数据库文件的操作。]\[ checkpoint 10245表示每写1024kb数据，或者是每隔5分钟,bdb会执行一次checkpoint的操作。]\[ 在bdb库中提拱了一个命令db_checkpoint，用来给用户执行checkpoint用。比如，当用户需要删除日志的时候，他需要先执行一下db_checkpoint，来确保数据已经回写到数据库文件中了，这时才能放心地删掉日志。]\ [ 还有一些设置bdb环境的选项设置，这些选项存在于DB_CONFIG。这个文件放在openldap-data/下]\[ set_cachesize是bdb库自己的cache，这个选项用来设置cache的大小。这个选项的格式]\ [ set_cachesize &lt;gbytes&gt; &lt;bytes&gt;&lt;ncache&gt;]\[ &lt;gbytes&gt;: cache 的 GB大小]\[ &lt;bytes&gt;: cache 的Bytes]\[ &lt;ncache&gt;: cache 段的数目, 如果配置为 0 or 1,那么是一段连续的cache. ]\[ set_cachesize一旦设定，就不能更改，除非你再用db_recover重建库。]\[ set_lg_dir &lt;directory&gt;设置操作日志存放的目录。]\[ set_lg_bsize &lt;bytes&gt;设置操作日志的缓存]\[ set_lg_max &lt;bytes&gt;设置操作日志文件大小]\[ set_flags &lt;flag&gt; 配置数据库启动参数,可以配置多个选项标志，比如 DB_TXN_NOSYNC告诉数据库不要立即刷新事务缓冲, 设置该值可以提高数据库写性能,但伴随的是数据丢失的风险(无法通过操作日志恢复).因此并不推荐使用该选项。]\ [二、维护]\[ 1）数据库和日志的归档（或者叫备份）]\[ 有两种备份方法]\[ a）标准备份]\[ 这种备份方法，要求是在备份的时候停止对数据库的写操作。方法是，]\[ 1）停止对数据库的写]\[ 2）执行一次checkpoint]\[ 3）在数据库文件的目录下，执行db_archive–s标识出数据库文件，把它们拷到要备份的目录下。]\[ 4）在日志目录下，执行db_archive，列出的是不活动的日志文件，再用db_archive–l列出所有]\[ 的日志文件，由些来判断哪个是活动日志文件。一般是日志文件编号最大的一个。把这个日志文件拷到]\[ 备份的目录下。]\ [ 这种备份不需要recover，直接就能用。]\[ b）热备份]\[ 这种备份方法，可以在任何时候用。方法如下]\[ 1）在数据库文件的目录下，执行db_archive–s标识出数据库文件，把它们都拷到备份目录下。]\[ 2）在日志目录下，执行db_archive–l标识出所有的日志文件。把它们拷到备份目录下。]\[ 为了节省备份目录的空间，可以在热备份之前，在备份目录执行db_archive列出不再需要的日志文件]\[ 的列表，可以不把这些日志文件拷到备份目录下。]\ [ 2）数据恢复]\[ 数据恢复有两种，一种是正常恢复，一种是热恢复。 ]\[ 正常恢复是，当数据库文件和日志文件都没有被损坏时，执行db_recover，不要带参数。当采用热备份的方法所做的备份，必段要用热恢复的方法来恢复]\ [ 热恢复是，当数据库文件或者日志文件损坏时，在热备份的备份目录下，执行db_recover-c来恢复数据。]\ [几个工具的简介]\[ db_archive用来确定归档文件的工具，常用的用法]\[ 在数据文件目录下，运行db_archive –s用来确定哪些是数据库文件]\[db_archive 不带任保参数，列出不再需要的日志文件名。db_archive –l列出所有日志文件名]\ [ db_checkpoint用来手工checkpoint的工具，比如，在数据文件目录下，运行db_checkpoint –1执行一次checkpoint的操作。]\ [ db_recover 用于恢复数据库，常用的用法，db_recover不带任务参数，表示用正常恢复方法恢复数据库。db_recover –c用于热恢复用的，db_reover –t可以把数据库恢复到指定时间的状态。]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[本地iptables转发脚本]]></title>
    <url>%2F2015%2F01%2F15%2F60%2F</url>
    <content type="text"><![CDATA[12345678910111213141516171819202122232425262728#!/bin/bashIPTABLES=/sbin/iptablesecho "1" &gt; /proc/sys/net/ipv4/ip_forward$IPTABLES -t nat -F POSTROUTING$IPTABLES -t nat -F PREROUTING$IPTABLES -t nat -F OUTPUT$IPTABLES -F$IPTABLES -X$IPTABLES -P INPUT ACCEPT$IPTABLES -P OUTPUT ACCEPT$IPTABLES -P FORWARD ACCEPT$IPTABLES -A INPUT -p icmp --icmp-type timestamp-request -j DROP$IPTABLES -A INPUT -p icmp --icmp-type timestamp-reply -j DROP$IPTABLES -A INPUT -p icmp -j ACCEPT$IPTABLES -A INPUT -i lo -p all -j ACCEPT$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT$IPTABLES -A INPUT -p tcp --dport 22 -j ACCEPT$IPTABLES -A INPUT -p tcp --dport 80 -j ACCEPT$IPTABLES -A FORWARD -p TCP ! --syn -m state --state NEW -j DROP$IPTABLES -A FORWARD -f -m limit --limit 100/s --limit-burst 100 -j ACCEPT$IPTABLES -A FORWARD -p tcp --destination-port 3000 -j ACCEPT $IPTABLES -t nat -A PREROUTING -j REDIRECT -p tcp --destination-port 3000 --to-ports 80/etc/rc.d/init.d/iptables save/etc/rc.d/init.d/iptables restart]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[国外免费的vpn翻墙,亲测可用]]></title>
    <url>%2F2015%2F01%2F13%2F61%2F</url>
    <content type="text"><![CDATA[国外免费的vpn翻墙,亲测可用 ①打开以下网址 http://www.freevpnmac.com/macvpn/ ②滑动按钮获取vpn账号信息,并点击Get VPN info ③下载并安装vpn客户端 http://free-vpn-client.privatevpn.org/free-vpn-client.exe ④输入vpn账号信息并连接，弹出connect fail请忽略，360安全软件弹窗请忽略! ⑤测试 https://www.google.com.hk/ https://www.youtube.com/?gl=HK&amp;hl=zh-HK]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[批量清理某目录下的文件或移除某目录下的文件]]></title>
    <url>%2F2015%2F01%2F04%2F62%2F</url>
    <content type="text"><![CDATA[123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195#!/bin/bash #author: QingFeng#qq: 530035210#blog: http://my.oschina.net/pwd/blog #批量清理某目录下的文件或移除某目录下的文件#缺省的配置如下#basedir=/data/db/renewal/snapshots #执行目录#mvdir=/data/move/$(date "+%Y%m%d")#clear_before_days=90 #清理的时间,120代表120天前的数据 #file_key="snapshot" #清理文件包含关键字logdir=/data/log/clear #日志路径log=$logdir/clear.log #日志文件 is_font=1 #终端是否打印日志: 1打印 0不打印 is_log=0 #是否记录日志: 1记录 0不记录 datef()&#123;date "+%Y-%m-%d %H:%M:%S"&#125;print_log()&#123;if [[ $is_log -eq 1 ]];then[[ -d $logdir ]] || mkdir -p $logdirecho "[ $(datef) ] $1" &gt;&gt; $logfiif [[ $is_font -eq 1 ]];thenecho "[ $(datef) ] $1"fi&#125;check_dir()&#123;if [[ ! -d $basedir ]];thenprint_log "[ $(datef) ] 需要清理的目录不存在: $basedir"exitfi&#125; static_sizes()&#123;size=$(du -sh $basedir |awk '&#123;print $1&#125;')print_log "现在该目录[$basedir]的大小为: $size"&#125; static_files()&#123;if [[ $file_key = "all" ]];thenfile_num=$(find $basedir -mtime +$clear_before_days -type f |wc -l)if [[ $file_num -eq 0 ]];thenprint_log "$basedir目录下:现在$clear_before_days天以前的文件:总共文件为0个,退出清理/移除动作"exitelseprint_log "$basedir目录下:现在$clear_before_days天以前的文件有:$file_num个 "fielsefile_num=$(find $basedir -mtime +$clear_before_days -type f -name "$file_key*" |wc -l)if [[ $file_num -eq 0 ]];thenprint_log "$basedir目录下:现在含有关键字:$file_key以及$clear_before_days天以前的文件为0个,退出清理/移除动作"exitelseprint_log "$basedir目录下:现在含有关键字:$file_key以及$clear_before_days天以前的文件有:$file_num个 "fifi&#125; rm_files()&#123;if [[ $file_key == "all" ]];thenfind $basedir -mtime +$clear_before_days -type f -exec rm &#123;&#125; \;if [[ $? -eq 0 ]];thenprint_log "$basedir目录下:$clear_before_days天以前的文件删除成功."elseprint_log "$basedir目录下:$clear_before_days天以前的文件删除失败."fielsefind $basedir -mtime +$clear_before_days -type f -name "$file_key*" -exec rm &#123;&#125; \;if [[ $? -eq 0 ]];thenprint_log "$basedir目录下:现在含有关键字:$file_key以及$clear_before_days天以前的文件删除成功."else print_log "$basedir目录下:现在含有关键字:$file_key以及$clear_before_days天以前的文件删除失败."fi fi&#125;mv_files()&#123;[[ -d $mvdir ]] || mkdir -p $mvdirif [[ $file_key == "all" ]];thenfind $basedir -mtime +$clear_before_days -type f -exec mv &#123;&#125; $mvdir \;if [[ $? -eq 0 ]];thenprint_log "$basedir目录下:$clear_before_days天以前的文件move成功."elseprint_log "$basedir目录下:$clear_before_days天以前的文件move失败."fielsefind $basedir -mtime +$clear_before_days -type f -name "$file_key*" -exec mv &#123;&#125; $mvdir \;if [[ $? -eq 0 ]];thenprint_log "$basedir目录下:目前含有关键字:$file_key以及$clear_before_days天以前的文件move成功."elseprint_log "$basedir目录下:目前含有关键字:$file_key以及$clear_before_days天以前的文件move失败."fifi&#125; #static_sizes#statics_total#static_files #rm_files#mv_files#statics_totalif [[ "$1" != "" ]];thenfirt_args=$1elseecho -e " 批量清理某目录下的文件或移除某目录下的文件 用法示例"echo -e "clean.class.sh: ./clean.class.sh delete 要删除文件的所在目录 要删除文件的关键词 要删除多少天以前的文件 ./clean.class.sh move 要移除文件的所在目录 要移除文件的关键词 要移除多少天以前的文件 移除的目标目录exp: ./clean.class.sh delete /data/db/renewal/snapshots/ snapshot 120 ./clean.class.sh move /data/db/renewal/snapshots/ snapshot 120 /data/movetips: 直接删除/移动所有文件示例如下: ./clean.class.sh delete /data/db/renewal/snapshots/ all 120 ./clean.class.sh move /data/db/renewal/snapshots/ all 120 /data/move"exitfi if [[ $firt_args != "delete" ]];thenif [[ $firt_args != "move" ]];thenprint_log "第一个参数,只能是move或delete."exitfifiif [[ $2 != "" ]];thenbasedir=$2check_dirif [[ $2 = "/" ]];thenprint_log "第二个参数[执行目录],不能选择根目录"exitfi elseprint_log "第二个参数[执行目录],不能为空"exitfi if [[ $3 != "" ]];thenfile_key=$3elseprint_log "第三个参数[关键词],不能为空"exitfiif [[ $4 != "" ]];thenclear_before_days=$4elseprint_log "第四个参数[天数],不能为空"exitfiif [[ $firt_args = "move" ]];thenif [[ $5 != "" ]];thenmvdir=$5if [[ ! -d $mvdir ]];thenecho "[ $(datef) ] 要移除文件的目的目录不存在: $basedir"exitfi elseprint_log "第五个参数[目的目录],不能为空"exitfistatic_sizesstatic_filesmv_filesstatic_sizesfiif [[ $firt_args = "delete" ]];thenstatic_sizesstatic_files rm_filesstatic_sizesfi 执行结果:]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Linux下nginx支持.htaccess文件实现伪静态的方法]]></title>
    <url>%2F2015%2F01%2F04%2F63%2F</url>
    <content type="text"><![CDATA[[在Google上搜索的资料很多人都说nginx目前不支持.htaccess文件，我按照nginx的规则试验了一下，结果发现nginx是完全支持.htaccess文件的！] [方法如下：] [] [1. 在需要使用.htaccess文件的目录下新建一个.htaccess文件，\如本人的一个] [vim/var/www/html/168pc/bbs/.htaccess] [2.在里面输入规则，我这里输入Discuz的伪静态规则：] #nginx ][ rule\rewrite \^(.*)/archiver/((fid|tid)-[w-]+.html)\$\$1/archiver/index.php?\$2 last;\rewrite \^(.*)/forum-([0-9]+)-([0-9]+).html\$\$1/forumdisplay.php?fid=\$2&amp;page=\$3 last;\rewrite \^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+).html\$\$1/viewthread.php?tid=\$2&amp;extra=page%3D\$4&amp;page=\$3 last;\rewrite \^(.*)/profile-(username|uid)-(.+).html\$\$1/viewpro.php?\$2=\$3 last;\rewrite \^(.*)/space-(username|uid)-(.+).html\$ \$1/space.php?\$2=\$3last;\rewrite \^(.*)/tag-(.+).html\$ \$1/tag.php?name=\$2 last;\# end nginx rewriterule] [wq保存退出。] [3.修改nginx配置文件：] vim/etc/nginx/] 4.在需要添加伪静态的虚拟主机的][{}中引入.htaccess文件，如图所示：\]{width=”439”height=”322”} [include/var/www/html/168pc/bbs/.htaccess;（把这个改成你.htaccess文件的具体位置）] [wq保存退出。] [5.重新加载nginx配置文件：] [/etc/init.d/nginxreload] [重新打开网页看看，如果伪静态正常就证明你的rewrite rule语法是正确的。\]{width=”562”height=”412”}\[正常，完毕！] 补充：偶在网上发现了个可以在线将][ Rewrite伪静态规则自动转换为NginxRewrite网页。大家可以试试看。] [http://www.anilcetin.com/convert-apache-htaccess-to-nginx/] [此地址里面的内容包含可以完成上面说的略做修改的功能。就是把.htaccess中的规则自动转换成nginx下面可用的规则。] [总结：.htaccess文件本来是apache专用的分布式配置文件，提供了针对每个目录改变配置的方法，即在一个特定的目录中放置一个包含指令的文件，其中的指令作用于此目录及其所有子目录。其实修改一下，nginx也可使用.htaccess文件实现多种功能。实现伪静态只是.htaccess的其中一个用途，.htaccess还可以做很多的用途，如过滤访问IP，设置web目录访问权限、密码等。]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[linux 文件编码格式转换]]></title>
    <url>%2F2015%2F01%2F03%2F64%2F</url>
    <content type="text"><![CDATA[[如果你需要在] [查看文件编码] [在Linux中查看文件编码可以通过以下几种方式：] [1.在] [:set fileencoding] [即可显示文件编码格式。] [如果你只是想查看其它编码格式的文件或者想解决用Vim查看文件乱码的问题，那么你可以在] [~/.vimrc文件中添加以下内容：] [set encoding=utf-8fileencodings=ucs-bom,utf-8,cp936] [这样，就可以让vim自动识别文件编码（可以自动识别UTF-8或者GBK编码的文件），其实就是依照fileencodings提供的编码列表尝试，如果没有找到合适的编码，就用latin-1(ASCII)编码打开。] [文件编码转换] [1.在Vim中直接进行转换文件编码,比如将一个文件转换成utf-8格式] [:setfileencoding=utf-8] [2. iconv转换，iconv的命令格式如下：] [iconv -f encoding -t encodinginputfile] [比如将一个UTF-8编码的文件转换成GBK编码] [iconv -f GBK -t UTF-8 file1 -ofile2] [Linux对一个3G的文本进行编码转换全过程] [本过程中涉及到的Linux的命令有：split, iconv,cat] [问题：有一个3G的文本a.txt，编码格式为gbk，现在需要对其进行转换成为utf-8。] [难点：iconv的转换是在内存中进行的，因此3G大小的文本，无法进行直接转换。] [思路：先利用split进行文件切分，然后对每一个字文件进行ivonv转换，最后进行cat合并。] [1) ll -h a.txt查看文件的大小，2.9G] [2) wc -l a.txt查看文件的行数，9千200万行] [3) split -l 20000000 a.txt chunk按照每个文件2千万行进行切割，共分成5个文件] [4) 进行转换] [iconv -f gbk -t utf-8 chunka &gt; chunka_utf8-c] [iconv -f gbk -t utf-8 chunkb &gt; chunkb_utf8-c] [iconv -f gbk -t utf-8 chunkc &gt; chunkc_utf8-c] [iconv -f gbk -t utf-8 chunkd &gt; chunkd_utf8-c] [iconv -f gbk -t utf-8 chunke &gt; chunke_utf8-c] [5) rm chunka chunkb chunkc chunkd chunke删除原文件] [6) cat chunk* &gt; a.txt_utf8进行合并] [至此，工作完成] [二、] [批量文件编码转换] [本操作有风险，请注意操作前备份文件。] [1.将原来所有编码为gb2312的*.java文件转换为编码为utf-8的*.java.new文件] [for i in `find . -name \”*.java\”`; do iconv -f gb2312 -t utf-8 \$i-o \$i.new; done] [2.将*.java.new文件的.new扩展名去除] [find . -name \”*.new\” | sed \’s/\(.*\).new\$/mv \”&amp;\” \”\1\”/\’ |sh] [三、] [linux下有许多方便的小工具来转换编码，] [文本内容转换iconv] [文件名转换convmv] [mp3标签转换python-mutagen] [四、] [用法： iconv [选项…][文件…]] [转换给定文件的编码。] [输入/输出格式规范：] [-f, –from-code=名称原始文本编码] [-t, –to-code=名称输出编码] [信息：] [-l, –list列举所有已知的字符集] [输出控制：] [-c从输出中忽略无效的字符] [-o, –output=FILE输出文件] [-s, –silent关闭警告] [–verbose打印进度信息] [-?, –help给出该系统求助列表] [–usage给出简要的用法信息] [-V, –version打印程序版本号] [五、] [find default -type d -exec mkdir -p utf/{}\;] [find default -type f -exec iconv -f GBK -t UTF-8 {} -o utf/{}\;] [这两行命令将default目录下的文件由GBK编码转换为UTF-8编码，目录结构不变，转码后的文件保存在utf/default目录下。] [六、] [Linux下文件名编码批量转换convmv] [由于FC将字符编码统一成了UTF8，原来在gb18030下建立的ext3分区中的文件和目录，一挂载到FC上就显示成乱码。google遍整个互联网，说对于目录名和文件名，有一个叫convmv的软件可以对其进行自动转换。] [今日下载了convmv，摸索了一套使用方法如下：] [convmv -f code1 -t code2-r] [code1:分区原来使用的字符集编码。支持gb2312、gbk、big5，不支持gb18030和big5-hkscs。] [code2：预转换到的字符集编码。对于FC，这里填写utf8] [-r参数：转换子目录。] [dir：要转换的目录，当前目录用./表示。] [回车执行，这个时候convmv会显示执行的结果，但不会真正对文件进行修改。并提示使用–replace参数进行修改。] [七、] [批量转换文件的编码] [for i in `find ./ -name *.htm` ; do echo \$i;iconv -f gb18030 -tutf8 \$i -o /tmp/iconv.tmp;mv /tmp/iconv.tmp \$i;done] [find -name “*.htm“\] [-exec iconv -f gb2312 -t utf8 ‘{}‘ -o /tmp/iconv.tmp \;\] [-exec mv /tmp/iconv.tmp ‘{}‘\;]]]></content>
      <categories>
        <category>日常记录</category>
      </categories>
      <tags>
        <tag>日常记录</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Top 命令详解]]></title>
    <url>%2F2015%2F01%2F03%2F65%2F</url>
    <content type="text"><![CDATA[TOP命令是Linux下常用的性能分析工具，能够实时显示系统中各个进程的资源占用状况。 TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间对任务进行排序；而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定. top - 12:38:33 up 50 days, 23:15, 7 users, load average: 60.58, 61.14,61.22 Tasks: 203 total, 60 running, 139 sleeping, 4 stopped, 0 zombie Cpu(s) : 27.0%us, 73.0%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 1939780k total, 1375280k used, 564500k free, 109680k buffers Swap: 4401800k total, 497456k used, 3904344k free, 848712k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4338 oracle 25 0 627m 209m 207m R 0 11.0 297:14.76 oracle 4267 oracle 25 0 626m 144m 143m R 6 7.6 89:16.62 oracle 3458 oracle 25 0 672m 133m 124m R 0 7.1 1283:08 oracle 3478 oracle 25 0 672m 124m 115m R 0 6.6 1272:30 oracle 3395 oracle 25 0 672m 122m 113m R 0 6.5 1270:03 oracle 3480 oracle 25 0 672m 122m 109m R 8 6.4 1274:13 oracle 3399 oracle 25 0 672m 121m 110m R 0 6.4 1279:37 oracle 4261 oracle 25 0 634m 100m 99m R 0 5.3 86:13.90 oracle 25737 oracle 25 0 632m 81m 74m R 0 4.3 272:35.42 oracle 7072 oracle 25 0 626m 72m 71m R 0 3.8 6:35.68 oracle 16073 oracle 25 0 630m 68m 63m R 8 3.6 175:20.36 oracle 16140 oracle 25 0 630m 66m 60m R 0 3.5 175:13.42 oracle 16122 oracle 25 0 630m 66m 60m R 0 3.5 176:47.73 oracle 786 oracle 25 0 627m 63m 63m R 0 3.4 1:54.93 oracle 4271 oracle 25 0 627m 59m 58m R 8 3.1 86:09.64 oracle 4273 oracle 25 0 627m 57m 56m R 8 3.0 84:38.20 oracle 22670 oracle 25 0 626m 50m 49m R 0 2.7 84:55.82 oracle 一. TOP前五行统计信息 统计信息区前五行是系统整体的统计信息。 1. 第一行是任务队列信息 同 uptime 命令的执行结果: [root@localhost ~]# uptime 13:22:30 up 8 min, 4 users, load average: 0.14, 0.38, 0.25 其内容如下： 12:38:33 当前时间 up 50days 系统运行时间，格式为时:分 1 user 当前登录用户数 load average: 0.06, 0.60, 0.48 系统负载，即任务队列的平均长度。 三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。 2. 第二、三行为进程和CPU的信息 当有多个CPU时，这些内容可能会超过两行。内容如下： Tasks: 29 total 进程总数 1 running 正在运行的进程数 28 sleeping 睡眠的进程数 0 stopped 停止的进程数 0 zombie 僵尸进程数 Cpu(s): 0.3% us 用户空间占用CPU百分比 1.0% sy 内核空间占用CPU百分比 0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比 98.7% id 空闲CPU百分比 0.0% wa 等待输入输出的CPU时间百分比 0.0% hi 0.0% si 3. 第四五行为内存信息。 内容如下： Mem: 191272k total 物理内存总量 173656k used 使用的物理内存总量 17616k free 空闲内存总量 22052k buffers 用作内核缓存的内存量 Swap: 192772k total 交换区总量 0k used 使用的交换区总量 192772k free 空闲交换区总量 123988k cached 缓冲的交换区总量。内存中的内容被换出到交换区，而后又被换入到内存，但使用过的交换区尚未被覆盖，该数值即为这些内容已存在于内存中的交换区的大小。相应的内存再次被换出时可不必再对交换区写入。 二. 进程信息 列名 含义 PID 进程id PPID 父进程id RUSER Real user name UID 进程所有者的用户id USER 进程所有者的用户名 GROUP 进程所有者的组名 TTY 启动进程的终端名。不是从终端启动的进程则显示为 ? PR 优先级 NI nice值。负值表示高优先级，正值表示低优先级 P 最后使用的CPU，仅在多CPU环境下有意义 %CPU 上次更新到现在的CPU时间占用百分比 TIME 进程使用的CPU时间总计，单位秒 TIME+ 进程使用的CPU时间总计，单位1/100秒 %MEM 进程使用的物理内存百分比 VIRT 进程使用的虚拟内存总量，单位kb。VIRT=SWAP+RES SWAP 进程使用的虚拟内存中，被换出的大小，单位kb。 RES 进程使用的、未被换出的物理内存大小，单位kb。RES=CODE+DATA CODE 可执行代码占用的物理内存大小，单位kb DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小，单位kb SHR 共享内存大小，单位kb nFLT 页面错误次数 nDRT 最后一次写入到现在，被修改过的页面数。 S 进程状态。 D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 COMMAND 命令名/命令行 WCHAN 若该进程在睡眠，则显示睡眠中的系统函数名 Flags 任务标志，参考 sched.h top 的man 命令解释如下： Listed below are top\&apos;s available fields. They are always associated with the letter shown, regardless of the position you mayhave established for them with the \’o\’ (Order fields) interactivecommand.Any field is selectable as the sort field, and you controlwhether they are sorted high-to-low or low-to-high. For additional information on sort provisions see topic 3c. TASK Area Commands. a: PID – Process Id The task\&apos;s unique process ID, which periodically wraps, though never restarting at zero. b: PPID – Parent Process Pid The process ID of a task\&apos;s parent. c: RUSER – Real User Name The real user name of the task\&apos;s owner. d: UID – User Id The effective user ID of the task\&apos;s owner. e: USER – User Name The effective user name of the task\&apos;s owner. f: GROUP – Group Name The effective group name of the task\&apos;s owner. g: TTY – Controlling Tty The name of the controlling terminal. This is usually the device (serial port, pty, etc.) from which the process was started, andwhich it uses for input oroutput. However, a task need not beassociated with a terminal, in which case you\’ll see \’?\’ displayed. h: PR – Priority The priority of the task. i: NI – Nice value The nice value of the task. A negative nice value means higher priority, whereas a positive nice value means lower priority. Zero in this field simply means priority will not be adjusted indetermining a task\’s dispatchability. j: P – Last used CPU (SMP) A number representing the last used processor. In a true SMP environment this will likely change frequently since the kernelintentionally uses weak affinity. Also, the very act of running top maybreak this weak affinity and cause more processes to change CPUsmore often (because of the extra demand for cpu time). k: %CPU – CPU usage The task\&apos;s share of the elapsed CPU time since the last screen update, expressed as a percentage of total CPU time. In a true SMPenvironment, if \’Irix mode\’ is Off, top will operate in \’Solarismode\’ where a task\’s cpu usage will be divided by the total number of CPUs. You toggle \’Irix/Solaris\’ modes with the \’I\’interactive command. l: TIME – CPU Time Total CPU time the task has used since it started. When \’Cumulative mode\’ is On, each process is listed with the cpu timethat it and its dead children has used. You toggle \’Cumulative mode\’with \’S\’, which is a command-line option and an interactive command. See the \’S\’ interactive command for additional information regardingthis mode. m: TIME+ – CPU Time, hundredths The same as \&apos;TIME\&apos;, but reflecting more granularity through hundredths of a sec ond. n: %MEM – Memory usage (RES) A task\&apos;s currently used share of available physical memory. o: VIRT – Virtual Image (kb) The total amount of virtual memory used by the task. It includes all code, data and shared libraries plus pages that have been swapped out. (Note: you can define the STATSIZE=1 environment variable andthe VIRT will be calculated from the /proc/#/state VmSize field.) VIRT = SWAP + RES. p: SWAP – Swapped size (kb) The swapped out portion of a task\&apos;s total virtual memory image. q: RES – Resident size (kb) The non-swapped physical memory a task has used. RES = CODE + DATA. r: CODE – Code size (kb) The amount of physical memory devoted to executable code, also known as the\’text resident set\’ size or TRS. s: DATA – Data+Stack size (kb) The amount of physical memory devoted to other than executable code, also known the \’data resident set\’ size or DRS. t: SHR – Shared Mem size (kb) The amount of shared memory used by a task. It simply reflects memory that could be potentially shared with otherprocesses. u: nFLT – Page Fault count The number of major page faults that have occurred for a task. A page fault occurs when a process attempts to read from or writeto a virtual page that is not currently present in its addressspace. A major page fault is when disk access is involved in makingthat page available. v: nDRT – Dirty Pages count The number of pages that have been modified since they were last written to disk. Dirty pages must be written to disk beforethe corresponding physical memory location can be used for some othervirtual page. w: S – Process Status The status of the task which can be one of: \&apos;D\&apos; = uninterruptible sleep \&apos;R\&apos; = running \&apos;S\&apos; = sleeping \&apos;T\&apos; = traced or stopped \&apos;Z\&apos; = zombie Tasks shown as running should be more properly thought of as \’ready to run\’ –their task_struct is simply represented on theLinux run-queue. Even without a true SMP machine, you may see numeroustasks in this state depending on top\’s delay interval and nicevalue. x: Command – Command line or Program name Display the command line used to start a task or the name of the associated program. You toggle between command line and name with\’c\’, which is both a command-line option and an interactive command.When you\’ve chosen to display command lines, processes without acommand line (like kernel threads) will be shown with only the programname in parentheses, as in this example: ( mdrecoveryd) Either form of display is subject to potential truncation if it\’stoo long to fit in this field\’s current width. That width depends upon other fields selected, their order and the current screenwidth. Note: The \&apos;Command\&apos; field/column is unique, in that it is not fixed-width. When displayed, this column will be allocated allremaining screen width (up to the maximum 512 characters) to provide for the potential growth of program names into command lines. y: WCHAN – Sleeping in Function Depending on the availability of the kernel link map (\’System.map\’), this field will show the name or the address ofthe kernel function in which the task is currently sleeping. Runningtasks will display a dash (\’-\’) in this column. Note: By displaying this field, top\&apos;s own working set will be increased by over 700Kb. Your only means of reducing that overheadwill be to stop and restart top. z: Flags – Task Flags This column represents the task\&apos;s current scheduling flags which are expressed in hexadecimal notation and with zeros suppressed. These flags are officially documented in &lt;linux/sched.h&gt;. Lessformal documentation can also be found on the \’Fields select\’ and\’Order fields\’ screens. 默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。 2.1 用快捷键更改显示内容。 （1）更改显示内容通过 f键可以选择显示的内容。 按 f 键之后会显示列的列表，按 a-z 即可显示或隐藏对应的列，最后按回车键确定。 （2）按o键可以改变列的显示顺序。 按小写的 a-z 可以将相应的列向右移动，而大写的 A-Z 可以将相应的列向左移动。最后按回车键确定。 按大写的 F 或 O 键，然后按 a-z 可以将进程按照相应的列进行排序。而大写的 R 键可以将当前的排序倒转。 设置完按回车返回界面。 三. 命令使用 详细内容可以参考MAN 帮助文档。这里列举部分内容： 命令格式： top [-] [d] [p] [q] [c] [C] [S] [n] 参数说明： d： 指定每两次屏幕信息刷新之间的时间间隔。当然用户可以使用s交互命令来改变之。 p： 通过指定监控进程ID来仅仅监控某个进程的状态。 q：该选项将使top没有任何延迟的进行刷新。如果调用程序有超级用户权限，那么top将以尽可能高的优先级运行。 S： 指定累计模式 s ： 使top命令在安全模式中运行。这将去除交互命令所带来的潜在危险。 i： 使top不显示任何闲置或者僵死进程。 c： 显示整个命令行而不只是显示命令名 在top命令的显示窗口，我们还可以输入以下字母，进行一些交互： 帮助文档如下： Help for Interactive Commands - procps version 3.2.7 Window 1:Def: Cumulative mode Off. System: Delay 4.0 secs; Secure modeOff. Z,B Global: \’Z\’ change color mappings; \’B\’ disable/enablebold l,t,m Toggle Summaries: \’l\’ load avg; \’t\’ task/cpu stats;\’m\’ mem info 1,I Toggle SMP view: \’1\’ single/separate states; \’I\’Irix/Solaris mode f,o . Fields/Columns: \’f\’ add or remove; \’o\’ change displayorder F or O . Select sort field &lt;,&gt; . Move sort field: \’&lt;\’ next col left; \’&gt;\’ nextcol right R,H . Toggle: \’R\’ normal/reverse sort; \’H\’ show threads c,i,S . Toggle: \’c\’ cmd name/line; \’i\’ idle tasks; \’S\’cumulative time x,y . Toggle highlights: \’x\’ sort field; \’y\’ running tasks z,b . Toggle: \’z\’ color/mono; \’b\’ bold/reverse (only if \’x\’or \’y\’) u . Show specific user only n or # . Set maximum tasks displayed k,r Manipulate tasks: \’k\’ kill; \’r\’ renice d or s Set update interval W Write configuration file q Quit ( commands shown with \&apos;.\&apos; require a visible task display window ) Press \’h\’ or \’?\’ for help with Windows, h或者? : 显示帮助画面，给出一些简短的命令总结说明。 k ：终止一个进程。系统将提示用户输入需要终止的进程PID，以及需要发送给该进程什么样的信号。一般的终止进程可以使用15信号；如果不能正常结束那就使用信号9强制结束该进程。默认值是信号15。在安全模式中此命令被屏蔽。 i：忽略闲置和僵死进程。这是一个开关式命令。 q： 退出程序。 r： 重新安排一个进程的优先级别。系统提示用户输入需要改变的进程PID以及需要设置的进程优先级值。输入一个正值将使优先级降低，反之则可以使该进程拥有更高的优先权。默认值是10。 S：切换到累计模式。 s : 改变两次刷新之间的延迟时间。系统将提示用户输入新的时间，单位为s。如果有小数，就换算成ms。输入0值则系统将不断刷新，默认值是5s。需要注意的是如果设置太小的时间，很可能会引起不断刷新，从而根本来不及看清显示的情况，而且系统负载也会大大增加。 f或者F :从当前显示中添加或者删除项目。 o或者O :改变显示项目的顺序。 l: 切换显示平均负载和启动时间信息。即显示影藏第一行 m： 切换显示内存信息。即显示影藏内存行 t ： 切换显示进程和CPU状态信息。即显示影藏CPU行 c： 切换显示命令名称和完整命令行。 显示完整的命令。 这个功能很有用。 M ： 根据驻留内存大小进行排序。 P：根据CPU使用百分比大小进行排序。 T： 根据时间/累计时间进行排序。 W： 将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[photoshopCS和ImageReady CS的序列号]]></title>
    <url>%2F2015%2F01%2F03%2F66%2F</url>
    <content type="text"><![CDATA[.mb-10&#125;1234567mageReady CS是photoshopCS捆绑的，一个序列号两个通用。1045-0502-9715-8471-5218-7925 1045-1423-6436-0168-7941-1739 1045-1189-6296-3291-6041-1048 1045-1084-6341-6905-7261-7154 1045-1380-6674-5614-0950-9671 1045-0698-5460-2637-3409-8631]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[SSh登陆失败的日志查看与攻击预防]]></title>
    <url>%2F2015%2F01%2F03%2F67%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/363278]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[如何保持SSH连接的linux服务器不断线]]></title>
    <url>%2F2015%2F01%2F03%2F68%2F</url>
    <content type="text"><![CDATA[[windows系统] 使用SecureCRT连接远程服务器，在会话选项 -&gt; 终端设置中勾选“发送协议NO-OP”。 使用putty连接远程服务器，找到Connection -&gt; Seconds between keepalives( 0 to turn off )， 默认为0，改为60。 {width=”533”height=”436”} [Linux系统] 在linux系统中使用ssh连接远程服务器时，可以使用-o的一个参数ServerAliveInterval来设置防止超时的时间。 比如：ssh -o serveraliveinterval=60username@host [服务器配置修改] 修改ssh配置文件/etc/ssh/sshd_config，添加或者修改ClientAliveInterval为“ClientAliveInterval 60”。这个参数的是意思是每1分钟，服务器向客户端发一个消息，用于保持连接。保存后记得重启ssh服务。 修改过后，上面几个办法都可以让ssh保持连接，一直处于alive状态，不会因为没有操作而被服务器强制断线了。]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[开源web终端ssh解决方案——gateone]]></title>
    <url>%2F2014%2F12%2F31%2F69%2F</url>
    <content type="text"><![CDATA[[1.首先来说一下为什么要webssh?] [有人是说，有xshell，secureRT，putty等众多的ssh终端，为嘛还要弄个web的ssh，不是够二的吗？能起多大作用？] [有个web的ssh，的确没有多大作用，的确无法代替ssh客户端，但是你想过没有，类似于xshell，secureRT，putty，在运维管理中确实有很多麻烦，不同的用户，需要不同的登录名，授权等等管理，而且存在一定的风险，比如个人电脑被攻击等等安全问题？] [\] [总结：] [对于的小型公司如只有50~100来台左右的服务器的话，在实际的使用中是没有必要去使用web-ssh解决方案的,传统的方法来连接和管理Linux服务器就能够维护好了。] [但是我们在实际的使用过程中,随着服务器的越来越多,传统的secureCRT来管理越来越麻烦,因为服务器增加到了几百台,(secureCRT目录和连接list会越来越多)当我们需要去连接其中某些机器的时候,当需要快速] [连接和定位问题的时候,在查找和连接的时候的也要耗费一定的时间。这并不是我们想要的,所以才迫切需要机遇web-ssh解决方案。] [\] [2.是否有解决方案呢？] [其实，很多公司目前都会用堡垒机，跳板机等一系列安全措施来防止系统非法访问，不少公司都已经实现了登录系统需要手机验证码了，不失为一种安全解决方案。] [\] [3.是否还有其他解决方案呢？] [那么，这里我推荐一个可以替代运维堡垒机的功能的一个软件，那就是这里的gateone。] [在说运维堡垒机之前，先来了解下什么是运维堡垒机？] [运维堡垒机的理念起源于跳板机，那么跳板机的弱势在哪里？] [**[理念一：唯有控制才能真正解决问题] [**[理念二：系统账号无法确认用户身份] [**[理念三：人为操作难免会出问题] [于是，产生了后来的运维堡垒机，运维堡垒机具有对运维人员的身份认证、对运维操作的访问控制和审计等功能（来自看百度百科的解释http://baike.baidu.com/view/4274690.htm，目前有不少厂家可以提供运维堡垒机产品，但是，作为devops或是运维人员，喜欢自己动手去实现功能！] [\] [**[4.推荐方案] [可以看到，运维堡垒机好处很多，有效的控制了运维风险，而今天给大家介绍的gateone，就是一套自己的开源堡垒机解决方案。] [\] [5.Gateone的简介] [个人认为gateone是一个高端大气上档次的webssh，同类产品中，要么是体验不好，要么就是界面看着不顺眼，要么还带着细微的bug，直到遇到了gateone，才觉得webssh原来可以这么好用。] [不妨看看都有哪些web的ssh终端] [https://github.com/aluzzardi/wssh] [https://code.google.com/p/shellinabox] [http://code.google.com/p/web-shell] [https://github.com/antonylesuisse/qweb] [大家可以一一尝试的。] [\] [GateOne 是一款使用 HTML5 技术编写的网页版 SSH 终端模拟器。] [· 基于现代的 HTML5 技术，无需任何浏览器插件。] [· 支持多个 SSH 进程。] [· 可以嵌入到其他任意应用程序中。] [· 支持使用 JavaScript，Python 甚至纯 CSS 编写的插件。] [· 支持 SSH 进程副本，打开多个进程而无需重复输入密码。] [· 支持各种服务器端的日志功能，支持 Keberos-based 单点登录甚至活动目录。] [· 支持操作日志记录，具有操作记录回放功能] [\] [项目地址 https://github.com/liftoff/GateOne] [文档地址 http://liftoff.github.io/GateOne/About/] [开发语言 python] [框架 tornado+html5] [当前版本 1.1] [安装简单，使用方便，更多功能请参看官方文档。] [6. 安装 gateone] [\] [我的系统版本是CentOS release 6.464bit] [\] [浏览器版本是chrome30，看官方文档，gateone在ie浏览器不受支持（鄙视ie，虽然我的电脑上有ie浏览器，但是一直都让其躺着睡打觉的），支持的浏览器有chrome，firefox，所以若是你用ie不能显示……] [\] [\] [\] [#wget https://github.com/downloads/liftoff/GateOne/tornado-2.4-1.noarch.rpm] [\] [#wget https://github.com/downloads/liftoff/GateOne/gateone-1.1-1.noarch.rpm] [\] [[# rpm-ivh ] [\] [] [] [# yum localinstall tornado-2.4-1.noarch.rpm# yumlocalinstallgateone-1.1-1.noarch.rpm# easy_install installordereddict] [\] [] [#cd/opt/gateone#./gateone.py#运行这个脚本，会生成server.conf配置文件] [\] [假如出现以下错误] [\] [] [是提示你没有安装 ordereddict] [\] [好了，启动服务] [\] [#cd /opt/gateone] [\] [#./gateone.py] [\] [\] [] [gateone安装脚本：] [ http://pan.baidu.com/s/1qW4sHLM] [] [如果你想让其后台运行，请使用serveri来启动] [\] [#/etc/init.d/gateone start] [\] [] [ok，服务启动成功，通过浏览器去访问] [\] [我的ip地址是192.168.0.201] [\] [所以访问地址为https://192.168.0.201,点击继续] [\] [] [如果出现以下提示信息，则按照以下步骤处理即可] [\] [] [提示此url访问被拒绝了，看web日志如下] [\] [] [1.修改] [\] [*[#vim/opt/gateone/server.conf] [\] [] [] [如果一切顺利，讲看到如下界面] [\] [] [] [哈哈，终于进入系统， ls 以下] [\] [] [来个 vim /etc/passwd 试试] [\] [] [别急，还有日志审计功能，支持日志回放哦！] [\] [] [一个屏是不是有些单调呢，来，开 4 个屏试试] [\] [] [还有更多好玩的功能，显示图片] [\] [] [] [] [] [怎么样，如果还没有看够，建议你赶快动手试试？去体验以下 webssh 的魅力！] [\] [怎么样，是不是高端大气上档次？] [\] [\] [\] [7.说了这么多，不是说好的要弄什么运维堡垒机的功能吗，我怎么没有看到，别急，这正是我要说的功能。] [Gateone提供了基于web的ssh功能，那么，资产系统，运维系统，其他用户权限分配系统，以及日志回放功能，需要devops自己去开发，结合gateone，保证让你玩的爽歪歪，至于怎么去开发这个堡垒机功能的系统，自己慢慢体会哦，这里就点到为止！] [8.web-ssh api接口开发] [先上图] []\ [] [博客原文取自（部分已修改）：http://itnihao.blog.51cto.com/1741976/1311506]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Config::IniFiles模块的安装]]></title>
    <url>%2F2014%2F10%2F27%2F70%2F</url>
    <content type="text"><![CDATA[1perl -MCPAN -e 'install Module::Build' .;toolbar: .true; .auto-links: .false;&#125;1perl -MCPAN -e &apos;install Config::IniFiles&apos; config模块使用方法: 12345678910use Config::IniFiles;my $cfg = Config::IniFiles-&gt;new( -file =&gt; "config.ini") ; if ($cfg)&#123; my $username = $cfg-&gt;val( 'auth', 'username' ) ; # print "用户名:". $username ; # say ""; &#125;else&#123; say "请确认配置文件是否存在,退出任务!"; exit; &#125;]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[备份数据删除和腾讯云数据库下载脚本]]></title>
    <url>%2F2014%2F10%2F14%2F71%2F</url>
    <content type="text"><![CDATA[12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667#!/bin/bashbase_dir=/data/Mysql-BackCenterdelete_day=30delete_log_dir=/data/log/deletedownload_dir=$base_dir/ZZB-7vardate=$(date +%Y%m%d)datebefore=$(date -d "1 days ago" +%Y%m%d)cdmdump=$base_dir/cdb_dump_tool [[ -d $delete_log_dir ]] || mkdir -p $delete_log_dirprint_to_log()&#123;echo "[ $(date "+%Y-%m-%d %H:%M:%S") ] $1" &gt;&gt; $delete_log_dir/delete.log&#125;print_log()&#123;echo "[ $(date "+%Y-%m-%d %H:%M:%S") ] $1" &gt;&gt; $delete_log_dir/download.log&#125;function delete_file()&#123;delete_total_num=$(find $base_dir -type f -mtime +$delete_day |grep "tar.gz$"|wc -l)print_to_log "开始删除$delete_day天前的数据压缩包..."print_to_log "删除数量:$delete_total_num"if [[ $delete_total_num -ne 0 ]];then for i in $(find $base_dir -type f -mtime +$delete_day |grep "tar.gz$")doprint_to_log "开始删除: $i"rm -f $iif [[ $? -eq 0 ]];thenprint_to_log "删除$i,成功!"else print_to_log "删除$i,失败...!"fidoneelse print_to_log "$delete_day天前的历史压缩数据不存在..."fi print_to_log "删除结束."&#125;function download_sql()&#123;cd $base_dir[[ -d $download_dir/$vardate ]] || mkdir -p $download_dir/$vardate $cdmdump APPID 实例名称 $datebefore $download_dir/$vardate if [[ $? -eq 0 ]];thenprint_log "Download 实例名称 $datebefore 成功!"download_file_size=$(du -sh $download_dir/$vardate |awk '&#123;print $1&#125;')print_log "$download_dir/$vardate 源目录大小: $download_file_size"cd $base_dir/$download_dirtar -zcf $vardate.tar.gz $vardate rm -fr $download_dir/$vardate else print_log "Download 实例名称 $datebefore 失败!"fi &#125;delete_filedownload_sql]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[亚马逊VPC实操相关文档]]></title>
    <url>%2F2014%2F10%2F14%2F72%2F</url>
    <content type="text"><![CDATA[]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Bash漏洞测试和升级摘要]]></title>
    <url>%2F2014%2F09%2F29%2F73%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/323158]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Windows下wnmp快速部署]]></title>
    <url>%2F2014%2F09%2F25%2F74%2F</url>
    <content type="text"><![CDATA[解压安装位置: C:\Users\Administrator\Desktop\Wnmp 一定要是这个位置哦,配置文件里面写死了这个固定的位置 如果要修改： 则修改如下文件: C:\Users\Administrator\Desktop\Wnmp\php5.6\php.ini C:\Users\Administrator\Desktop\Wnmp\nginx-1.6.1\conf\nginx.conf C:\Users\Administrator\Desktop\Wnmp\mysql-5.6.17-winx64\my.cnf 还有脚本位置也需要修改: mysqlStart.bat mysql启动脚本,启动后不会退出cmd,可以看到启动过程的日志. mysqlStart.vbs [ mysql启动脚本,启动后在后台运行.] mysqlStop.bat mysql停止脚本. nginx_start.bat nginx启动脚本 phpStart.vbs php启动后置于后台 php_start.bat php启动,启动会打开cmd窗口 wnmp-Start.bat (这个好像有点问题,没仔细研究了) mysq[l] kill语句: taskkill /f /immysqld.exe nginx kill语句: taskkill /f /im nginx.exe php kill语句: taskkill /f /im php-cgi.exe Download url: http://pan.baidu.com/s/1pJCzXk3\]]></content>
      <categories>
        <category>Windows</category>
      </categories>
      <tags>
        <tag>Windows</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[nginx多域名ssl证书以及lua模块的编译安装]]></title>
    <url>%2F2014%2F08%2F12%2F75%2F</url>
    <content type="text"><![CDATA[123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#!/bin/bash#unzip zip&amp;tar filefunction untarfile()&#123;for i in $( ls . |grep -v .sh)doval=$(echo $i | grep ".zip$" |wc -l)if [[ "$val" -eq 1 ]];thendirname=$(echo $i|sed "s/.zip//")if [[ ! -d $dirname ]];thenecho "Unzip file: $dirname..."unzip $i &gt; /dev/nullfielsedirname=$(echo $i|sed "s/.tar.gz//")if [[ ! -d $dirname ]];thentar -zxvf $i &gt; /dev/nullecho "Tar file: $dirname..."fifidonesleep 2echo "[ unzip files ] have finished!"&#125;#untarfile#install allfunction installLua ()&#123;#LuaJITif [[ ! -d /usr/local/lj2/ ]];thencd LuaJIT-2.0.2make PREFIX=/usr/local/lj2/make install PREFIX=/usr/local/lj2/elseecho "[ /usr/local/lj2/ ]: Directory have exists,exit!"fiecho "[ install LuaJIT ] have finished!"sleep 2&#125;function installnginx ()&#123;if [[ ! -d /usr/local/nginx ]];thencd nginx-1.6.1./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module --without-select_module --without-poll_module --with-openssl=../openssl-1.0.1i --add-module=../ngx_devel_kit-0.2.19 --add-module=../lua-nginx-module-0.9.10makemake -j2make installecho "/usr/local/lj2/lib/" &gt; /etc/ld.so.conf.d/lj2.confldconfigelseecho "[ /usr/local/nginx ]: Directory have exists,exit!"fiecho "[ install nginx ] have finished!"sleep 2&#125;untarfileinstallLuainstallnginx 最新源码 包以及安装脚本位置: nginx的ssl和lua模块相关包]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Linux tcpdump命令详解]]></title>
    <url>%2F2014%2F07%2F08%2F76%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/288172]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[log4j配置文件模版]]></title>
    <url>%2F2014%2F06%2F18%2F77%2F</url>
    <content type="text"><![CDATA[log4j.properties .true; .auto-links: .false;&#125;12345678910111213141516171819202122232425262728log4j.rootLogger=DEBUG, INFO, ERROR# 输出控制台log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.Threshold=INFOlog4j.appender.CONSOLE.Target=System.outlog4j.appender.CONSOLE.Encoding=UTF-8log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=[%p]%d&#123;yyyy-MM-dd HH:mm:ss&#125; %l - %m%n### 输出INFO到日志文件 ###log4j.appender.INFO = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.INFO.File = /data/log/messagePush/messagePush_info.log#log4j.appender.INFO.File = D:/work/projects/message/trunk/baoxian-message-push/log/messagePush_info.loglog4j.appender.INFO.Append = truelog4j.appender.INFO.Threshold = INFOlog4j.appender.INFO.Encoding=UTF-8log4j.appender.INFO.layout = org.apache.log4j.PatternLayoutlog4j.appender.INFO.layout.ConversionPattern = [%p] %d&#123;yyyy-MM-dd HH:mm:ss&#125; %l - %m%n### 输出ERROR到日志文件 ###log4j.appender.ERROR = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.ERROR.File = /data/log/messagePush/messagePush_error.log#log4j.appender.ERROR.File = D:/work/projects/message/trunk/baoxian-message-push/log/messagePush_error.loglog4j.appender.ERROR.Append = truelog4j.appender.ERROR.Threshold = ERRORlog4j.appender.ERROR.Encoding=UTF-8log4j.appender.ERROR.layout = org.apache.log4j.PatternLayoutlog4j.appender.ERROR.layout.ConversionPattern = [%p] %d&#123;yyyy-MM-dd HH:mm:ss&#125; %l - %m%n log4j.xml .true; .auto-links: .false;&#125;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;&lt;!DOCTYPE log4j:configuration SYSTEM &quot;log4j.dtd&quot;&gt;&lt;log4j:configuration xmlns:log4j=&quot;http://jakarta.apache.org/log4j/&quot;&gt; &lt;appender name=&quot;debug-out&quot; class=&quot;org.apache.log4j.RollingFileAppender&quot;&gt; &lt;param name=&quot;File&quot; value=&quot;/data/log/openfire/debug.log&quot; /&gt; &lt;param name=&quot;MaxFileSize&quot; value=&quot;1024KB&quot;/&gt; &lt;param name=&quot;MaxBackupIndex&quot; value=&quot;5&quot;/&gt; &lt;layout class=&quot;org.apache.log4j.PatternLayout&quot;&gt; &lt;param name=&quot;ConversionPattern&quot; value=&quot;%d&#123;yyyy.MM.dd HH:mm:ss&#125; %c - %m%n&quot; /&gt; &lt;/layout&gt; &lt;filter class=&quot;org.apache.log4j.varia.LevelRangeFilter&quot;&gt; &lt;param name=&quot;LevelMax&quot; value=&quot;debug&quot; /&gt; &lt;param name=&quot;AcceptOnMatch&quot; value=&quot;true&quot; /&gt; &lt;/filter&gt; &lt;/appender&gt; &lt;appender name=&quot;info-out&quot; class=&quot;org.apache.log4j.RollingFileAppender&quot;&gt; &lt;param name=&quot;File&quot; value=&quot;/data/log/openfire/info.log&quot; /&gt; &lt;param name=&quot;MaxFileSize&quot; value=&quot;1024KB&quot;/&gt; &lt;param name=&quot;MaxBackupIndex&quot; value=&quot;5&quot;/&gt; &lt;layout class=&quot;org.apache.log4j.PatternLayout&quot;&gt; &lt;param name=&quot;ConversionPattern&quot; value=&quot;%d&#123;yyyy.MM.dd HH:mm:ss&#125; %c - %m%n&quot; /&gt; &lt;/layout&gt; &lt;filter class=&quot;org.apache.log4j.varia.LevelRangeFilter&quot;&gt; &lt;param name=&quot;LevelMax&quot; value=&quot;info&quot; /&gt; &lt;param name=&quot;LevelMin&quot; value=&quot;info&quot; /&gt; &lt;param name=&quot;AcceptOnMatch&quot; value=&quot;true&quot; /&gt; &lt;/filter&gt; &lt;/appender&gt; &lt;appender name=&quot;warn-out&quot; class=&quot;org.apache.log4j.RollingFileAppender&quot;&gt; &lt;param name=&quot;File&quot; value=&quot;/data/log/openfire/warn.log&quot; /&gt; &lt;param name=&quot;MaxFileSize&quot; value=&quot;1024KB&quot;/&gt; &lt;param name=&quot;MaxBackupIndex&quot; value=&quot;5&quot;/&gt; &lt;layout class=&quot;org.apache.log4j.PatternLayout&quot;&gt; &lt;param name=&quot;ConversionPattern&quot; value=&quot;%d&#123;yyyy.MM.dd HH:mm:ss&#125; %c - %m%n&quot; /&gt; &lt;/layout&gt; &lt;filter class=&quot;org.apache.log4j.varia.LevelRangeFilter&quot;&gt; &lt;param name=&quot;LevelMax&quot; value=&quot;warn&quot; /&gt; &lt;param name=&quot;LevelMin&quot; value=&quot;warn&quot; /&gt; &lt;param name=&quot;AcceptOnMatch&quot; value=&quot;true&quot; /&gt; &lt;/filter&gt; &lt;/appender&gt; &lt;appender name=&quot;error-out&quot; class=&quot;org.apache.log4j.RollingFileAppender&quot;&gt; &lt;param name=&quot;File&quot; value=&quot;/data/log/openfire/error.log&quot; /&gt; &lt;param name=&quot;MaxFileSize&quot; value=&quot;1024KB&quot;/&gt; &lt;param name=&quot;MaxBackupIndex&quot; value=&quot;5&quot;/&gt; &lt;layout class=&quot;org.apache.log4j.PatternLayout&quot;&gt; &lt;param name=&quot;ConversionPattern&quot; value=&quot;%d&#123;yyyy.MM.dd HH:mm:ss&#125; %c - %m%n&quot; /&gt; &lt;/layout&gt; &lt;filter class=&quot;org.apache.log4j.varia.LevelRangeFilter&quot;&gt; &lt;param name=&quot;LevelMin&quot; value=&quot;error&quot; /&gt; &lt;param name=&quot;AcceptOnMatch&quot; value=&quot;true&quot; /&gt; &lt;/filter&gt; &lt;/appender&gt; &lt;!-- OF-506: Jetty INFO messages are generally not useful. Ignore them by default. --&gt; &lt;logger name=&quot;org.eclipse.jetty&quot;&gt; &lt;level value=&quot;warn&quot; /&gt; &lt;/logger&gt; &lt;root&gt; &lt;level value=&quot;info&quot; /&gt; &lt;appender-ref ref=&quot;debug-out&quot; /&gt; &lt;appender-ref ref=&quot;info-out&quot; /&gt; &lt;appender-ref ref=&quot;warn-out&quot; /&gt; &lt;appender-ref ref=&quot;error-out&quot; /&gt; &lt;/root&gt; &lt;/log4j:configuration&gt;]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[标准化启动脚本的构建与cronolog的日志分割]]></title>
    <url>%2F2014%2F06%2F17%2F78%2F</url>
    <content type="text"><![CDATA[[先上标准化启动脚本:] 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596#!/bin/bash# chkconfig: 2345 93 11# description:$INS_APP Server. /etc/rc.d/init.d/functionsJAVA_HOME="/usr/local/jdk"PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:$JAVA_HOME/binexport PATHINS_APP="storm"KEY="ice"BASE_DIR="/data/www/apps/$INS_APP"LOG_DIR="/data/log/$INS_APP"LOG_FILE="/data/log/$INS_APP/$INS_APP.log"prog=$INS_APPpid_file=/var/run/$INS_APP.pidfunction app_action()&#123;APP_PORT=$(netstat -tpln |grep $KEY |grep -v grep |awk '&#123;print $4&#125;' |awk -F':' '&#123;print $NF&#125;')APP_PID=$(ps aux |grep $KEY |grep -v grep |awk '&#123;print $2&#125;')&#125;[[ -d /data/log/$INS_APP/ ]] || mkdir -p /data/log/$INS_APP/start() &#123;# JAVA_OPTS="-Xms1536M -Xmx1536M -Xss1M -XX:MaxPermSize=256M -XX:+UseParallelGC" if [[ ! -d $BASE_DIR ]];then echo "$INS_APP Directorg: $BASE_DIR isn't exist,exit!" exit fi cd $BASE_DIR #nohup icebox --Ice.Config=config.icebox &gt;&gt; $LOG_FILE 2&gt;&amp;1 &amp; nohup icebox --Ice.Config=config.icebox 2&gt;&amp;1 | /usr/local/sbin/cronolog $LOG_DIR/$INS_APP.%Y-%m-%d.log &amp; ret=$? if [ $ret -eq 0 ]; then action $"Starting $INS_APP: " /bin/true app_action echo $APP_PID &gt; $pid_file else action $"Starting $INS_APP: " /bin/false fi chmod 755 /etc/init.d/$INS_APP chkconfig --add $INS_APP chkconfig --level 3 $INS_APP on &#125;stop() &#123; app_action if [[ -z $APP_PID ]];then action $"Stopping $INS_APP: " /bin/false exit fi for i in $APP_PID do kill -9 $i done ret=$? if [ $ret -eq 0 ]; then action $"Stopping $INS_APP: " /bin/true rm -f $pid_file else action $"Stopping $INS_APP: " /bin/false fi&#125;restart() &#123; stop sleep 2 start&#125;case "$1" in start) start ;; stop) stop ;; status) status $prog ;; restart) restart ;; *) echo $"Usage: $0 &#123;start|stop|status|restart&#125;" exit 1esac [cronolog是[一款日志分割软件,以上范例日志文件将按天分割，每天产生一个新的日志文件。] 1 nohup icebox --Ice.Config=config.icebox 2&gt;&amp;1 | /usr/local/sbin/cronolog $LOG_DIR/$INS_APP.%Y-%m-%d.log &amp; cronolog源码包安装: http://pan.baidu.com/s/1ntiF90X]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[常用APP等日志分割与nginx日志分析脚本合集]]></title>
    <url>%2F2014%2F06%2F17%2F79%2F</url>
    <content type="text"><![CDATA[[针对app,resin,tomcat日志分割脚本]\ [appname：填写app（包含resin/tomcat）的名字;] [key：过滤日志关键字，避免删除其他不必要的文件;\] [cleanday：日志保存的周期，缺省保存30天;] [cleanlog:删除日志的记录保存的目录] [核心命令:find命令去查找日志目录下含关键字的日志文件,然后利用for循环去删除\$cleanday之前的日志文件] 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#!/bin/bash today=$(date +%Y_%m%d_%H%M)#appname=tomcat#logdir=/data/log/tomcat#key=log#key=catalina.outappname=stormlogdir=/data/log/$appnamekey=$appnamecleanday=30cleanlog=/data/log/cleanfilelist=$(find $logdir -type f -mtime +$cleanday |grep "$key" )[[ -d $cleanlog ]] || mkdir -p $cleanlogecho "[Date:`date`]"if [[ -z $filelist ]];thenecho "$appname logfile have't the $cleanday days ago file! ---exit！"echo "[ Date:`date` ] $appname logfile have't the $cleanday days ago file! ---exit！" &gt;&gt; $cleanlog/delete.logexitfiecho "Starting clean up the $appname is logfile for $cleanday days ago..."echo "Need to clean up the following directory:"echo "$filelist"echo "[ Date:`date` ]" &gt;&gt; $cleanlog/delete.logecho "Starting clean up the $appname is logfile..." &gt;&gt; $cleanlog/delete.logecho "Need to clean up the following directory:" &gt;&gt; $cleanlog/delete.logecho "$filelist" &gt;&gt; $cleanlog/delete.log for i in $filelistdorm -f $i#echo $i &gt; /dev/null 2&gt;&amp;1 donefilelist2=$(find $logdir -type f -mtime +$cleanday |grep "$key")if [[ -z $filelist2 ]];then echo "$appname logfile have cleanup ---successful!"echo "$appname logfile have cleanup ---successful!" &gt;&gt; $cleanlog/delete.logelse echo "$appname logfile have cleanup ---faild!"echo "$appname logfile faild file:"echo "$filelist2"echo "$appname logfile have cleanup ---faild!" &gt;&gt; $cleanlog/delete.logecho "$appname logfile faild file:" &gt;&gt; $cleanlog/delete.logecho "$filelist2" &gt;&gt; $cleanlog/delete.logfi [针对nginx日志分割脚本:] 12345#!/bin/bash path=/data/log/nginx nginx=` cat /usr/local/nginx/logs/nginx.pid ` mv $path/access.log $path/access_`date +%Y%m%d`.log kill -USR1 $nginx #使用USR1参数通知Nginx进程切换日志文 [] 1234567891011121314151617181920212223242526272829303132333435363738394041424344#!/bin/bash#Date create 2013-10-23#Author GaoMingHuanglog_path=/data/log/nginx/access.loglog_dir=/data/log/Analysisdomain="crm.baoxian.in"email="530035210@qq.com"maketime=`date +%Y-%m-%d" "%H":"%M`logdate=`date -d "yesterday" +%Y-%m-%d`dayone=`date +%d/%b/%Y`now=`date +%Y_%m%d_%H%M`date_start=$(date +%s)total_visit=`wc -l $&#123;log_path&#125; | awk '&#123;print $1&#125;'`total_bandwidth=`awk -v total=0 '&#123;total+=$10&#125;END&#123;print total/1024/1024&#125;' $&#123;log_path&#125;`total_unique=`awk '&#123;ip[$1]++&#125;END&#123;print asort(ip)&#125;' $&#123;log_path&#125;`ip_pv=`awk '&#123;ip[$1]++&#125;END&#123;for (k in ip)&#123;print ip[k],k&#125;&#125;' $&#123;log_path&#125; | sort -rn |head -20`url_num=`awk '&#123;url[$7]++&#125;END&#123;for (k in url)&#123;print url[k],k&#125;&#125;' $&#123;log_path&#125; | sort -rn | head -20`#referer=`awk -v domain=$domain '$11 !~ /http:\/\/[^/]*'"$domain"'/&#123;url[$11]++&#125;END&#123;for (k in url)&#123;print url[k],k&#125;&#125;' $&#123;log_path&#125; | sort -rn `notfound=`awk '$9 == 404 &#123;url[$7]++&#125;END&#123;for (k in url)&#123;print url[k],k&#125;&#125;' $&#123;log_path&#125; | sort -rn | head -20`#spider=`awk -F'"' '$6 ~ /Baiduspider/ &#123;spider["baiduspider"]++&#125; $6 ~ /Googlebot/ &#123;spider["googlebot"]++&#125;END&#123;for (k in spider)&#123;print k,spider[k]&#125;&#125;' $&#123;log_path&#125;`#search=`awk -F'"' '$4 ~ /http:\/\/www\.baidu\.com/ &#123;search["baidu_search"]++&#125; $4 ~ /http:\/\/www\.google\.com/ &#123;search["google_search"]++&#125;END&#123;for (k in search)&#123;print k,search[k]&#125;&#125;' $&#123;log_path&#125;`#echo -e "概况\n报告生成时间：$&#123;maketime&#125;\n总访问量:$&#123;total_visit&#125;\n总带宽:$&#123;total_bandwidth&#125;M\n独立访客:$&#123;total_unique&#125;\n\n访问IP统计\n$&#123;ip_pv&#125;\n\n访问url(统计前20个页面)\n$&#123;url_num&#125;\n\n来源页面统计\n$&#123;referer&#125;\n\n404统计(统计前20个页面)\n$&#123;notfound&#125;\n\n蜘蛛统计\n$&#123;spider&#125;\n\n搜索引擎来源统计\n$&#123;search&#125;" #统计该ip在干些什么max_ip=`awk '&#123;ip[$1]++&#125;END&#123;for (k in ip)&#123;print ip[k],k&#125;&#125;' $&#123;log_path&#125; | sort -rn |head -1 |awk '&#123;print $2&#125;'`ip_havi=`cat $log_path | grep "$max_ip" | awk '&#123;print $7&#125;'| sort |uniq -c |sort -nr |head -20`#统计当天哪个时间段访问量最多time_stats=`awk '&#123;print $4&#125;' $&#123;log_path&#125; | grep "$dayone" |cut -c 14-18 |sort|uniq -c|sort -nr |head -n 10`echo -e "概况\n报告生成时间：$&#123;maketime&#125;\n总访问量:$&#123;total_visit&#125;\n总带宽:$&#123;total_bandwidth&#125;M\n独立访客:$&#123;total_unique&#125;\n\n访问IP统计(统计前20个IP):\n$&#123;ip_pv&#125;\n\n访问url最多(统计前20个页面)\n:$&#123;url_num&#125;\n\n404统计(统计前20个页面):\n$&#123;notfound&#125;\n\n当天访问次数最多的时间段如下:\n$&#123;time_stats&#125;\n\n访问量最高的IP[$&#123;max_ip&#125;]前20个最多的页面如下:\n$&#123;ip_havi&#125; "[[ -d $log_dir ]] || mkdir -p $log_direcho -e "概况\n报告生成时间：$&#123;maketime&#125;\n总访问量:$&#123;total_visit&#125;\n总带宽:$&#123;total_bandwidth&#125;M\n独立访客:$&#123;total_unique&#125;\n\n访问IP统计(统计前20个IP):\n$&#123;ip_pv&#125;\n\n访问url最多(统计前20个页面)\n:$&#123;url_num&#125;\n\n404统计(统计前20个页面):\n$&#123;notfound&#125;\n\n当天访问次数最多的时间段如下:\n$&#123;time_stats&#125;\n\n访问量最高的IP[$&#123;max_ip&#125;]前20个最多的页面如下:\n$&#123;ip_havi&#125; " &gt; $log_dir/analysis_access$now.logdate_end=$(date +%s)time_take=$(($date_end-$date_start))take_time=$(($time_take/60))echo "access统计脚本分析日志花费了: [start:$date_start end:$date_end] $time_take"s" $take_time"min""echo "access统计脚本分析日志花费了: [start:$date_start end:$date_end] $time_take"s" $take_time"min"" &gt;&gt; $log_dir/analysis_access$now.log [针对nginx日志分析脚本结果展现如下:]]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[网络信息监控[客户端版/BAT版]]]></title>
    <url>%2F2014%2F06%2F10%2F80%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/277749]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[多并行网络延迟监控小程序[客户端版/BAT版]]]></title>
    <url>%2F2014%2F06%2F10%2F81%2F</url>
    <content type="text"><![CDATA[https://my.oschina.net/pwd/blog/277730]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[js 获取url 传值 参数]]></title>
    <url>%2F2014%2F06%2F08%2F82%2F</url>
    <content type="text"><![CDATA[.true; .auto-links: .false;&#125;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051&lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot;&gt; function GetUrlParms() &#123; var args=new Object(); var query=location.search.substring(1);//获取查询串 var pairs=query.split(&quot;&amp;&quot;);//在逗号处断开 for(var i=0;i&lt;pairs.length;i++) &#123; var pos=pairs[i].indexOf(&apos;=&apos;);//查找name=value if(pos==-1) continue;//如果没有找到就跳过 var argname=pairs[i].substring(0,pos);//提取name var value=pairs[i].substring(pos+1);//提取value args[argname]=unescape(value);//存为属性 &#125; return args;&#125;var args = new Object();args = GetUrlParms();//如果要查找参数key:if(args[&quot;id&quot;]!=undefined)&#123;//如果要查找参数key:var value1 = args[&quot;id&quot;] ;alert(value1);&#125;&lt;/script&gt;]]></content>
      <categories>
        <category>HTML相关</category>
      </categories>
      <tags>
        <tag>HTML相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[HTML中传递和引用JavaScript变量]]></title>
    <url>%2F2014%2F06%2F08%2F83%2F</url>
    <content type="text"><![CDATA[.true; .auto-links: .false;&#125;123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566&lt;html&gt; &lt;head&gt; &lt;title&gt;在HTML中传递和引用JavaScript变量&lt;/title&gt; &lt;script type=&quot;text/javascript&quot;&gt; var foobar; //全局变量声明 function passvar()&#123; foobar = document.getElementById(&apos;textfield&apos;).value; //document.write(&apos;传递变量成功&apos;); alert(&apos;传递变量成功!&apos;); &#125; //显示变量 function displayvar()&#123; alert(&apos;变量值为:&apos;+foobar); &#125; //引用变量 function varpass()&#123; document.getElementById(&apos;textdispaly&apos;).value = foobar; //foobar = document.getElementById(&apos;textdispaly&apos;).value ; &#125; &lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;center&gt; &lt;h1&gt;在HTML中传递JavasScript变量&lt;/h1&gt;&lt;hr&gt;&lt;br&gt; &lt;h5&gt;单击相应按钮...&lt;/h5&gt; &lt;form name=&quot;form1&quot; method=&quot;post&quot; action=&quot;&quot;&gt; &lt;p&gt; &lt;label&gt; &lt;input type=&quot;text&quot; name=&quot;textfield&quot; id=&quot;textfield&quot;&gt; &lt;/label&gt; &lt;label&gt; &lt;!--绑定 onclick事件 --&gt; &lt;input type=&quot;button&quot; name=&quot;button1&quot; value=&quot;传递变量&quot; onclick=&quot;void passvar();&quot;&lt; /span&gt; &lt;/label&gt; &lt;label&gt; &lt;!--绑定 onclick事件 --&gt; &lt;input type=&quot;button&quot; name=&quot;button2&quot; value=&quot;显示变量&quot; onclick=&quot;void displayvar();&quot;&lt; /span&gt;&gt; &lt;/label&gt; &lt;/p&gt; &lt;p&gt; &lt;label&gt; &lt;input type=&quot;text&quot; name=&quot;display&quot; id=&quot;textdispaly&quot;&gt; &lt;/label&gt; &lt;label&gt; &lt;!--绑定 onclick事件 --&gt; &lt;input type=&quot;button&quot; name=&quot;button3&quot; value=&quot;引用输入变量&quot; onclick=&quot;void varpass();&quot;&lt; /span&gt;&gt; &lt;/label&gt; &lt;/p&gt; &lt;/form&gt; &lt;/center&gt; &lt;/body&gt; &lt;/html&gt; 原文来自： http://ivantian2008.blog.51cto.com/622133/1127456]]></content>
      <categories>
        <category>HTML相关</category>
      </categories>
      <tags>
        <tag>HTML相关</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[IOS7.1企业版解决证书无效问题]]></title>
    <url>%2F2014%2F04%2F25%2F84%2F</url>
    <content type="text"><![CDATA[[方法一：] [添加ssl证书认证的服务器,可以是nginx，可以是apache，放在生产的话是需要购买ssl证书的，由于考虑到需要购买证书需要消耗费用就不考虑第一种方法了，提供第一种方法参考url。\] [http://blog.csdn.net/zhaoxy_thu/article/details/21133399] [方法二：] [苹果客户端更新方法] [注：由于IOS7.1以上更新需要S认证所以更新IOS方法发生改变] [1.下载zzb.plist文件，这个文件在相关论坛上有，并且在zzb.plist文件里面修改最新的IOS下载的客户端地址。] [2.打开 https://www.dropbox.com/home] [ 输入账号：你申请的账号] [ 密码： 你申请的密码] [3.删除dropbox上已有的zzb.plist并上传最新的zzb.plist文件。] [ 直接拖拽即可上传。] [4.点击共享zzb.plist文件，弹出对话框,复制共享连接,如https://www.dropbox.com/s/l19vpb827d8lc5t/zzb.plist] [***关键点***将https://www.dropbox.com/s/l19vpb827d8lc5t/zzb.plist 替换为https://dl.dropboxusercontent.com/s/l19vpb827d8lc5t/zzb.plist] [手动打开 https://dl.dropboxusercontent.com/s/l19vpb827d8lc5t/zzb.plist[ ] [ 如正确则进行下一步。][] [5.写一个index文件，访问如下index即可更新IOS] .true; .auto-links: .false;&#125;12345&lt;html&gt;&lt;head&gt;&lt;meta http-equiv=&quot;REFRESH&quot; content=&quot;0;url=itms-services://?action=download-manifest&amp;url=https://dl.dropboxusercontent.com/s/l19vpb827d8lc5t/zzb.plist&quot;&gt;&lt;/head&gt;&lt;/html&gt; [] [ zzb.plist文件示例:] &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt; &lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt; &lt;plist version=&quot;1.0&quot;&gt; &lt;dict&gt; &lt;key&gt;items&lt;/key&gt; &lt;array&gt; &lt;dict&gt; &lt;key&gt;assets&lt;/key&gt; &lt;array&gt; &lt;dict&gt; &lt;key&gt;kind&lt;/key&gt; &lt;string&gt;software-package&lt;/string&gt; &lt;key&gt;url&lt;/key&gt; &lt;string&gt;http://baowang.oss-cn-hangzhou.aliyuncs.com/ios/zzb_20140328_V2.8.1.6_v2.ipa&lt;/string&gt; &lt;/dict&gt; &lt;/array&gt; &lt;key&gt;metadata&lt;/key&gt; &lt;dict&gt; &lt;key&gt;bundle-identifier&lt;/key&gt; &lt;string&gt;com.baoxian.fhzzb&lt;/string&gt; &lt;key&gt;bundle-version&lt;/key&gt; &lt;string&gt;1.0&lt;/string&gt; &lt;key&gt;kind&lt;/key&gt; &lt;string&gt;software&lt;/string&gt; &lt;key&gt;title&lt;/key&gt; &lt;string&gt;掌中保&lt;/string&gt; &lt;/dict&gt; &lt;/dict&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/plist&gt;]]></content>
      <categories>
        <category>工作日志</category>
      </categories>
      <tags>
        <tag>工作日志</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[IIS网站权限 目录权限及常用设置 图文教程]]></title>
    <url>%2F2014%2F04%2F21%2F85%2F</url>
    <content type="text"><![CDATA[&lt;转&gt; http://blog.vpsks.com/696.html]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[scp断点续传]]></title>
    <url>%2F2014%2F04%2F15%2F86%2F</url>
    <content type="text"><![CDATA[[举例如下] [rsync -P –rsh=ssh home.tar 192.168.205.34:/home/home.tar，再输出密码后，可以用ctrl+z 来中断，再使用bg命令让它在后台执行。如下图：\] [加密的key可以使用以下传:] [rsync -P –rsh=\”ssh -i key\”username@ip:/data/bw_mon/bw_mysqlbk/local_data/20140414_0415.tar.gz./]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[shell小技巧 (1)]]></title>
    <url>%2F2014%2F04%2F11%2F87%2F</url>
    <content type="text"><![CDATA[[[1.]上下文对齐 [ ][column-t (格式化输出)] [[2.去掉字符串中的空格 ]echo\” 10.68.3.102 \”| tr -d \’ \’]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[pmap查看某进程所消耗的内存]]></title>
    <url>%2F2014%2F04%2F11%2F88%2F</url>
    <content type="text"><![CDATA[[[Address:内存开始地址]\[Kbytes:占用内存的字节数（KB）]\[RSS:保留内存的字节数（KB）]\[Dirty:脏页的字节数（包括共享和私有的）（KB）]\[Mode: 内存的权限：read、write、execute、shared、private(写时复制)]\[Mapping:占用内存的文件、或[anon]（分配的内存）、或[stack]（堆栈）]\[Offset:文件偏移]\[Device: 设备名(major:minor)]]]></content>
      <categories>
        <category>小技巧</category>
      </categories>
      <tags>
        <tag>小技巧</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[公有云镜像模版的创建&lt;二&gt;]]></title>
    <url>%2F2014%2F04%2F08%2F89%2F</url>
    <content type="text"><![CDATA[123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332base_init.sh &lt;!-- 自动修改主机名/更改编码/本来准备加内核优化，后来放弃，原因省略1000字--&gt;#/bin/bash #Changes in the system initialization#Some args need to Change!!Localdir=`pwd`BACKUP=$Localdir/backupCONF=$Localdir/sys.confshellname=$(basename $0)#Determine whether you are in the right positionif [[ ! -f $Localdir/$shellname ]];thenecho "Please cd to the directory location of the script at the same level,Exit"exitfi[[ -d $BACKUP ]] || mkdir -p $BACKUP. $CONFfunction gennip ()&#123;re=`echo $IP | awk -F. '&#123;printf "%d",$1*256^3+$2*256^2+$3*256+$4&#125;'`echo "$re"&#125;function config_hostname()&#123;IPADDR=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '&#123;print $2&#125;'|tr -d "addr:"`for IP in $IPADDRdoipn=`gennip $IP`if [ $ipn -ge 167772160 -a $ipn -le 184549376 -o $ipn -ge 2130706432 -a $ipn -le 2147483648 -o $ipn -ge 2886729728 -a $ipn -le 2887778304 -o $ipn -ge 3232235520 -a $ipn -le 3232301056 ]; thenIPP=`echo $IP|awk -F'.' '&#123;print $NF&#125;'`echo "-----Starting configure the Hostname!" local _HOST_NAME=$base_hostname$IPP cp -fpv /etc/sysconfig/network $BACKUP if grep "^HOSTNAME=" /etc/sysconfig/network &gt; /dev/null 2&gt;&amp;1 then sed -i '/^HOSTNAME=.*$/d' /etc/sysconfig/network fi hostname $_HOST_NAME echo "HOSTNAME=$_HOST_NAME" &gt;&gt; /etc/sysconfig/network . /etc/sysconfig/network if ! grep "$_HOST_NAME" /etc/hosts |grep "$IP" &gt; /dev/null 2&gt;&amp;1thenecho "$IP $_HOST_NAME" &gt;&gt; /etc/hostsfiecho "-----Configure hostname Have done!"fidone &#125;config_lang()&#123;if ! grep "UTF-8" /etc/sysconfig/i18n &gt; /dev/null 2&gt;&amp;1thencp -fpv /etc/sysconfig/i18n $BACKUPsed -i 's/^LANG=.*$/LANG="en_US.UTF-8"/' /etc/sysconfig/i18n. /etc/sysconfig/i18nfi&#125;config_network_param()&#123; if ! grep "synack_retries" /etc/sysctl.conf &gt; /dev/null 2&gt;&amp;1 thencp -fpv /etc/sysctl.conf /etc/rc.local $BACKUPecho "" &gt;&gt; /etc/sysctl.confecho "net.ipv4.ip_forward = 0net.ipv4.conf.default.rp_filter = 1net.ipv4.conf.default.accept_source_route = 0kernel.sysrq = 0kernel.core_uses_pid = 1net.ipv4.tcp_syncookies = 1kernel.msgmnb = 65536kernel.msgmax = 65536kernel.shmmax = 68719476736kernel.shmall = 4294967296fs.file-max = 6553500net.ipv4.tcp_syncookies = 1net.ipv4.conf.eth0.secure_redirects = 1net.ipv4.conf.lo.secure_redirects = 1net.ipv4.conf.default.secure_redirects = 1net.ipv4.conf.all.secure_redirects = 1net.ipv4.conf.eth0.accept_redirects = 0net.ipv4.conf.eth0.send_redirects = 0net.ipv4.conf.lo.send_redirects = 0net.ipv4.conf.default.send_redirects = 0net.ipv4.conf.all.send_redirects = 0net.ipv4.icmp_echo_ignore_broadcasts = 1net.ipv4.icmp_ignore_bogus_error_responses = 1net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_tw_recycle = 1net.ipv4.tcp_fin_timeout = 30net.ipv4.tcp_keepalive_time = 1800net.core.wmem_max = 8388608net.core.rmem_max = 8388608net.ipv4.tcp_rmem = 4096 873814 8738140net.ipv4.tcp_wmem = 4096 873814 8738140net.ipv4.tcp_max_syn_backlog = 4096net.ipv4.tcp_syn_retries = 1net.ipv4.tcp_synack_retries = 1" &gt;&gt; /etc/sysctl.confsysctl -pfi&#125;config_hostnameconfig_lang#config_network_paramif grep base_init.sh /etc/rc.d/rc.local &gt; /dev/null 2&gt;&amp;1thensed -i '/base_init.sh/ &#123;s/^/#/&#125;' /etc/rc.d/rc.localfi sysinit.sh &lt;!--自定义初始化镜像脚本，自动安装jdk/nginx/iftop/ifstat/zabbix/puppet/salt/log.io等常用 --&gt;#!/bin/bash #Add by GM.H#Create time 2014-04-03#System Initialization templatesBase_dir=`pwd`Tmp_dir=$Base_dir/tmpInstall_log=$Base_dir/install.logSys_base_shell=$Base_dir/base_init.shConf=$Base_dir/sys.confshellname=$(basename $0)#Determine whether you are in the right positionif [[ ! -f $Base_dir/$shellname ]];thenecho "Please cd to the directory location of the script at the same level,Exit"exitfi###Define some base pakgs!!defile_pakges="$Base_dir/pakgs/bw_resin_install.tar.gz$Base_dir/pakgs/bw_tomcat_install.tar.gz$Base_dir/pakgs/bw_tomcat7.0_install.tar.gz$Base_dir/pakgs/bw_nginx_install.zip$Base_dir/pakgs/bw_nginx_install.tar.gz$Base_dir/pakgs/jdk1.6.0_25.tar.gz$Base_dir/pakgs/jdk-7u17-linux-x64.tar.gz$Base_dir/pakgs/iftop.tar.gz$Base_dir/pakgs/ifstat-1.1.tar.gz$Base_dir/pakgs/bw_zabbixclient_install.tar.gz$Base_dir/pakgs/bw_puppetclient_install.tar.gz$Base_dir/pakgs/epel-release-5-4.noarch.rpm$Base_dir/pakgs/epel-release-6-8.noarch.rpm$Base_dir/pakgs/log.io.tar.gz$Base_dir/pakgs/mysqlbk_init.zip$Base_dir/pakgs/bw_backup_install.tar.gz$Base_dir/pakgs/bw_mysql5.6_install.zip$Base_dir/pakgs/bw_mysql_install.tar.gz". $Confdatef() &#123; date "+%Y/%m/%d %H:%M" ; &#125;print_to_log() &#123;echo "$1" echo "[$(datef)] $1" &gt;&gt; $Install_log ;&#125;[[ -d $Tmp_dir ]] || mkdir -p $Tmp_dir&gt; $Install_log#functions for System Initialization templates #1.Define Hostname define_hostname()&#123;if ! grep base_init.sh /etc/rc.d/rc.local &gt; /dev/null 2&gt;&amp;1 ;thenecho "/bin/bash $Sys_base_shell &gt; /dev/null 2&gt;&amp;1" &gt;&gt; /etc/rc.d/rc.local/bin/bash $Sys_base_shell &gt; /dev/null 2&gt;&amp;1print_to_log "$FUNCNAME(): have finished!"fi&#125;#2.Define resin/tomcat/mysql/nginx-0.7.65 &amp;&amp; Install nginx-1.0.6 and jdkconfirm_pakges()&#123;#confirm pakgesfor i in $defile_pakgesdoif [[ ! -f $i ]];thenprint_to_log "$FUNCNAME(): $i is not exist!!"fi doneprint_to_log "$FUNCNAME(): resin/tomcat/mysql/nginx-0.7.65 pakges check have finished!"#nginxif [[ ! -d /usr/local/nginx ]];then[[ ! -d $Tmp_dir/bw_nginx_install ]] || rm -rf $Tmp_dir/bw_nginx_installtar -zxf $Base_dir/pakgs/bw_nginx_install.tar.gz -C $Tmp_dircd $Tmp_dir/bw_nginx_install/bin/bash init.sh &gt; /dev/null 2&gt;&amp;1 print_to_log "$FUNCNAME(): Nginx-1.0.6 have install successfully!"elseprint_to_log "$FUNCNAME(): Nginx have already Intalled!"fi#jdkif [[ ! -d /usr/local/jdk ]];thenif [[ ! -d /usr/local/jdk1.7.0_17 ]];thentar -zxf $Base_dir/pakgs/jdk-7u17-linux-x64.tar.gz -C /usr/local/filn -s /usr/local/jdk1.7.0_17 /usr/local/jdkprint_to_log "$FUNCNAME(): jdk1.7.0_17 have install successfully!"elseprint_to_log "$FUNCNAME(): Jdk1.7.0_17 have already Intalled!"fiif ! grep "/usr/local/jdk/bin" /etc/profile &gt; /dev/null 2&gt;&amp;1 ;thenecho "export PATH=/usr/local/jdk/bin:$PATH" &gt;&gt; /etc/profilefi&#125;#3.Install some Common packageInstall_com_pakges()&#123;#iftopiftop -h &gt; /dev/null 2&gt;&amp;1if [[ $? -ne 0 ]];then[[ -d $Tmp_dir/iftop ]] || tar -zxf $Base_dir/pakgs/iftop.tar.gz -C $Tmp_dir cd $Tmp_dir/iftop/bin/bash iftop_init.sh &gt; /dev/null 2&gt;&amp;1print_to_log "$FUNCNAME(): iftop have installed successfully!" elseprint_to_log "$FUNCNAME(): iftop have already installed!"fi#ifstatifstat -h &gt; /dev/null 2&gt;&amp;1if [[ $? -ne 0 ]];then[[ -d $Tmp_dir/ifstat-1.1 ]] || tar -zxf $Base_dir/pakgs/ifstat-1.1.tar.gz -C $Tmp_dircd $Tmp_dir/ifstat-1.1/bin/bash ifstat_init.sh &gt; /dev/null 2&gt;&amp;1print_to_log "$FUNCNAME(): ifstat have installed successfully!"elseprint_to_log "$FUNCNAME(): ifstat have already installed!"fi#zabbixif [[ ! -f /etc/zabbix/zabbix_agentd.conf ]];then[[ ! -d $Tmp_dir/bw_zabbixclient_install ]] || rm -rf $Tmp_dir/bw_zabbixclient_install[[ -d $Tmp_dir/bw_zabbixclient_install ]] || tar -zxf $Base_dir/pakgs/bw_zabbixclient_install.tar.gz -C $Tmp_dircd $Tmp_dir/bw_zabbixclient_install/bin/bash install.sh &gt; /dev/null 2&gt;&amp;1sed -i "s/192.168.100.241/$zabbix_server/" /etc/zabbix/zabbix_agentd.confsed -i "s/Zabbix server/`hostname`/" /etc/zabbix/zabbix_agentd.confchkconfig zabbix_agentd offprint_to_log "$FUNCNAME(): zabbixclient have installed successfully!"elseprint_to_log "$FUNCNAME(): zabbixclient have already installed!"fi#puppetif [[ ! -f /etc/puppet/puppet.conf ]];then[[ ! -d $Tmp_dir/bw_puppetclient_install ]] || rm -rf $Tmp_dir/bw_puppetclient_install[[ -d $Tmp_dir/bw_puppetclient_install ]] || tar -zxf $Base_dir/pakgs/bw_puppetclient_install.tar.gz -C $Tmp_dircd $Tmp_dir/bw_puppetclient_install/bin/bash install.sh &gt; /dev/null 2&gt;&amp;1sed -i "s/vpnserver/$puppet_server/" /etc/puppet/puppet.conf chkconfig puppet offprint_to_log "$FUNCNAME(): puppetclient have installed successfully!"elseprint_to_log "$FUNCNAME(): puppetclient have already installed!"fi#salt-minion if [[ ! -d /etc/salt ]];thenif grep "6." /etc/redhat-release &gt; /dev/null 2&gt;&amp;1 ;then rpm -ivh $Base_dir/pakgs/epel-release-6-8.noarch.rpm &gt; /dev/null 2&gt;&amp;1 yum install salt-minion -y &gt; /dev/null 2&gt;&amp;1elserpm -ivh $Base_dir/pakgs/epel-release-5-4.noarch.rpm &gt; /dev/null 2&gt;&amp;1yum install salt-minion -y &gt; /dev/null 2&gt;&amp;1fiif ! grep "^master:" /etc/salt/minion &gt; /dev/null 2&gt;&amp;1 ;thenecho "master: $salt_server" &gt;&gt; /etc/salt/minionfiif ! grep "^id" /etc/salt/minion &gt; /dev/null 2&gt;&amp;1 ;thenecho "id: `hostname`" &gt;&gt; /etc/salt/minionfichkconfig salt-minion offprint_to_log "$FUNCNAME(): salt-minion have installed successfully!"elseprint_to_log "$FUNCNAME(): salt-minion have already installed!"fi#log.ioif [[ ! -d ~/.log.io/ ]];then[[ -d $Tmp_dir/log.io ]] || tar -zxf $Base_dir/pakgs/log.io.tar.gz -C $Tmp_dircd $Tmp_dir/log.io/bin/bash logio_install.sh &gt; /dev/null 2&gt;&amp;1 chkconfig log.io-harvester offchkconfig log.io-server offprint_to_log "$FUNCNAME(): log.io have installed successfully!"elseprint_to_log "$FUNCNAME(): log.io have already installed!"fi&#125;#4. Install some usefull install_other_pakges()&#123;#mysqlbkif [[ ! -d /data/bw_mon/bw_mysqlbk ]] ; then[[ ! -d $Tmp_dir/mysqlbk_init ]] || rm -rf $Tmp_dir/mysqlbk_init[[ -d $Tmp_dir/mysqlbk_init ]] || unzip $Base_dir/pakgs/mysqlbk_init.zip -d $Tmp_dircd $Tmp_dir/mysqlbk_init /bin/bash initbk.sh &gt; /dev/null 2&gt;&amp;1print_to_log "$FUNCNAME(): mysqlbk have installed successfully!"else print_to_log "$FUNCNAME(): mysqlbk have already installed!"fi#backupif [[ ! -d /data/bw_mon/bw_backup ]] ; then[[ ! -d $Tmp_dir/bw_backup_install ]] || rm -rf $Tmp_dir/bw_backup_install[[ -d $Tmp_dir/bw_backup_install ]] || tar -zxf $Base_dir/pakgs/bw_backup_install.tar.gz -C $Tmp_dircd $Tmp_dir/bw_backup_install/bin/bash init.sh &gt; /dev/null 2&gt;&amp;1print_to_log "$FUNCNAME(): backup have installed successfully!"elseprint_to_log "$FUNCNAME(): backup have already installed!"fi&#125;define_hostnameconfirm_pakgesInstall_com_pakgesinstall_other_pakges######nginx tomcat resin mysql等源码自动安装脚本后续更新!############################]]></content>
      <categories>
        <category>Shell相关</category>
      </categories>
      <tags>
        <tag>Shell相关</tag>
      </tags>
  </entry>
</search>