分类目录归档:JavaEE

linux下如何实现mysql数据库每天定时自动备份

需要将数据库进行每天定时自动备份,所以网上找了各种方式就行了测试,遇到很多坑,特此记录下来,步骤是东拼西凑的,虽然也是网上找的,但都是经过亲自测试,一定能用,针对部署时期遇到的问题和解决方式都记录了下来。

1、创建备份目录:
为了方便,在/home保存备份文件;

cd
mkdir /home/dbback
cd /home/dbback
2、创建备份Shell脚本:
注意把以下命令中的DatabaseName换为实际的数据库名称;
当然,你也可以使用其实的命名规则!

vi bkDatabaseName.sh
输入/粘贴以下内容:

#!/bin/bash
mysqldump -uusername -ppassword DatabaseName > /home/dbback/DatabaseName_$(date +%Y%m%d_%H%M%S).sql
对备份进行压缩:

#!/bin/bash
mysqldump -uusername -ppassword DatabaseName | gzip > /home/dbback/DatabaseName_$(date +%Y%m%d_%H%M%S).sql.gz
注意:
把 username 替换为实际的用户名;
把 password 替换为实际的密码;
把 DatabaseName 替换为实际的数据库名;

3、添加可执行权限:
chmod u+x bkDatabaseName.sh
添加可执行权限之后先执行一下,看看脚本有没有错误,能不能正常使用;

./bkDatabaseName.sh
注:这里可能会报错
Warning: Using a password on the command line interface can be insecure.
导出MySQL数据库的时候采用mysqldump命令,出现”Warning: Using a password on the command line interface can be insecure.”的错误提示,当然数据库肯定也没有能备份下来。这个问题应该是在MySQL5.6+版本的时候就有出现,可能是为了确保数据库的安全性采用的保护机制。

解决方法、修改数据库配置文件

1、我们需要修改数据库配置文件,这个要看我们数据库的配置的,有些是在/etc/my.cnf,有些是/etc/my.conf

我们需要在[client]部分添加脚本:

host=localhost
user=数据库用户
password=’数据库密码’

这里参数要修改成我们自己的。

2、采用命令导出和导入数据库

其实在这个时候,我们如果采用”详解使用mysqldump命令备份还原MySQL数据用法整理”介绍的方法也是可以使用的,虽然依旧有错误提示,但是数据库还是可以导出的。您肯定和老左一样是追求细节的人,一点点问题都不能有,但我们可以用下面的命令导出和导入,就没有错误提示。

#导出数据库

mysqldump –defaults-extra-file=/etc/my.cnf database > database.sql

#导入数据库

mysql –defaults-extra-file=/etc/my.cnf database < database.sql

这里我们可以看到上面的命令和以前常用的快速导入和导入命令有所不同了,需要加载我们配置的MYSQL配置文件,这个红色部分要根据我们实际的路径修改。用这样的命令导出备份和导入是没有错误提示的。

4、添加计划任务
检测或安装 crontab
确认crontab是否安装:
执行 crontab 命令如果报 command not found,就表明没有安装

# crontab
-bash: crontab: command not found
如时没有安装 crontab,需要先安装它,具体步骤请参考:
CentOS下使用yum命令安装计划任务程序crontab
使用rpm命令从CentOS系统盘安装计划任务程序crontab

添加计划任务
执行命令:

crontab -e
这时就像使用vi编辑器一样,可以对计划任务进行编辑。
输入以下内容并保存:

*/1 * * * * /home/backup/bkDatabaseName.sh
具体是什么意思呢?

意思是每一分钟执行一次shell脚本“/home/backup/bkDatabaseName.sh”。

1、额外学习,crontab用法
crontab命令用于安装、删除或者列出用于驱动cron后台进程的表格。用户把需要执行的命令序列放到crontab文件中以获得执行。
每个用户都可以有自己的crontab文件。/var/spool/cron下的crontab文件不可以直接创建或者直接修改。该crontab文件是通过crontab命令创建的

