构建java环境的自动化构建和部署系列四

 所有系列文章:

  <<构建java环境的自动化构建和部署系列一>>

  <<构建java环境的自动化构建和部署系列二>>

 <<构建java环境的自动化构建和部署系列三>>

 <<构建java环境的自动化构建和部署系列四>>

前面都介绍了整套的自动化部署环境的搭建,本章是介绍怎么基于docker快速启动一个jenkins容器,实现docker 的环境部署;

本章将基于 https://gitee.com/gz-tony/viemall-dubbo.git 开源代码来演练自动化部署的步骤;

通过docker file构建 jenkins镜像

#cd  /opt/program/tools/docker-file/jenkins

# docker build -t www.viemall.cn/viemall/jenkins:v1 .

这里构建镜像成功后,把镜像文件push公司的harbor镜像仓库中;

       #docker  push  www.viemall.cn/viemall/jenkins:v1

    docker-fil文件:

        https://gitee.com/gz-tony/viemall-dubbo/tree/master/viemall-docekr/dockerfile

启动jenkins镜像;

docker run -d –name jenkins -p 8080:8080 –restart=always –privileged=true \

-v /var/jenkins_home/:/var/jenkins_home  \

-v /usr/java/jdk1.8.0_131/:/usr/local/jdk \

-v /usr/local/apache-maven-3.3.9/:/usr/local/maven \

-v /var/run/docker.sock:/var/run/docker.sock \

-v $(which docker):/usr/bin/docker \

-v ~/.ssh:/root/.ssh \

-e JAVA_OPTS=-Dorg.apache.commons.jelly.tags.fmt.timeZone=Asia/Shanghai

www.viemall.cn/viemall/jenkins:v1

启动成功,访问:

 配置跟 <<构建java环境的自动化构建和部署系列三>> 基本一致;

唯一注意的配置的路径是配置您的docker mavean 路径

image.png
这里的mavean 就是配置您的docker mavean 路径

2. 构建Job任务:

 构建viemall-web服务:

 新建JOB

image.png

image.png

image.png

   image.png

   image.png

Source files(源目录文件)

viemall-service-web/target/viemall-service-web-0.0.1-SNAPSHOT.war

Remove prefix(删除的目录文件)

viemall-service-web/target

Remote directory(远程目录)

/opt/program/servers

 

Exec command(远程命令)

#!/bin/sh

echo '================开始本机执行 docker 部署任务================'

#相当于在构建完成后自动执行此脚本,这个脚本实现自动化发布工作

mv /opt/program/servers/viemall-service-web-0.0.1-SNAPSHOT.war /opt/program/servers/viemall-service-web.war

docker rm -f viemall-service-web-tomcat || true

docker run -d -p 8081:8080 –restart=always -v /opt/program/servers/viemall-service-web.war:/usr/local/tomcat/webapps/ROOT.war –name viemall-service-web-tomcat tomcat8:v1

echo '================结束 docker 部署任务================'

构建java环境的自动化构建和部署系列三

 所有系列文章:

  <<构建java环境的自动化构建和部署系列一>>

  <<构建java环境的自动化构建和部署系列二>>

 <<构建java环境的自动化构建和部署系列三>>

 <<构建java环境的自动化构建和部署系列四>>

前面已经讲述了SVN、mavean 、nexus的安装;本章将继续介绍jenkins安装与使用

一、环境 2

二、准备工作 2

三、Jenkins环境部署: 2

四、Jenkins系统配置 3

五、构建邮件配置 3

六. 配置SSH服务器 7

七、 Jenkins Job 9

为了方便运维人员的部署,采用Jenkins实现多机远程自动化部署方案;

自动化部署原理图示:

image.png

 Jenkins 是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变得可能。现在软件开发追求的是效率以及质量,Jenkins使得自动化成为可能!

亮点

  采用shell自定义脚本,控制集成部署环境更加方便灵活

  精简war包中的lib包,常驻tomcat里,减少war包传输时间

  细粒度的用户权限管理,

  构建失败发邮件通知相关人员解决

  自动按天备份war包,Jenkins配置备份以及版本控制化

  可扩展性的插件管理

一、环境

  Linux(centos 7)、JDK8

二、准备工作

  SVN 版本控制服务器

  Tomcat发布服务器

  Jenkins服务器(提前安装好Maven,SVN,Jdk)

  Nexus 服务器

实验时可以在同一台机器配置,但是生产不建议,一台机器挂了,所有服务器都挂了。

机器

IP

Jenkins

192.168.0.144

SVN

192.168.1.110

Tomcat

192.168.0.146

Nexus

http://192.168.0.110:6161/nexus/

三、Jenkins环境部署:

1、wget https://pkg.jenkins.io/redhat-stable/jenkins-2.32.2-1.1.noarch.rpm

       rpm -ivh jenkins-2.32.2-1.1.noarch.rpm

安装完成之后: 

    /usr/lib/jenkins/jenkins.war    WAR包 

    /etc/sysconfig/jenkins       配置文件 

    /var/lib/jenkins/        默认的JENKINS_HOME目录 

    /var/log/jenkins/jenkins.log    Jenkins日志文件 

Jenkins 命令:

   service jenkins start –启动

   service jenkins restart –重启

   service jenkins stop –停止

2、配置Jenkins 的目录空间及端口

    vi /etc/sysconfig/jenkins

    JENKINS_HOME="/data/jenkins"

    JENKINS_PORT="6161"

3、访问链接: http://192.168.0.144:6161/

    第一次访问会初始化安装;

    在配置的时候需要注意用户权限问题:

    https://www.cnblogs.com/melody-emma/p/6026622.html


4、Jenkins 插件安装:

    Jenkins以其拥有大量的插件而著称,接下来需要安装常用的插件,本文需要确保已经安装了如下插件:

    Email Extension Plugin (邮件通知)

   Deploy to container Plugin (部署到Java容器中的插件)

   Publish Over SSH (远程Shell)

   Maven Integration plugin (Maven集成,否则新建的时候没有Maven Project)

   Monitoring (监控Jenkins所消耗的系统资源,如内存使用等)

    Docker Commons (运行docker 命令)

    MultiJob plugin(多项目构建的插件)


四、Jenkins系统配置

  1、配置JDK、Git、Maven、Ant:系统管理–Global Tool Configuration

image.png

 image.png

五、构建邮件配置

     1. 配置邮件服务器及邮件模板

     首先保证已经成功安装了Email Extension Plugin插件,然后依次点击左边的“Manage Jenkins” – “Configure System”,首先在Jenkins Location项目下面设置系统管理员的邮件地  址,这里填写的邮箱地址必须跟下面设置的发件人邮箱一致,否则不能成功发送邮件。

image.png

接下来在 Extended E-mail Notification 项下面设置SMTP服务器和邮件模板,这里推荐使用QQ邮箱:

image.png

image.png

Default Recipients填写默认的接收人邮箱地址,多个用英文逗号(,)进行分割,邮件模板可以使用下面参考资料里面提供的模板。