在crontab文件中如何输入需要执行的命令和时间。该文件中每行都包括六个域,其中前五个域是指定命令被执行的时间,最后一个域是要被执行的命令。
每个域之间使用空格或者制表符分隔。格式如下:
minute hour day-of-month month-of-year day-of-week commands
合法值 00-59 00-23 01-31 01-12 0-6 (0 is sunday)
除了数字还有几个个特殊的符号就是”*”、”/”和”-“、”,”,*代表所有的取值范围内的数字,”/”代表每的意思,”/5″表示每5个单位,”-“代表从某个数字到某个数字,”,”分开几个离散的数字。

-l 在标准输出上显示当前的crontab。
-r 删除当前的crontab文件。
-e 使用VISUAL或者EDITOR环境变量所指的编辑器编辑当前的crontab文件。当结束编辑离开时,编辑后的文件将自动安装。

 

2、例子:
每天早上6点
0 6 * * * echo “Good morning.” >> /tmp/test.txt //注意单纯echo,从屏幕上看不到任何输出,因为cron把任何输出都email到root的信箱了。

每两个小时
0 */2 * * * echo “Have a break now.” >> /tmp/test.txt

晚上11点到早上8点之间每两个小时和早上八点
0 23-7/2,8 * * * echo “Have a good dream” >> /tmp/test.txt

每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
0 11 4 * 1-3 command line

1月1日早上4点
0 4 1 1 * command line SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root //如果出现错误,或者有数据输出,数据作为邮件发给这个帐号 HOME=/

每小时执行/etc/cron.hourly内的脚本
01 * * * * root run-parts /etc/cron.hourly
每天执行/etc/cron.daily内的脚本
02 4 * * * root run-parts /etc/cron.daily

每星期执行/etc/cron.weekly内的脚本
22 4 * * 0 root run-parts /etc/cron.weekly

每月去执行/etc/cron.monthly内的脚本
42 4 1 * * root run-parts /etc/cron.monthly

注意: “run-parts”这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是文件夹名。

每天的下午4点、5点、6点的5 min、15 min、25 min、35 min、45 min、55 min时执行命令。
5,15,25,35,45,55 16,17,18 * * * command

每周一,三,五的下午3:00系统进入维护状态,重新启动系统。
00 15 * * 1,3,5 shutdown -r +5

每小时的10分,40分执行用户目录下的innd/bbslin这个指令:
10,40 * * * * innd/bbslink

每小时的1分执行用户目录下的bin/account这个指令:
1 * * * * bin/account

每天早晨三点二十分执行用户目录下如下所示的两个指令(每个指令以;分隔):
20 3 * * * (/bin/rm -f expire.ls logins.bad;bin/expire$#@62;expire.1st)

每年的一月和四月,4号到9号的3点12分和3点55分执行/bin/rm -f expire.1st这个指令,并把结果添加在mm.txt这个文件之后(mm.txt文件位于用户自己的目录位置)。
12,55 3 4-9 1,4 * /bin/rm -f expire.1st$#@62;$#@62;mm.txt

5、测试任务是否执行
很简单,我们就执行几次“ls”命令,看看一分钟过后文件有没有被创建就可以了!

如果任务执行失败了,可以通过以下命令查看任务日志:

# tail -f /var/log/cron
输出类似如下

Maven WEB 项目使用ProGuard进行混淆,最佳解决方案

近期公司的Android项目做了混淆,虽说对于保护代码并不是100%的,但混淆后的代码可以使那些不法份子难以阅读,这样也能对代码的保护做出贡献。
于是,公司写的一大堆WEB项目也想做保护。但几大问题随之而来:

公司的所有项目全部是Maven项目,网上的混淆方案不是陈旧就是无效
网上的大部分解决方案感觉像是对简单DEMO进行混淆,根本不能用于复杂的WEB项目中
网上的大部分解决方案是针对Android项目的,针对WEB的少之又少
针对以上问题,本人花费一个月研究了WEB+Maven项目的混淆,终于收获果实,解决了这一大空缺难题。

项目介绍
就如之前所述,我们要混淆的项目绝不是一个简单的WEB DEMO,必须要包含了大量第三方框架。
本文中介绍的项目使用了主流的一些框架:

Spring 4.1.1.RELEASE
SpringMVC 4.1.1.RELEASE
JackSon 2.5.0
MyBatis 3.3.0
Shiro 1.2.3
Log4J 1.2.17
SLF4J 1.7.10
Druid Pool 1.0.15
patchca 1.0.0
Jetty 9.2.7.v20150116
项目包结构

该项目是典型的Maven WEB项目,对于Maven WEB项目的结构不再赘述,这里对各种包做一下解释:

annotation 注解包,里面是自己写的注解类,主要混淆对象
controller SpringMVC的控制器包,主要混淆对象
credntials Shiro的自定义凭证,次要混淆对象
dao DAO包,主要混淆对象
exception 异常包,自定义了一些异常,主要混淆对象
filter Shiro的自定义过滤器,次要混淆对象
interceptor Shiro的自定义拦截器,次要混淆对象
job SpringTASK的定时任务包,次要混淆对象
mapper Mybatis的XML映射文件包,非混淆对象
model 实体包,非混淆对象
realm Shiro的自定义域包,次要混淆对象
service 实体的服务包,次要混淆对象
token Shiro的自定义令牌包,次要混淆对象
utils 公司自己的工具类,主要混淆对象
主要混淆对象 对类的名称、属性、方法名都进行混淆
次要混淆对象 对类的名称不混淆,类的属性、方法名选择性混淆
非混淆对象 不进行混淆,混淆后可能出现异常

Maven 配置(pom.xml)
本文的重头戏,使用Maven集成的ProGuard插件,混淆配置不用单独建立文件

<?xml version=”1.0″ encoding=”UTF-8″?>
<project xmlns=”http://maven.apache.org/POM/4.0.0″
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<groupId>…</groupId>
<artifactId>zhukun.shiro-spring</artifactId>
<version>1.0-SNAPSHOT</version>

<!– 属性–>
<properties>
<!– 项目编码–>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!– 单元测试包–>
<junit.version>4.12</junit.version>
<!– JAVAEE支持包–>
<jstl.version>1.2</jstl.version>
<servlet.version>3.1.0</servlet.version>
<!– 日志包–>
<log4j.version>1.2.17</log4j.version>
<slf4j.version>1.7.10</slf4j.version>
<aspectj.version>1.6.12</aspectj.version>
<!– commons支持–>
<commons-logging.version>1.1.3</commons-logging.version>
<commons-collections.version>3.2.1</commons-collections.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<!– shiro安全框架–>
<shiro.version>1.2.3</shiro.version>
<!– druid连接池–>
<druid.version>1.0.15</druid.version>
<!– 数据库及数据库框架–>
<mysql.version>5.1.30</mysql.version>
<mybatis.version>3.3.0</mybatis.version>
<mybatis-spring.version>1.2.3</mybatis-spring.version>
<!– Mybatis分页插件–>
<mybatis-paginator.version>1.2.16</mybatis-paginator.version>
<!– Mybatis生成器插件–>
<mybatis-generator.version>1.3.2</mybatis-generator.version>
<!– Spring及SpringMVC支持包–>
<spring.version>4.1.1.RELEASE</spring.version>
<jackson.version>2.5.0</jackson.version>
<!– 验证码支持包–>
<patchca.version>1.0.0</patchca.version>
<!– Jetty插件–>
<jetty.version>9.2.7.v20150116</jetty.version>
<!– Maven编译插件–>
<maven-compiler.version>2.3.2</maven-compiler.version>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${commons-logging.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons-collections.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>com.github.miemiedev</groupId>
<artifactId>mybatis-paginator</artifactId>
<version>${mybatis-paginator.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.patchca</groupId>
<artifactId>patchca</artifactId>
<version>${patchca.version}</version>
</dependency>
</dependencies>

<build>
<finalName>shiro-spring</finalName>
<!–使Maven打包时能打包src目录下的XML文件–>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<webApp>
<contextPath>/shiro-spring</contextPath>
</webApp>
<httpConnector>
<!– 设置端口–>
<port>8080</port>
</httpConnector>
</configuration>
</plugin>

<!– MyBatis自动生成Mapper插件–>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>${mybatis-generator.version}</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>

<!– ProGuard混淆插件–>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.11</version>
<executions>
<execution>
<!– 混淆时刻,这里是打包的时候混淆–>
<phase>package</phase>
<goals>
<!– 使用插件的什么功能,当然是混淆–>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<!– 是否将生成的PG文件安装部署–>
<attach>true</attach>
<!– 是否混淆–>
<obfuscate>true</obfuscate>
<!– 指定生成文件分类 –>
<attachArtifactClassifier>pg</attachArtifactClassifier>
<options>
<!– JDK目标版本1.7–>
<option>-target 1.7</option>
<!– 不做收缩(删除注释、未被引用代码)–>
<option>-dontshrink</option>
<!– 不做优化(变更代码实现逻辑)–>
<option>-dontoptimize</option>
<!– 不路过非公用类文件及成员–>
<option>-dontskipnonpubliclibraryclasses</option>
<option>-dontskipnonpubliclibraryclassmembers</option>
<!– 优化时允许访问并修改有修饰符的类和类的成员 –>
<option>-allowaccessmodification</option>
<!– 确定统一的混淆类的成员名称来增加混淆–>
<option>-useuniqueclassmembernames</option>
<!– 不混淆所有包名,本人测试混淆后WEB项目问题实在太多,毕竟Spring配置中有大量固定写法的包名–>
<option>-keeppackagenames</option>
<!– 不混淆所有特殊的类–>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod</option>
<!– 不混淆所有的set/get方法,毕竟项目中使用的部分第三方框架(例如Shiro)会用到大量的set/get映射–>
<option>-keepclassmembers public class * {void set*(***);*** get*();}</option>

<!– 不混淆job包下的所有类名,且类中的方法也不混淆–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.job.** { &lt;methods&gt;; }</option>
<!– 不混淆filter包下的所有类名,这里主要是对Shiro的路踢人过滤器混淆,对类的属性和方法进行了混淆–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.filter.** </option>
<!– 不混淆凭证包下的所有类名,但对类中的属性、方法进行混淆,原因是Spring配置中用到了这个类名–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.credntials.** </option>
<!– 混淆目的同上,这个是拦截器的包,包中有防止重复提交的拦截器–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.interceptor.** </option>
<!– 混淆目的同上,这个是域包,包中有用户登录域–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.realm.** </option>
<!– 不混淆model包中的所有类以及类的属性及方法,实体包,混淆了会导致ORM框架及前端无法识别–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.model.** {*;}</option>
<!– 以下两个包因为大部分是Spring管理的Bean,不对包类的类名进行混淆,但对类中的属性和方法混淆–>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.service.** </option>
<option>-keep class com.chinatelecom.gz.wy.zhukun.shiro_spring.dao.**</option>
</options>
<outjar>${project.build.finalName}-pg.jar</outjar>
<!– 添加依赖,这里你可以按你的需要修改,这里测试只需要一个JRE的Runtime包就行了 –>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
</libs>
<!– 加载文件的过滤器,就是你的工程目录了–>
<inFilter>com/chinatelecom/gz/wy/zhukun/shiro_spring/**</inFilter>
<!– 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧–>
<injar>classes</injar>
<!– 输出目录–>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>

以上代码中的注释足够各位参考了,若有问题欢迎留言

执行
clean package -DskipTests

使用Maven运行以上代码,执行完成后在target目录中会生成三个文件:

classes-pg.jar 混淆后的classes文件,里面包含完整的项目结构
proguard_map.txt 混淆内容的映射
proguard_seed.txt 参与混淆的类
混淆完成后,将classes-pg.jar解压到应用服务器覆盖原有的classes文件,通常目录为

X:\jetty9或tomcat7\webapps\shiro-spring\WEB-INF\classes

运行服务,项目运行正常

反编译
既然是混淆了的代码,那我们现在作为盗码者来反编译一下classes文件

可以看出,混淆成功了,盗码者读起来不是一二般的痛苦,我们的目的已经达到

遗留问题
虽然混淆是在Maven打包的时候进行,但是生成的war包及classes目录并未混淆,还需要将jar包中的内容提取,比较麻烦,不知道有没有让生成的war包就是已经混淆的办法。
本人的JAVA环境是JDK1.7 64位,其它的JDK并未尝试
不能对Spring等配置文件混淆,这样包结构还是存在,减弱了盗码者的读码难度

java float double精度为什么会丢失

由于对float或double 的使用不当,可能会出现精度丢失的问题。问题大概情况可以通过如下代码理解:

  1. public class FloatDoubleTest {
  2. public static void main(String[] args) {
  3. float f = 20014999;
  4. double d = f;
  5. double d2 = 20014999;
  6. System.out.println(“f=” + f);
  7. System.out.println(“d=” + d);
  8. System.out.println(“d2=” + d2);
  9. }
  10. }

得到的结果如下:

f=2.0015E7

d=2.0015E7

d2=2.0014999E7

从输出结果可以看出double 可以正确的表示20014999 ,而float 没有办法表示20014999 ,得到的只是一个近似值。这样的结果很让人讶异。20014999 这么小的数字在float下没办法表示。于是带着这个问 题,做了一次关于float和double学习,做个简单分享,希望有助于大家对java 浮 点数的理解。

 

关于 java  float  double

Java 语言支持两种基本的浮点类型: float 和 double 。java 的浮点类型都依据 IEEE 754 标准。IEEE 754 定义了32 位和 64 位双精度两种浮点二进制小数标准。

IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。32 位浮点数用 1 位表示数字的符号,用 8 位来表示指数,用 23 位来表示尾数,即小数部分。作为有符号整数的指数可以有正负之分。小数部分用二进制(底数 2 )小数来表示。对于64 位双精度浮点数,用 1 位表示数字的符号,用 11 位表示指数,52 位表示尾数。如下两个图来表示:

float(32位):

float

double(64位):

double

都是分为三个部分:

(1) 一 个单独的符号位s 直接编码符号s 。

(2)k 位 的幂指数E ,移 码表示 。

(3)n 位 的小数,原码表示 。

那么 20014999 为什么用 float 没有办法正确表示?

结合float和double的表示方法,通过分析 20014999 的二进制表示就可以知道答案了。

以下程序可以得出 20014999 在 double 和 float 下的二进制表示方式。

  1. public class FloatDoubleTest3 {
  2. public static void main(String[] args) {
  3. double d = 8;
  4. long l = Double.doubleToLongBits(d);
  5. System.out.println(Long.toBinaryString(l));
  6. float f = 8;
  7. int i = Float.floatToIntBits(f);
  8. System.out.println(Integer.toBinaryString(i));
  9. }
  10. }

输出结果如下:

Double:100000101110011000101100111100101110000000000000000000000000000

Float:1001011100110001011001111001100

对于输出结果分析如下。对于都不 double 的二进制左边补上符号位 0 刚好可以得到 64 位的二进制数。根据double的表 示法,分为符号数、幂指数和尾数三个部分如下:

0 10000010111 0011000101100111100101110000000000000000000000000000

对于 float 左边补上符 号位 0 刚好可以得到 32 位的二进制数。 根据float的表示法, 也分为 符号数、幂指数和尾数三个部分如下 :

0 10010111 00110001011001111001100

绿色部分是符号位,红色部分是幂指数,蓝色部分是尾数。

对比可以得出:符号位都是 0 ,幂指数为移码表示,两者刚好也相等。唯一不同的是尾数。

在 double 的尾数 为: 001100010110011110010111 0000000000000000000000000000 ,省略后面的零,至少需要24位才能正确表示 。

而在 float 下面尾数 为: 00110001011001111001100 ,共 23 位。

为什么会这样?原因很明显,因为 float尾数 最多只能表示 23 位,所以 24 位的 001100010110011110010111 在 float 下面经过四舍五入变成了 23 位的 00110001011001111001100。所以 20014999 在 float 下面变成了 20015000 。
也就是说 20014999 虽然是在float的表示范围之内,但 在 IEEE 754 的 float 表示法精度长度没有办法表示出 20014999 ,而只能通过四舍五入得到一个近似值。

总结:

浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是 因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用 float 和double 作精确运 算的时候要特别小心。
可以考虑采用一些替代方案来实现。如通过 String 结合 BigDecimal 或 者通过使用 long 类型来转换。

运行node提示:events.js:160 throw er; // Unhandled ‘error’ event

运行node时遇到下述提示:

events.js:160  throw er; // Unhandled ‘error’ event或者events.js:160       throw er; // Unhandled ‘error’ event       ^  Error: listen EADDRNOTAVAIL 172.16.1.228:3003。

本来程序运行的好好的,有一次启动时提示我们上面的信息,经从网上查找答案是:此端口已被占用,改换其他端口。然后是一系列解决方案。

下面说说我遇到这个问题是怎样解决:

1、我换了端口,没有效果,依旧有上述提示。

2、查看当前被端口占用的进程,没的找到。

3、监听函数所有参数已写完整。ip地址是我本地ip地址。实在纳闷,到底是哪里出了差错。

4、从stactoverflow中查找到答案说让重新安装整个node_modules文件夹下的node,我看了后果断放弃,我里面用到了很多包,重新搭的话还不知道遇到什么问题。

5、无奈之下把程序中监听地址中的本机ip换成了127.0.0.1。靠!居然成功。我纳闷,这是在逗我吗?然后果断看了看电脑上的本地ip,再次傻住,我去!我本地电脑ip已变,你怎么说变就变了!好吧,原来如此,把程序中ip地址改成127.0.0.1最靠谱。

ansible基础教程

ansible 是一个轻量级的IT自动化工具,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。

特点

  • SSH by default
  • No agents: controlled hosts / devices need no agent sofware
  • No server: any linux machine can do Ansible activities via terminal commands
  • Modules in any languages: the modules can be developed in any languages
  • YAML, not code: using YAML language(标记语言,类XML) to write playbook
  • Strong multi-tier solution:可实现多级指挥

ansible 配置文件

  • ansible.cfg
    • 定义各种通用变量
    • 查找ansible.cfg文件的顺序
      • ANSIBLE_CONFIG环境变量所指定的文件
      • ./ansible.cfg
      • ~/.ansible.cfg
      • /etc/ansible/ansible.cfg
    • 配置举例:
      inventory = /etc/ansible/hosts  #指定inventory文件位置

Inventory

Ansible只能管理指定的服务器,在inventory文件中进行配置对应的主机/分组的数据,其格式如下:

--组名(对系统进行分组)
[webservers]
--主机名
foo.example.com

--指定系统的别名 + ssh的用户
jumper ansible_ssh_host=192.168.1.50 ansible_ssh_user=appadmin

--01到50,一组相似的hostname
www[01:50].example.com

--给host设定变量,后续playbook中可以使用
host1 http_port=80 maxRequestsPerChild=808

--给group设定变量,应用于组内的所有host
[atlanta]
host1
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com    

--组内组
[southeast:children]
atlanta
raleigh

Ansible Ad-Hoc 命令

  • 临时执行的命令
ansible <pattern_goes_here[webservers, all, *]> -m <module_name> -a <arguments>
  • 不指定module的话,则默认执行command模块
  • ansible-doc: 获取模块列表,以及模块使用格式
    • ansible-doc [-l] [-s MODULE]
      • -l : 列出支持的核心模块
      • -s MODULE : 查看模块的用法

使用例子:ping主机

ansible -i hosts webservers -m ping --ask-pass -u user
ansible -i hosts all -m ping --ask-pass -u user

输出:

[root@Centos7 ~]# ansible all -m ping
host1 | success >> {
    "changed": false,
    "ping": "pong"
}

host2 | UNREACHABLE! => {
    "changed": false,
    "msg": "Authentication failed.",
    "unreachable": true
}

参数解释

  • -m, –module-name: module name to execute(default=command)
    • -m ping : 执行ping module
  • -a, –args: module arguments
  • -i, –inventory-file: specify inventory host path(default=/etc/ansible/hosts) or comma separated host list.
  • -k, –ask-pass: ask for connection password
  • -u REMOTE_USER, –user=REMOTE_USER: connect as this user (default=None)
  • webservers 表示执行该命令的分组,all 表示inventory中配置的所有主机
  • -l, –limit=SUBSET: further limit selected hosts to an additional pattern,限定组或host来执行playbook
  • -c, –connect: connect type to use (default=smart)
  • –ask-vault-pass: ask for vault password(sudo 模式需要)
  • -b, –become: run operations with become (does not imply password prompting)(使用playbook制定的become_user进行操作)
  • -t TAGS, –tags=TAGS: only run plays and tasks tagged with these values
  • -C, –check: don’t make any changes; instead, try to predict some of the changes that may occur

Ansible Playbook

  • Ad-Hoc命令只能执行一些临时性的、简单的命令
  • 实际企业应用需要经过多个步骤,且各个步骤之间存在依赖关系,Ad-Hoc命令无法满足使用需求
  • 使用playbook来定义步骤以及依赖
  • playbook 由yaml编写,让远程主机按照事先编排的机制执行task
---
- hosts: all    #执行tasks的主机,all表示所有
  become: yes   #使用特定用户执行tasks,该参数也可以配置在相应task中。
  become_user: root
  remote_user: username #the user log into machine.

  tasks:
    # 每个task都相当于在执行对应模块的功能
    # 每个task感觉都是单次的连接,执行完之后断掉,之前的环境变量设置不会在后续的task中生效
    # 描述task
    - name: copy local file to remote machine
      # 执行对应模块功能
      copy: 
        src: ~/test
        dest: ~/test
        owner: root 
        mode: 0600
      # 命令执行的结果存到变量中,方便后续使用
      register: rsa
      # 设置环境变量
      environment:
        JAVA_HOME: /usr/java/jre1.8.0_51
      # task有失败之后,相同host后续的task不会执行,该参数可在失败后继续执行。
      ignore_errors: yes
      # 给这部分task打上tags,可指定只执行相应tags的task  (命令中添加:-t deploy)
      tags: deploy
      # (call the tasks defined in handlers if module does some changes to the remote host)
      notify:
        - do something

    # defines a list of tasks
    handlers:
      - name: do something
        service: test

    - name: task 2
      debug: var={{ host_vars }} # 使用对应host的host_vars变量
  • 例:在几台机子中执行hostname命令,并获取返回值
    • 文件目录:
      test        # inventory文件,配置主机
      test.yml    # playbook
    • inventory 配置内容
      [server]
      host1 ansible_ssh_host=1.1.1.1 ansible_ssh_user=appadmin
      host2 ansible_ssh_host=1.1.1.2 ansible_ssh_user=appadmin
    • test.yml 内容

      “`


    • hosts: all
      tasks:

      • name: get hostname
        shell: hostname
        register: out
      • debug: var=out
        “`
    • 执行playbook:$ ansible-playbook -i test test.yml,返回内容:
PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [host1]
ok: [host2]

TASK [get hostname] ************************************************************
changed: [host1]
changed: [host2]

TASK [debug] *******************************************************************
ok: [host1] => {
    "out": {
        "changed": true,
        "cmd": "hostname",
        "delta": "0:00:00.003584",
        "end": "2017-02-09 16:05:04.043118",
        "rc": 0,
        "start": "2017-02-09 16:05:04.039534",
        "stderr": "",
        "stdout": "host1.com",
        "stdout_lines": [
            "host1.com"
        ],
        "warnings": []
    }
}
ok: [host2] => {
    "out": {
        "changed": true,
        "cmd": "hostname",
        "delta": "0:00:00.003584",
        "end": "2017-02-09 16:05:04.043118",
        "rc": 0,
        "start": "2017-02-09 16:05:04.039534",
        "stderr": "",
        "stdout": "host2.com",
        "stdout_lines": [
            "host1.com"
        ],
        "warnings": []
    }
}

PLAY RECAP *********************************************************************
# 以下是对应host的task执行情况,ok表示执行成功的task数量,charged表示对host产生修改的task数量。
host1                         : ok=3    changed=1    unreachable=0    failed=0
host2                         : ok=3    changed=1    unreachable=0    failed=0

role 使用

  • playbook 直接调用 task 问题
    • playbook 是需要处理的事情,task 是执行细节,playbook并不关心细节
    • playbook 直接调用task 使task无法复用
    • playbook会越来越长,难维护
  • 将一个或多个task抽象成一个role,隐藏细节,供playbook调用
  • role易于复用,可以从一个已知的文件结构中自动加载vars, tasks, handler。
  • 部分文件结构:
test
test.yml
roles/
    install/
        files/
        templates/
        tasks/
            main.yml  #应用 install 时,优先执行main.yml
        handlers/
        vars/
    deploy/
        files/
        templates/
        tasks/
            main.yml
        handlers/
        vars/
  • playbook内容
---
- hosts: webservers
  roles:
     - install
     - deploy

部分常用模块

  • file: 包含了文件、文件夹、超级链接类的创立、拷贝、移动、删除操作。
  • copy: copy a file on the local box to remote locations. (可以使用 remote_src,使src在远程机子上,2.0 以后的版本适用)
  • fetch: copy files from remote locations to the local box.
  • template: Templates a file out to a remote server.
  • command: Executes a command on a remote node(It will not be processed through the shell, so variables like $HOME and operations like “<“, “>”, “|”, “;” and “&” will not work)If you want to execute a command securely and predictably, it may be better to use the command module instead.
  • lineinfile: Ensure a particular line is in a file, or replace an existing line using a back-referenced regular expression.
  • pause : Pause playbook execution
  • ping : Try to connect to host, verify a usable python and return pong on success. no sense in playbook.
  • shell : Execute commands in nodes.(runs the command through a shell (/bin/sh) on the remote node.)If you want to execute a command securely and predictably, it may be better to use the command module instead.
  • debug : Print statements during execution
  • setup : Gathers facts about remote hosts(默认执行),支持filter。
  • apt : Manages apt-packages
  • service: Controls services on remote hosts
  • fail: Fail with custom message
  • subversion: Deploys a subversion repository.
  • group: Add or remove groups
  • user: Manage user accounts
  • get_url: Downloads files from HTTP, HTTPS, or FTP to node
  • wait_for: Waits for a condition before continuing.(port is open , file is present, and so on.)
  • script: Runs a local script on a remote node after transferring it

实际场景应用

参考:

an-intro-to-network-automation-3-ansible
an-ansible-tutorial
ansible-simple-tutorial