Default Content Type内容:

image.png

构建通知:$PROJECT_NAME – Build # $BUILD_NUMBER – $BUILD_STATUS!

Default Subject内容:

资料参考:

   http://blog.csdn.net/fullbug/article/details/53024562

   http://blog.csdn.net/songjiaping/article/details/51496977


. 配置SSH服务器

首先保证已经安装了Publish Over SSH插件,然后依次点击左边的“Manage Jenkins” – “Configure System”,在Publish over SSH项下面设置登录到远程服务器的配置信息,可以使用用户名/密码的方式,也可以使用证书的方式,这里建议使用后者。

 

1、首先配置免SSH免密码登录:

  确认用户

  确认当前用户是你需要的用户!

 $ whoami

  root   #root用户,根据你自己的需求选择用户。我这儿用root用户演示。不建议使用root

 生成key

 $ cd ~ #回到用户目录,不回去也没有关系

 $ ssh-keygen    

  #可以使用-t选项选择加密方式,包括 RSA 和 DSA 两种密钥

  #例如:$ssh-keygen -t dsa 或者ssh-keygen -t rsa

  #加密方式不同,key的名称不同,其他没有区别

  #如果没有指定密钥,默认RSA

 Generating public/private rsa key pair.

 Enter file in which to save the key (/home/froad/.ssh/id_rsa): #私钥存放的位置,默认会存放在用户目录的.ssh文件夹,直接回车

 Enter passphrase (empty for no passphrase): #默认,回车

 Enter same passphrase again: #默认,回车

 Your identification has been saved in /home/froad/.ssh/id_rsa.#私钥路径

 Your public key has been saved in /home/froad/.ssh/id_rsa.pub.#公钥路径

 The key fingerprint is:

  e8:b6:e6:xxxxxxxxxxxxxxxxx:ec:b5:d8 root@192.168.0.144;

 将本地公钥上传到远程主机:

 scp ~/.ssh/id_rsa.pub tomcatuser1@192.168.0.146:.ssh/id_rsa.pub 在远程主机(tomcat所在主机,如192.168.0.146):1,生成密钥文件:   touch /home/tomcatuser1/.ssh/authorized_keys

6.再转到第二台机器的.ssh目录下,会发现刚刚传输过来的文件-authorized_keys,然后执行命令,将第二台计算机的公钥也加进来,如:cat id-     rsa.pub >> authorized_keys.

2,修改权限:  chmod 600 ~/.ssh/authorized_keys

3,将控制主机上传的公钥复制:  cat /home/tomcatuser1/.ssh/id_rsa.pub  >> /home/tomcatuser1/.ssh/authorized_keys   将authorized_keys文件拷贝到需要被管理的电脑上。注意:放在用户目录下.ssh文件夹中。Linux用户会限制你的访问权限

4.验证

  ssh tomcatuser1@192.168.0.146

5、其他

   如果添加指纹的时候提示添加失败,是因为你以前添加过了这个ip的指纹。

   解决办法:将.ssh目录的known_hosts文件删除掉(好粗暴啊( ⊙ o ⊙ )啊!),也可以打开这个文件把对于ip的那条记录删除(这个就精细多了O(∩_∩)O哈哈~)

   如果操作步骤都正确,但是依然要求输入密码。一般是因为权限的问题。命令如下

   chmod 755 ~/.ssh/

   chmod 600 ~/.ssh/id_rsa  ~/.ssh/id_rsa.pub

   chmod 644 ~/.ssh/authorized_keys

二、 接下来就可以在Publish over SSH项设置Passphrase和Key,分别是私钥的密码和id_rsa文件的内容,点击下面的Add按钮增加SSH Servers,如果不使用上面公共的密钥设置或者使用用户名密码可以将 Use password authenticatio, or use a different key 选项勾选。

image.png

      设置完成之后可以点击下面的Test Configuration按钮,如果无误的话会出现Success的提示。

      PS:如果对远程服务器进行了安全设置,需要将 /etc/ssh/sshd_config 文件中的 PermitRootLogin 项目设置为 without-password,这样root账号不能用密码直接远程登录,但可以使用密钥对进行登录。

      构建完上述的配置后,就可以构建JOB服务了,提前说明一下,Publish over SSH是基于插件的形式进行远程登录,您可以不用这种方式,可以就简单的采用SHELL方式进行免登陆。

3. 构建完成之后使用SSH发布到演示服务器上

  在项目的配置项中的Post Steps项中选中 Send files or execute commands over SSH:

   image.png

接下来就可以设置执行的任务内容了:

   image.png

七、Jenkins Job

   方式一:基于SSH插件

直接点击Jenkins首页的新建按钮,创建一个Maven项目,配置根据大家需要,实际配置,供参考:

   image.png

接下来就可以设置执行的任务内容了:

  image.png

八、自动化部署docker的脚本

#!/bin/bash
#Time
app_name="viemall-web"
deploy_war="$app_name.war"
deploy_path="/opt/program/servers/$app_name"
deploy_path_war="$deploy_path/$deploy_war"
if [ ! -f $deploy_path_war ]; then
    echo "!WARN: No build jar file found in $deploy_path_war."
    echo "!WARN: Deployment is skipped."
    exit 0
fi
#备份log日志
echo "*************备份log日志****************"
if [ ! -d "$deploy_path/logs" ];then
mkdir -p $deploy_path/logs
else
   mv $deploy_path/logs $deploy_path/logs-$(date '+%m-%d')
   rm -rf $deploy_path/logs/*
fi
echo "************* 启动docker镜像 ****************"
docker rm -f $app_name || true
docker run -d -p 8080:8080 --restart=always -e TZ=Asia/Shanghai  -v $deploy_path_war:/usr/local/tomcat/webapps/ROOT.war -v $deploy_path/logs:/usr/local/tomcat/logs --name $app_name harbor.dczou.com/benniu/tomcat8-session-redis-test:v1
echo "************* 启动docker镜像成功 ****************"

构建java环境的自动化构建和部署系列二

 所有系列文章:

  <<构建java环境的自动化构建和部署系列一>>

  <<构建java环境的自动化构建和部署系列二>>

 <<构建java环境的自动化构建和部署系列三>>

 <<构建java环境的自动化构建和部署系列四>>

  

 前段为了方便公司管理项目的版本控制,和方便开发人员快速的部署项目(公司么有运维人员),搭建了搭建敏捷高效的持续集成管理平台,并且规范了安装部署的规范统一通过Shell来实现一键安装环境.(不过也要淘汰了,BOSS想通过Docker 来实现系统环境的部署)

持续集成管理平台的组成

    持续集成管理平台不只是CI服务器,是一系列软件开发管理工具的组合

1、源码版本管理:Subversion、 Git

2、项目构建工具:Maven、 Ant

3、代码质量管理:Sonar(Checkstyle、 PMD、 FindBugs……)

4、持续集成引擎: Jenkins、

5、应用持续部署:操作系统、 JDK、 Tomcat、 JBoss…

实施持续集成过程中要用到的其他各种工具、各种插件、和Shell脚本…

本系列的大概章目: 

   (1) Subversion源码版本控制系统的安装

    Subversion + Apache + jsvnadmin

    公司是使用Windows来搭建SVN的,这比Linux方便多了,偷懒了

     http://www.dczou.com/viemall/522.html

  (2) Maven私有库和本地库的安装与配置  Nexus + Maven

  (3) Sonar代码质量管控平台的安装与使用配置,

      这个比较坑,在安装的时候插件都不兼容;需要一个个找来组装

   (4) Hudson持续集成引擎的安装与配置

   (5) 自动化部署的实现

   (6) 自动化测试的实现

Maven私有库和本地库的安装与配置—-> Maven

    java开发环境(JDK)/ Eclipse IDE

    Maven3.0以上版本 下载地址:

       http://maven.apache.org/index.html

  1.本机机子环境:

      jdk1.7.0_55、apache-maven-3.3.9-bin.zip、myeclise10

 2.配置Mavean环境

       MAVEN_HOME: D:\web-server\apache-maven-3.2.3;

       path: ;%MAVEN_HOME%\bin;

 3.修改本地仓库位置

      Maven会将下载的类库(jar包)放置到本地的一个目录下,如果想重新定义这个目录的位置就需要修改Maven本地仓库的配置:

     D:\web-server\apache-maven-3.2.3\conf\settings.xml

 image.png

   依据该配置,Maven就会将下载的类库保存到固定文件中。

    通过mvn -V 检查mavean是否安装成功;

二、Maven基本介绍:

      Maven 是一个项目管理和构建自动化工具。但是对于我们程序员来说,我们最关心的是它的项目构建功能。所以这里我们介绍的就是怎样用 maven 来满足我们项目的日常需要。

      Maven 使用惯例优于配置的原则 。它要求在没有定制之前,所有的项目都有如下的结构:

 image.png

 Maven 常用命令:

mvn archetype:create 创建Maven项目

mvn compile 编译源代码

mvn deploy 发布项目

mvn test-compile 编译测试源代码

mvn test 运行应用程序中的单元测试

mvn site 生成项目相关信息的网站

mvn clean 清除项目目录中的生成结果

mvn package 根据项目生成的jar

mvn install 在本地Repository中安装jar

mvn eclipse:eclipse 生成eclipse项目文件;

清除eclipse的一些系统设置:mvn eclipse:clean 

mvnjetty:run 启动jetty服务

mvn tomcat:run 启动tomcat服务

mvn clean package -Dmaven.test.skip=true:清除以前的包后重新打包,跳过测试类

我常用的命令是:clean install package -Dmaven.test.skip -PDEV

使用-P参数显示的激活一个profile

    Maven简介(三)——profile介绍

如何将Jar包添加到本地maven仓库:

mvn install:install-file 

 -DgroupId=net.sf.json-lib

 -DartifactId=json-lib

 -Dversion=2.1

 -Dpackaging=jar

 -Dfile=json-lib-2.1-jdk15.jar

 

mvn deploy:deploy-file -DgroupId=org.springframework 

-DartifactId=org.springframework.web.servlet 

-Dversion=3.1.1.RELEASE 

-Dpackaging=jar -Dfile=org.springframework.web.servlet-3.1.1.RELEASE.jar

-Durl=http://192.168.0.66:8081/nexus/content/repositories/releases/    

-DrepositoryId=user-releases


mavean的生命周期及常用的插件介绍:

http://www.cnblogs.com/davidwang456/p/3915031.html


Mavean版本管理:

image.png

  http://hualom.iteye.com/blog/1387708


maven pom.xml文件教程详解:

http://www.zuidaima.com/share/1781583829978112.htm

http://yanguz123.iteye.com/blog/2211224


maven 多项目管理:

https://my.oschina.net/xuqiang/blog/99854

http://www.cnblogs.com/1995hxt/p/5254448.html 


基于mavean配置多个源目录环境(用于环境区分):

  http://casheen.iteye.com/blog/540385

   https://my.oschina.net/vernon/blog/271970

 资料参考:http://blog.csdn.net/liujiahan629629/article/details/39272321

Maven私有库和本地库的安装与配置—-> Nexus

        简介 :前边简单介绍了Maven,而Maven默认提供的中央仓库是在远程网络服务Appache提供的,这对于我们开发时不合理的。如果我们没网了或者什么情况,我们怎么办?也就是说我们队中央仓库的依赖性太大。而Nexus私服则可以解决我们这个问题。先看下这张图应该大家就非才明白了:

image.pngimage.png

      这样就相当于在我们本地的局域网搭建了一个类似中央仓库的服务器,我们开始将中央仓库的一些资料下载到私服务器上,然后平时我们的maven项目就是直接访问局域网内的私服即可,既节省了网络带宽也会加速项目搭建的进程,这样对我们开发来说,对公司来说都是非常好的选择。下边简单看一下Nexus私服的简单使用:

环境配置:

        本地环境: nexus-2.14.2-01-bundle.zip 

 1、Nexus下载

       下载地址:http://www.sonatype.org/nexus/go 

 2、Nexus启动

        我下载的是zip包,解压后进入\ nexus-2.14.2-01-bundle \nexus-2.14.2-01\bin\jsw\,根据操作系统类型选择文件夹,我选的是windows-x86-64文件夹,进入后可看到如下所示bat文件。

 8081为默认的端口号,要修改端口号可进入nexus-2.14.2-01-bundle\nexus-2.14.2-01\conf\打开nexus.properties文件,修改application-port属性值就可以了。

image.png

       双击console-nexus.bat运行。游览器中输入http://127.0.0.1:8081/nexus/,出现如下图所示就代表nexus已经启动成功。

image.png 

Nexus 的仓库分为这么几类:

   hosted 宿主仓库:主要用于部署无法从公共仓库获取的构件(如 oracle 的 JDBC 驱动)以及自己或第三方的项目构件;

   proxy 代理仓库:代理公共的远程仓库;

   virtual 虚拟仓库:用于适配 Maven 1;

   group 仓库组:Nexus 通过仓库组的概念统一管理多个仓库,这样我们在项目中直接请求仓库组即可请求到仓库组管理的多个仓库。

PublicRepositories:  仓库组:

     3rd party: 无法从公共仓库获得的第三方发布版本的构件仓库

     Apache Snapshots: 用了代理ApacheMaven仓库快照版本的构件仓库

     Central: 用来代理maven中央仓库中发布版本构件的仓库

    Central M1 shadow: 用于提供中央仓库中M1格式的发布版本的构件镜像仓库

     Codehaus Snapshots: 用来代理CodehausMaven 仓库的快照版本构件的仓库

     Releases: 用来部署管理内部的发布版本构件的宿主类型仓库

     Snapshots:用来部署管理内部的快照版本构件的宿主类型仓库

image.png

配置Maven使用Nexus私服

     让maven项目使用nexus作为远程仓库有两种方式,第一种是在项目的pom.xml中进行更改,让单个项目使用nexus仓库;另一种是通过修改maven的配置文件settings.xml进行更改,让所有项目都使用nexus仓库。

    pom配置:

<!-- 设定除中央仓库 (repo1.maven.org/maven2/)外的其他仓库,按设定顺序进行查询,
       如有Nexus私服, 取消注释并指向正确的服务器地址 -->
	<repositories>
		<repository>
			<id>nexus</id>
			<name>Team Nexus Repository</name>
			<url>http://192.168.0.110:6161/nexus/content/groups/public</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
	</repositories>

	<!-- 如有Nexus私服, 取消注释并指向正确的服务器地址 -->
	<pluginRepositories>
		<pluginRepository>
			<id>nexus</id>
			<name>Team Nexus Repository</name>
			<url>http://192.168.0.110:6161/nexus/content/groups/public</url>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>

	<!-- 将项目发布到私服 -->
	<distributionManagement>
		<snapshotRepository>
			<uniqueVersion>false</uniqueVersion>
			<id>nexus-snapshots</id>  <!-- settings.xml id 对应 -->
			<name>User Porject Snapshot</name>
			<url>http://192.168.0.110:6161/nexus/content/repositories/snapshots/</url>
		</snapshotRepository>
		<repository>
			<id>nexus-releases</id>
			<name>User Porject Release</name>
			<url>http://192.168.0.110:6161/nexus/content/repositories/releases/</url>
		</repository>
	</distributionManagement>

基于Mavean将项目发布私服:

     1 . 修改私服中仓库的部署策略

        Release版本的项目应该发布到Releases仓库中,对应的,Snapshot版本应该发布到Snapshots仓库中。Maven根据pom.xml文件中版本号<version>节点的属性是否包含-SNAPSHOT,来判断该项目是否是snapshot版本。如果是snapshot版本,在执行mvn deploy部署命令时,maven会自动将项目发布到Snapshots仓库。要发布项目,

         首先需要将Releases仓库和Snapshots仓库的“Deployment Policy”设置为“Allow Redeploy”:

    奇葩问题:在mvn deploy jar是:Snapshot(快照)形式的项目打包后会自动增加时间戳的部分;

    问题:http://jira.codehaus.org/browse/MNG-4452

     image.png

  2 . 配置项目的部署仓库

      在pom.xml中分别对Release版本和Snapshot版本配置部署仓库,其中id唯一,url分别对应私服中Releases和Snapshots仓库的Repository Path:

     image.png

 配置如下:

    <!– 将项目发布到私服 –>        

 <distributionManagement>

              <snapshotRepository>

                     <uniqueVersion>false</uniqueVersion>

                     <id>nexus-snapshots</id>  <!– settings.xml id 对应 –>

                     <name>User Porject Snapshot</name>

                     <url>http://192.168.0.110:6161/nexus/content/repositories/snapshots/</url>

              </snapshotRepository>

              <repository>

                     <id>nexus-releases</id>

                     <name>User Porject Release</name>

                     <url>http://192.168.0.110:6161/nexus/content/repositories/releases/</url>

              </repository>

       </distributionManagement>


 3.在settings.xml中分别为上面配置的部署仓库配置server,其中id需要分别对应上面的部署仓库id:

  image.png

4 . 发布项目

   右键pom.xml – Run As – 2 Maven build…     clean deploy;


构建java环境的自动化构建和部署系列一

 所有系列文章:

  <<构建java环境的自动化构建和部署系列一>>

  <<构建java环境的自动化构建和部署系列二>>

 <<构建java环境的自动化构建和部署系列三>>

 <<构建java环境的自动化构建和部署系列四>>

        前段为了方便公司管理项目的版本控制,和方便开发人员快速的部署项目(公司么有运维人员),搭建了搭建敏捷高效的持续集成管理平台,并且规范了安装部署的规范统一通过Shell来实现一键安装环境.(不过也要淘汰了,BOSS想通过Docker 来实现系统环境的部署)

持续集成管理平台的组成

    持续集成管理平台不只是CI服务器,是一系列软件开发管理工具的组合

1、源码版本管理:Subversion、 Git

2、项目构建工具:Maven、 Ant

3、代码质量管理:Sonar(Checkstyle、 PMD、 FindBugs……)

4、持续集成引擎: Jenkins、

5、应用持续部署:操作系统、 JDK、 Tomcat、 JBoss…

实施持续集成过程中要用到的其他各种工具、各种插件、和Shell脚本…

    总体的平台流程图:下图网上找到,公司的部署架构跟这个类似,所以就没有自己去画了

image.png

本系列的大概章目: 

   (1) Subversion源码版本控制系统的安装

    Subversion + Apache + jsvnadmin

    公司是使用Windows来搭建SVN的,这比Linux方便多了,偷懒了

  (2) Maven私有库和本地库的安装与配置  Nexus + Maven

  (3) Sonar代码质量管控平台的安装与使用配置,

      这个比较坑,在安装的时候插件都不兼容;需要一个个找来组装

   (4) Hudson持续集成引擎的安装与配置

   (5) 自动化部署的实现

  (6) 自动化测试的实现

所有的前提准备:

    JDK 的环境安装(我是1.7的版本)

    Mysql 的安装.

系列一:Subversion + Apache + jsvnadmin

      公司是通过Window来搭建的SVN环境的,关于Windows的搭建,本章不去细说,本章通过Linux环境来搭建源码的控制。建议使用Windows来管理SVN,使用起来比较便捷方便,个人喜欢点;

安装步骤:

   #yum install -y httpd

  安装 apache

    # yum install httpd httpd-devel

    # service httpd start

    # chkconfig httpd on

我的机器有nginx 所以为了防止80端口冲突,改成了81。没有需要的可以不更改,也试过Nginx来实现,但是遇到一些奇葩问题,就采用Apatch了.

   # vi /etc/httpd/conf/httpd.conf

找到 ServerName 并修改成

    Listen 81

    ServerName localhost:81

防火墙中打开 81 端口:

    # vi /etc/sysconfig/iptables

    -A INPUT -m state –state NEW -m tcp -p tcp –dport 81 -j ACCEPT

    # service iptables restart

 访问:http://192.168.1.105:81/ 就可以知道有么有安装成功

 

安装 SVN 服务

   # yum install mod_dav_svn subversion

  必须安装 mod_dav_svn 模块

   安装完 svn 后要重启 apache

   # service httpd restart

查看测试是否安装 svn 模块

# ls /etc/httpd/modules/ | grep svn

# svn –version

创建 svn 库主目录(多库模式,一份配置文件管理多个库)

    # mkdir /svn/

    # vi /etc/httpd/conf.d/subversion.conf 添加以下内容

LoadModule dav_svn_module     modules/mod_dav_svn.so
LoadModule authz_svn_module   modules/mod_authz_svn.so
<Location /svn/>
         DAV svn
         SVNListParentPath on
         SVNParentPath /svn
         AuthType Basic
         AuthName "Subversion repositories"
         AuthUserFile /svn/passwd.http
         AuthzSVNAccessFile /svn/authz
         Require valid-user
</Location>
RedirectMatch ^(/svn)$ $1/

创建/svn/passwd.http 和/svn/authz

   # touch /svn/passwd.http

   # touch /svn/authz

重启 apache

    # service httpd restart

 

安装 jsvnadmin

   svnadmin 介绍

(在 Google Code 上,需要 FQ 才能下载。我们也会把最新版的 jsvnadmin 放到群共享中)

     https://code.google.com/p/jsvnadmin/

      https://jsvnadmin.googlecode.com/files/svnadmin-3.0.5.zip

 

将下载的jsvnadmin部署在tomcat;

修改svnadmin/WEB-INF 的jdbc.properties

内容改为如下

db=MySQL
#MySQL
MySQL.jdbc.driver=com.mysql.jdbc.Driver
MySQL.jdbc.url=jdbc:mysql://127.0.0.1:3306/svnadmin?characterEncoding=utf-8
MySQL.jdbc.username=root
MySQL.jdbc.password=123456

创建 svnadmin 数据库并导入相应数据( UTF-8 编码)

执行 db/mysql5.sql 和 db/lang/en.sql

 

启动tomcat:

浏览器中打开: http://192.168.1.105:9000/svnadmin/

第一次访问需要设置登录用户和密码,登录后的管理界面:

 image.png

创建库

 image.png

此时:

   /svn/目录下会创建一个viemall 的 SVN 库目录。通过下面就会有SVN项目的用户管理文件.

配置库目录权限

# cd /svn

# chown -R apache.apache viemall

# chmod -R 777 viemall

(如创建新库,需要对新建的库目录执行以上两步授权操作)

  否则在客户端提交代码的时候,会出现“SVN提交时:could not begin a transaction”;

关闭 SELinux( Linux 的访问控制)

修改/etc/selinux/config 文件

# vi /etc/selinux/config

将 SELINUX=enforcing 改为SELINUX=disabled

重启机器即可

# reboot

 

SVN 版本管理平台( Subversion+Apache+Jsvnadmin)的使用:

先安装 SVN 管理客户端 TortoiseSVN,方便对 SVN 库的操作和管理

    http://tortoisesvn.net/downloads.html 这个小海龟不多说都懂。

 

接下来可以对 wusc_edu 库进行相应的操作

(1) 用户组

(2) 用户

(3) 授权

(4) 导入项目

 image.png

     http://auskangaroo.blog.51cto.com/740826/1410549

聊聊互联网限流方案

   首先要知道为什么要进行限流,限流的方式有那些,那些应用需要限流。

    在业务场景中,我们会遇到有百万甚至更加大的用户请求流量来访问接口,或者在业务对接过程中,业务提供方的访问频率控制,等等我们的业务都需要做限流处理,

这个时候如果不做任何保护措施,服务器就会承受很大的处理压力,请求量很高,服务器负载也很高,并且当请求超过服务器承载极限的时候,系统就会崩溃,导致所有人都不能访问。为了应用服务的高可用,

一个常用的办法是对大流量的请求(秒杀/抢购)进行限流,拦截掉大部分请求,只允许一部分请求真正进入后端服务器,这样就可以防止大量请求造成系统压力过大导致的系统崩溃,从而保护服务正常可用。这里限流的常用算法有漏桶算法和令牌桶算法。

  额外插一句:处理高并发的三板斧: 缓存、降级和限流!

常见限流方案

 令牌桶(Token Bucket)、漏桶(leaky bucket)和计数器算法是最常用的三种限流的算法。

计数器方式:

    计数器限流算法也是比较常用的,主要用来限制总并发数,比如数据库连接池大小、线程池大小、程序访问并发数等都是使用计数器算法。也是最简单粗暴的算法。

  采用AtomicInteger:

     使用AomicInteger来进行统计当前正在并发执行的次数,如果超过域值就简单粗暴的直接响应给用户,说明系统繁忙,请稍后再试或其它跟业务相关的信息。

    弊端:使用 AomicInteger 简单粗暴超过域值就拒绝请求,可能只是瞬时的请求量高,也会拒绝请求。

 采用令牌Semaphore:

     使用Semaphore信号量来控制并发执行的次数,如果超过域值信号量,则进入阻塞队列中排队等待获取信号量进行执行。如果阻塞队列中排队的请求过多超出系统处理能力,则可以在拒绝请求。

    相对Atomic优点:如果是瞬时的高并发,可以使请求在阻塞队列中排队,而不是马上拒绝请求,从而达到一个流量削峰的目的。

 采用ThreadPoolExecutor java线程池:

    固定线程池大小,超出固定先线程池和最大的线程数,拒绝线程请求;

     https://www.cnblogs.com/clds/p/5850070.html

令牌桶方式:

 image.png 

   令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。先有一个木桶,系统按照固定速度,往桶里加入Token,如果桶已经满了就不再添加。当有请求到来时,会各自拿走一个Token,取到Token 才能继续进行请求处理,没有Token 就拒绝服务。

  这里如果一段时间没有请求时,桶内就会积累一些Token,下次一旦有突发流量,只要Token 足够,也能一次处理,所以令牌桶算法的特点是允许突发流量。

    我们看一个例子,看看令牌桶如何允许突发流量,假如令牌则按照每秒5 个的速度放入令牌桶,桶中最多存放20 个令牌,那系统可以支持两种类型的请求流量,一种是允许持续的每秒处理5 个请求,第二种是每隔4 秒,等桶中20 个令牌攒满后,就可以处理一次有20 个请求的突发情况。

令牌桶的方案设计:

  使用guava提供工具库里的RateLimiter类(内部采用令牌捅算法实现)进行限流

   平滑突发限流(SmoothBursty):

   image.png

     image.png

 

解析:

 RateLimiter.create(5) 表示桶容量为5且每秒新增5个令牌,即每隔200毫秒新增一个令牌;

 limiter.acquire()表示消费一个令牌,如果当前桶中有足够令牌则成功(返回值为0),如果桶中没有令牌则暂停一段时间,比如发令牌间隔是200毫秒,则等待200毫秒后再去消费令牌(如上测试用例返回的为0.198239,差不多等待了200毫秒桶中才有令牌可用),这种实现将突发请求速率平均为了固定请求速率。如果结构不想等待可以采用tryAcquire立刻返回!

RateLimiter的突发情况处理:

 image.png

     image.png 

limiter.acquire(5)表示桶的容量为5且每秒新增5个令牌,令牌桶算法允许一定程度的突发,所以可以一次性消费5个令牌,但接下来的limiter.acquire(1)将等待差不多1秒桶中才能有令牌,且接下来的请求也整形为固定速率了。

image.png

image.png

 

同上边的例子类似,第一秒突发了10个请求,令牌桶算法也允许了这种突发(允许消费未来的令牌),但接下来的limiter.acquire(1)将等待差不多2秒桶中才能有令牌,且接下来的请求也整形为固定速率了。


    因为SmoothBursty允许一定程度的突发,会有人担心如果允许这种突发,假设突然间来了很大的流量,那么系统很可能扛不住这种突发。因此需要一种平滑速率的限流工具,从而系统冷启动后慢慢的趋于平均固定速率(即刚开始速率小一些,然后慢慢趋于我们设置的固定速率)。Guava也提供了SmoothWarmingUp来实现这种需求类似漏桶算法;

 

漏桶算法:

        一个固定容量的漏桶,按照常量固定速率流出水滴;

      先想象有一个木桶,新请求就像水滴一样,不断地滴进来,水滴进来的速度是不确定的,有时会快一点,有时会慢一点,同时桶底下有个洞,可以按照固定的速度把水漏走,如果水进来的速度比漏走的快,桶就会满了,桶满了水就会漫出来,对应的就是拒绝请求。

  漏桶算法的主要特点是可以平滑网络上的突发流量,请求可以被整形成稳定的流量。
  image.png

C               // 水桶总容量

r               // 漏水速度

at              // 上一个请求时间

w               // 当前桶里面的水量
漏桶的方案设计:

    SmoothWarmingUp创建方式:RateLimiter.create(doublepermitsPerSecond, long warmupPeriod, TimeUnit unit)

permitsPerSecond表示每秒新增的令牌数,warmupPeriod表示在从冷启动速率过渡到平均速率的时间间隔。

image.png

image.png

    速率是梯形上升速率的,也就是说冷启动时会以一个比较大的速率慢慢到平均速率;然后趋于平均速率(梯形下降到平均速率)。可以通过调节warmupPeriod参数实现一开始就是平滑固定速率。

以上的方式都是单应用上的请求限流,那么在分布式上,就不能这样全局的方式来实现了, 因此我们需要分布式限流和接入层限流来解决这个问题。

 

常用的分布方式的解决方式有:

 1.纯采用nginx 的IP方式限流,在一些大型的应用流量可以这样控制;

   https://www.cnblogs.com/biglittleant/p/8979915.html

 2.采用redis 的计时和计数方式,在规定的时间窗口期,允许通过的最大请求数量;

 3.采用redis lua或者 nginx lua方式实现限流处理;

   https://blog.csdn.net/fenglvming/article/details/51996406

一般都是采用应用层的限流,用户接入层都是采用负载均衡去分发流量;

 

额外资料参考:

http://m635674608.iteye.com/blog/2339587

http://rayleung.xyz/2016/06/23/rate-limit/

https://blog.52itstyle.com/archives/2982/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

 

开发上怎么提供数据库的安全?

开发过程中,了提升的安全,一般都采用一下方式提示据的安全性:

 1.码级别:

 2.的用户权级别:

码级别:

       如果接采用明文的方式,这样的安全性不是很高,以至于所有的技只要知道配置文件就可以知道登录数帐号和密了,

如:

image.png

的方式:通加密和解密

druid配置加密:

image.png

实践过程:

1.生成加密的密信息:

命令方式:

  入命令 java -cp druid-1.0.27.jar com.alibaba.druid.filter.config.ConfigTools your_password  

  image.png

方式生成:

public class DruidTest {
 
    public static void main(String[] args) throws Exception {
        // 密码明文
        String password = "viemall@123";
 
        System.out.println("密码[ " + password + " ]的加密信息如下:\n");
 
        String[] keyPair = ConfigTools.genKeyPair(512);
        // 私钥
        String privateKey = keyPair[0];
        // 公钥
        String publicKey = keyPair[1];
        // 用私钥加密后的密文
        password = ConfigTools.encrypt(privateKey, password);
 
        System.out.println("privateKey:" + privateKey);
        System.out.println("publicKey:" + publicKey);
        System.out.println("password:" + password);
        String decryptPassword = ConfigTools.decrypt(publicKey, password);
        System.out.println("decryptPassword:" + decryptPassword);
 
    }
 
}

image.png

配置Druid解密:

jdbc.type=mysql
 jdbc.driver=com.mysql.jdbc.Driver
 jdbc.url=jdbc:mysql://localhost:3306/viemall?useUnicode=true&characterEncoding=utf-8
 jdbc.username=root
 jdbc.password=IVpkS/WvZQKLcm4+f7xlLFo5FzxGIj3O1br9TcvLlq2a17mmt0SWe9Qq1hyVKsnbsRdU6FKTItc6vVIF9RRpTw==
 jdbc.publickey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKYBLQ067pCDwEfysD6rAIWZD4C2K7BO09NFYM
 mA+VD4i+28znGk9F3w3uCFp6vYf633rPJpx+hoHU/+9gBIewUCAwEAAQ==

配置Druid解密的主要新增的行配置。

1

<property name="connectionProperties"
value="config.decrypt=true;config.decrypt.key=${jdbc.publickey}"/>

2、<property name="filters" value="config" />   作用:提示Druid据源需要对数码进行解密  


的用户权级别:

除了代的密安全上限制,在用帐号权限上也要分配好相的用户权限,如:查询 只有查询数据的限;

GRANT SELECT ON viemall.* TO reader@"%"  IDENTIFIED BY "123456"
FLUSH PRIVILEGES;

这样行其他命令的提示限不足:

错误: 1142

DELETE command denied to user 'reader'@'127.0.0.1' for table 'viemall_sms_log'

的用命令管理:

1.新建用

  1.1 登MYSQL

  @>mysql -u root -p

  @>密

  1.2 建用

  mysql> insert into mysql.user(Host,User,Password) values("localhost","test",password("1234"));

  这样建了一:test 密码为:1234 的用

  注意:此的"localhost",是指只能在本地登,不能在另外一台机器上程登。如果想程登"localhost""%",表示在任何一台电脑上都可以登。也可以指定某台机器可以程登

  1.3 然后登一下:

  mysql>exit;

  @>mysql -u test -p

  @>入密

  mysql>登成功

2.

  授格式:grant 限 on .* to 名@登主机 identified by "密"; 

  2.1 登MYSQL(有ROOT限),里以ROOT身

  @>mysql -u root -p

  @>密

  2.2 首先户创建一个数(testDB)

  mysql>create database testDB;

  2.3 授test户拥有testDB的所有限(某个数的所有限):

   mysql>grant all privileges on testDB.* to test@localhost identified by '1234';

   mysql>flush privileges;//刷新系统权限表

  格式:grant 限 on .* to 名@登主机 identified by "密"; 

  2.4 如果想指定部分一用,可以这样来写:

  mysql>grant select,update on testDB.* to test@localhost identified by '1234';

  mysql>flush privileges; //刷新系统权限表

  2.5 授test户拥有所有的某些限:   

  mysql>grant select,delete,update,create,drop on *.* to test@"%" identified by "1234";

     //test户对所有都有select,delete,update,create,drop 限。

  //@"%" 表示所有非本地主机授,不包括localhost。(localhost地址设为127.0.0.1,如果设为真实的本地地址,不知道是否可以,验证。)

 //localhost:加上一句grant all privileges on testDB.* to test@localhost identified by '1234';即可。

3、除用

   @>mysql -u root -p

  @>密

   mysql>Delete FROM user Where User='test' and Host='localhost';

   mysql>flush privileges;

   mysql>drop database testDB; //除用

账户限:>drop user 用名@'%';

        >drop user 用名@ localhost; 

 

4. 修改指定用

    @>mysql -u root -p

    @>密

    mysql>update mysql.user set password=password('新密') where User="test" and Host="localhost";

    mysql>flush privileges;

 

5. 列出所有

  mysql>show database;

 

6. 换数

  mysql>use '名';

 

7. 列出所有表

  mysql>show tables;

 

8. 据表结构

  mysql>describe 表名;

 

9. 据表

  mysql>drop database 名;

  mysql>drop table 据表名;

redis的RDB和AOF 持久化方案

最近在弄docker的Redis部署,顺便去温习了一下redis 的持久化方案,整理了一下笔记:

 如果想基础学起可以看之前的文章: http://www.dczou.com/viemall/439.html

本章大纲:

  RDB和AOF两种持久化机制的介绍:

  RDB持久化机制的优点

  RDB持久化机制的缺点

  AOF持久化机制的优点

  AOF持久化机制的缺点

  RDB和AOF如何选择;

  RDB 实战:

  AOF 实战:


RDB和AOF两种持久化机制的介绍:

    RDB持久化机制,对redis中的数据执行周期性的持久化,是基于二进制文件形式保存

AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集

   如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制;

  禁止:RDB   要设置 save "",还要把持久化的本地文件干掉!

  禁止: AOF   appendonly=no;

  通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来.

  在生产环境中,我们可以定期将持久化文件同步到其他备份机器或者是阿里云服务;

 如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整

RDB持久化机制的优点

   (1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去;

(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可

(3)相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速

 

RDB持久化机制的缺点

   (1)如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据

(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒

RDB 实战:

   配置RDB 持久化:

image.png

   每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting,快照

  客户端也可以使用 save或者 bgsave 命令通知 redis做一次快照持久化。save 操作是在 主线程中保存快照的, 由于 redis 是用一个主线程来处理所有客户端的请求, 这种方式会阻 塞所有客户端请求。 所以不推荐使用。 另一点需要注意的是, 每次快照持久化都是将内存数 据完整写入到磁盘一次, 并不是增量的只同步增量数据。 如果数据量大的话, 写操作会比较 多,必然会引起大量的磁盘 IO操作,可能会严重影响性能。
  注意: 由于快照方式是在一定间隔时间做一次的,所以如果 redis意外当机的话,就会丢失最后一次快照后的所有数据修改

工作机制:  

    (1)redis根据配置自己尝试去生成rdb快照文件

(2)fork一个子进程出来

(3)子进程尝试将数据dump到临时的rdb快照文件中

(4)完成rdb快照文件的生成之后,就替换之前的旧的快照文件

dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照

实战测试:

 我们在redis 保存几条数据,然后shutdown 掉服务,然后重新启动服务,你会发现保存的数据都还存在, 通过redis-cli SHUTDOWN这种方式去停掉redis,其实是一种安全退出的模式,redis在退出的时候会将内存中的数据立即生成一份完整的rdb快照

     注:用kill -9粗暴杀死redis进程,模拟redis故障异常退出,你就会发现导致内存数据丢失的场景了,所以需要通过save 来设置一个时间的间隔和数量;

     如:配置成  save 5 1 ,你会发现,插入几条数据后,待5秒后kill服务,重新启动该保存的数据还会存在。


RDB 的数据导入:

redis中使用redis-dump导出、导入、还原数据实例: https://blog.csdn.net/dszgf5717/article/details/48002943

AOF持久化机制的优点: 

    (1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据 

   (2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复

   (3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。

  (4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

AOF持久化机制的缺点

   (1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大

(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的

AOF 实战:

   配置AOF持久化:

   AOF持久化,默认是关闭的,默认是打开RDB持久化 

   Appendonly=yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓, AOFRD同时开启的时候,rdb里也有部分数据,aof里也有部分数据,这个时候其实会发现,rdb的数据不会恢复到内存中


工作机制:

   打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写入os cache的,然后每隔一定时间再fsync一下,

而且即使AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为aof数据比较完整


可以配置AOF的fsync策略,有三种策略可以选择,一种是每次写入一条数据就执行一次fsync; 一种是每隔一秒执行一次fsync; 一种是不主动执行fsync

 

always: 每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢,那就只能这样了

 

everysec: 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万的

 

no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了

实战测试:

  重复RDB 实战测试的步骤,你可以发现数据被恢复回来了,就是从AOF文件中恢复回来的

  同时有RDB snapshot文件和AOF日志文件,那么redis重启的时候,会优先使用AOF进行数据恢复,因为其中的日志更完整。

AOF的 rewrite log 机制:

redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉

redis中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在redis内存中

所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,到很大很大

所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致

可以通过配置来配置rewrite策略:

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

 

比如说上一次AOF rewrite之后,是128mb

然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite

但是此时还要去跟min-size,64mb去比较,256mb > 64mb,才会去触发rewrite

 

AOF破损文件的修复:

    如果redis在append数据到AOF文件时,机器宕机了,可能会导致AOF文件破损

 用redis-check-aof –fix命令来修复破损的AOF文件,用的很少;


RDB和AOF如何选择;

(1)不要仅仅使用RDB,因为那样会导致你丢失很多数据

(2)也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug

(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

深入浅出Docker技术- Disconf 分布式配置中心

 

本文主要介绍基于Disconf 搭建

环境准备:

   docker/centos7

Disconf 不懂的可以看我之前的系列文章:


   分布式配置中心 Disconf实践-概念片

   分布式配置中心 Disconf实践- 安装篇

   分布式配置中心 Disconf实践- 升级篇


image.png


 docker compose文件编写:

     https://gitee.com/gz-tony/viemall-dubbo/tree/master/viemall-docekr/compose/disconf

docker compose 服务启动;

    docker-compose up –d

docker ps –a : 服务列表

      image.png

所有容器启动正常以后,就可以通过 http://yourhost  访问Disconf-web服务了。Disconf的客户端需要访问zookeeper,所以在配置Disconf的客户端时请配置hosts文件,将主机名disconf-zoo映射到Docker所在的服务器上。

 image.png

   不过我用 admin admin 后台始终提示密码错误?????;

参考资料:

     https://github.com/friddle/docker-disconf

 

深入浅出Docker技术- mysql 部署;

本章目录:

 1.环境准备;

 2. mysql 启动命令:

环境准备:

     docker/centos7

 简单命令:

docker run -d -p 3306:3306 --restart=always viemall-mysql -e MYSQL_ROOT_PASSWORD=123456 \
    -v /opt/docker/compose/mysql/data:/var/lib/mysql \
	-v /opt/docker/compose/mysql/conf/utf8.cnf:/etc/mysql/my.cnf \
	 mysql:5.7

初始化启动mysql文件命令:

docker run -d -p 3306:3306 --restart=always viemall-mysql -e MYSQL_ROOT_PASSWORD=123456 \
-v /opt/docker/compose/mysql/sql:/docker-entrypoint-initdb.d \
-v /opt/docker/compose/mysql/data:/var/lib/mysql \
-v /opt/docker/compose/mysql/conf/utf8.cnf:/etc/mysql/my.cnf \
mysql:5.7

初始文件:

create DATABASE `disconf` character set utf8;
create user 'disconf'@'localhost' identified by 'disconf';
grant all privileges on disconf.* to 'disconf'@'%';
FLUSH PRIVILEGES ;


深入浅出Docker技术- Redis sentinel 集群的搭建

本章目录:

 1.环境准备;

 2.集群启动与测试:

 3. redis ha 常用方案:

 4. sentinel.conf 介绍:

 5.Java 操作 sentinel

 

本文主要介绍基于redis高可用的集群搭建

环境准备:

   docker/centos7

上一章介绍了基于redis slaveof 实现的redis主从复制;但是有一个问题是就, 当master节点失效时,应选举出一个slave节点作为新的master。然而Redis本身(包括它的很多客户端)没有实现自动故障发现并进行主备切换的能力,需要外部的监控方案来实现自动故障恢复。Redis Sentinel是官方推荐的高可用性解决方案。它是Redis集群的监控管理工具,可以提供节点监控、通知、自动故障恢复和客户端配置发现服务。

 

Redis slaveof 部署拓扑结构图

image.png

 

Redis sentinel部署拓扑结构图:

 image.png 

分别有3个Sentinel节点,1个主节点,2个从节点组成一个Redis Sentinel。采用docker 容器方式:

 

role

IP

port

master

127.0.0.1

6379

slave1

127.0.0.1

6379

slave2

127.0.0.1

6379

Sentinel1

127.0.0.1

26379

Sentinel2

127.0.0.1

26379

Sentinel3

127.0.0.1

26379


 docker compose
文件编写:

    https://gitee.com/gz-tony/viemall-dubbo/tree/master/viemall-docekr/compose/redis-sentinel

docker compose 服务启动;


  docker-compose up –d


检查一下docker 集群容器:

   image.png 

验证一下是否成功:

 

查看 redis-sentinel_sentinel_1 容器日记:

  image.png

查看 redis-master 的主从关系:

docker exec -it redis-master  redis-cli info Replication

  image.png

查看 redis-sentinel_redis-slave_1  的主从关系:

docker exec -it redis-sentinel_redis-slave_1  redis-cli info Replication

image.png

停止 redis-master 容器,看是否会自动切换master :

# docker stop redis-master

#

发现Redi-master主节点已经不能连接,redis-sentinel_redis-slave_1 成了主节点!

说明 sentinel 部署成功;

启动sentinel 多实例:

使用docker-compose scale指定某一个服务启动的容器的个数;

启动3个sentinel服务:

docker-compose scale sentinel=3

 image.png 

启动两次从节点:

docker-compose scale redis-slave=2

 image.png 

Docker ps –a 查看:

 image.png 

最终保持了有3个Sentinel节点,1个主节点,2个从节点组成一个Redis Sentinel;

验证测试如上面操作一样;

 

注意:在生产环境下建议sentinel节点的数量能在3个以上,并且最好不要在同一台机器上(使用同一网卡)。 所以一般正式环境上的操作,是采用docker 单个服务运行;

 

 

sentinel.conf配置文件介绍:

 

port 26379 #当前Sentinel服务运行的端口

 

# Sentinel服务运行时使用的临时文件夹

dir /tmp

 

#指定别名  主节点地址  端口  哨兵个数(有几个哨兵监控到主节点宕机执行转移)

sentinel monitor mymaster redis-master 6379 $SENTINEL_QUORUM

 

# Sentinel去监视一个名为mymaster的主redis实例,这个主实例的IP地址为本机地址redis-master 容器,端口号为6379,而将这个主实例判断为失效至少需要2个 Sentinel进程的同意,只要同意Sentinel的数量不达标,自动failover就不会执行

 

#如果哨兵3s内没有收到主节点的心跳,哨兵就认为主节点宕机了,默认是30秒 

sentinel down-after-milliseconds mymaster $SENTINEL_DOWN_AFTER

 

#选举出新的主节点之后,可以同时连接从节点的个数

#指定了在执行故障转移时,最多可以有多少个从Redis实例在同步新的主实例,在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长

sentinel parallel-syncs mymaster 1

 

#如果在该时间(ms)内未能完成failover操作,则认为该failover失败

sentinel failover-timeout mymaster $SENTINEL_FAILOVER

 

#配置连接redis主节点密码 

#sentinel auth-pass mymaster 123456 

# sentinel notification-script <master-name> <script-path>:指定sentinel检测到该监控的redis实例指向的实例异常时,调用的报警脚本。该配置项可选,但是很常用

 

 

 

常用的redis HA 方案:

 

Redis 一般以主/从方式部署(这里讨论的应用从实例主要用于备份,主实例提供读写)该方式要实现 HA 主要有如下几种方案: 


  1)keepalived:通过 keepalived 的虚拟 IP,提供主从的统一访问,在主出现问题时, 通过 keepalived 运行脚本将从提升为主,待主恢复后先同步后自动变为主,该方案的好处是主从切换后,应用程序不需要知道(因为访问的虚拟 IP 不变),坏处是引入 keepalived 增加部署复杂性,在有些情况下会导致数据丢失; 


  2) zookeeper: 通过 zookeeper 来监控主从实例, 维护最新有效的 IP, 应用通过 zookeeper取得 IP,对 Redis 进行访问,该方案需要编写大量的监控代码; 


  3)sentinel:通过 Sentinel 监控主从实例,自动进行故障恢复,该方案有个缺陷:因为主从实例地址(IP&PORT)是不同的, 当故障发生进行主从切换后, 应用程序无法知道新地址,故 在 Jedis2.2.2 中 新 增 了 对 Sentinel 的 支 持 , 应 用 通 过redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis实例会及时更新到新的主实例地址。 

 

 

Java 客户端操作:

public class RedisSentinelTest {

 

      public static void main(String[] args) {

 

           Set<String> sentinels = new HashSet<String>();

        sentinels.add("127.0.0.1:26379");

        sentinels.add("127.0.0.1:26380");

        sentinels.add("127.0.0.1:26381");

 

           String clusterName = "redis-master";

           String password = "";

 

           JedisSentinelPool redisSentinelJedisPool = new JedisSentinelPool(clusterName, sentinels, password);

           Jedis jedis = null;

           try {

                 jedis = redisSentinelJedisPool.getResource();

                 jedis.set("key", "value");

           } catch (Exception e) {

                 e.printStackTrace();

           } finally {

                 redisSentinelJedisPool.close();

           }

          

      }

 

}

 

 

 

参考资料:

 https://www.cnblogs.com/LiZhiW/p/4851631.html