iyihua

  • 首页

  • 标签

  • 分类

  • 归档

shell-从svn更新代码maven打包后部署的一个简单脚本

发表于 2017-03-11 | 更新于 2019-05-22 | 分类于 deploy

shell是个好东西,服务器上面的操作做多了,就需要想想办法把手工做的事情让脚本帮我们处理。以下是一个针对spring boot项目从svn更新出最新代码,然后maven打包,最后启动发布的一个脚本例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
#build icms app
path_src=/home/src/trunk/icms
path_target=${path_src}/target
path_app=/home/app
path_log=/data/logs/icms
file_app=icms-1.4.1.RELEASE.jar
url_app=localhost:8091

cd /home/src/trunk/icms
svn update
mvn clean package -P pro -Dmaven.test.skip=true

if [ -f ${path_target}/${file_app} ]; then
echo "build success, now begin to deploy..."
curl -X POST ${url_app}/shutdown
yes | cp -rf ${path_target}/${file_app} ${path_app}/
chmod +x ${path_app}/${file_app}
nohup java -jar ${path_app}/${file_app} < /dev/null > ${path_log}/icms.log 2>&1 &
else
echo "build failed!"
fi

echo "build process finish."

脚本中的“curl -X POST ${url_app}/shutdown”这里是因为使用了spring boot的优雅关闭应用,需要在应用添加maven依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然后在配置文件中添加:

1
2
endpoints.shutdown.enabled=true
endpoints.shutdown.sensitive=false

git如何使用-记一些常用的git使用方法

发表于 2017-03-11 | 更新于 2019-05-22 | 分类于 git
  1. git如何提交修改到远程仓库?

    • $ git commit –m “desc..” //对你更新或修改了哪些内容做一个描述
    • $ git remote add origin https://github.com/YihuaWanglv/post.git
      //如果你是第一次提交项目,这一句非常重要,这是你本地的当前的项目与远程的哪个仓库建立连接。
    • $ git push -u origin master //将本地的项目提交到远程仓库中
  2. 如果你是第一次想把github上面的项目克隆到本地或者要克隆别人的项目到地。

    • $ git clone git@github.com:defnngj/hibernate-demo.git //在git下面切换到想存放此项目的文件目录下,运行这条命令就可以将项目克隆下来。
  3. 假如本地已经存在了这个项目,而仓库中又有一新的更新,如何把更的合并到本地的项目中?

    • $ git fetch origin //取得远程更新,这里可以看做是准备要取了
    • $ git merge origin/master //把更新的内容合并到本地分支/master
  4. 添加和提交

    • git add *
    • git commit -m “代码提交信息”
    • git push origin master
    • 输入用户名密码
    • 如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:
    • git remote add origin
  5. 重装系统后,git项目如何恢复?
    • 本地先进入原项目路径,git clone [path of project], 连接上
    • 然后告诉git全局配置你是谁,输入你的邮箱和名称
    • git config –global user.email “you@example.com“
    • git config –global user.name “Your Name”
    • 然后该干嘛干嘛

使用Nginx作为简单的图片服务器

发表于 2017-03-10 | 更新于 2019-05-22 | 分类于 deploy

说明:

  • 为什么要用Nginx代理静态图片?

图片服务器是我们经常要用到的,在开始的时候,当还没用上阿里云oss,并且觉得FastDFS略微重量级的时候,就可以使用Nginx作为简单的图片服务器。

一下就是Nginx的conf配置文件例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
worker_processes  1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;

server {
listen 80;
server_name localhost;
location /images {
root /data/icms;
add_header 'Access-Control-Allow-Origin' *;
index index.html index.htm;
charset utf-8;
}
location / {
root html;
index index.html index.htm;
}
}
}

  • 所有http://domain/image/xxx.png 的图片都会请求到服务器/data/icms/images内对应的图片。

使用java收集github-trending页面中感兴趣的语言的新动态并归档到自己的repository

发表于 2017-03-10 | 更新于 2019-05-22 | 分类于 project

java-github-trending

what is this?

github-trending 展示了每天趋势较好的一些github项目。
java-github-trending项目的目的就是每天定时拉取github-trending页面中感兴趣的语言的流行项目,并以日期为分组归档到markdown文件里面,最后提交到github的repository。

  • 我的项目github地址:github-trending

how to use?

  • @Before
    首先要有一个github账号,然后要准备一个运行应用的环境.

在你的运行环境中生成一个ssh key, 然后保存到github的key列表中.

git clone project

1
git clone git@github.com:YihuaWanglv/github-trending.git

maven package

1
2
cd github-trending
mvn clean package

move github-trending.jar to project root path

将jar和sh脚本设置为可执行,然后nohu run github-trending.jar

1
2
3
chmod +x rungit.sh
chmon +x github-trending.jar
nohup java -jar github-trending.jar < /dev/null > /data/logs/github-trending.log 2>&1 &

how it works?

using spring @Scheduled as daily task.
using Jsoup lib to get and parse page content
use java.io lib to create markdown file and append content to md file.
use java Runtime class to run a shell to commit and push to github.

tips: 这个功能本身使用简单的java application,再配合linux的cron定时执行shell,即可更简单的做到,但由于一些原因,我使用spring boot来构建这个程序。

动态报表模块设计

发表于 2016-12-18 | 更新于 2019-05-22 | 分类于 design

动态报表模块设计

1.需求概述

  • 实现根据dba提供的sql语句,动态生成业务部门需要的报表展示页面

2.页面原型

1)报表展示和预览页面

  • 菜单栏,每个app代表一个应用,每个report代表一个具体报表
  • “添加报表”菜单,进入添加报表页面
  • 查询框,通过’ireports_report_setting’表的’query_column’动态生成
  • 报表table,通过’ireports_report_setting’表的’table_column_mapping’动态生成

2)报表添加与设置页面

  • 查询类型有:
    1
    2
    3
    4
    5
    6
    1, = (等于)
    2, > (大于)
    3, < (小于)
    4, >= (大于等于)
    5, <= (小于等于)
    6, time (时间区间)

3.模型设计

1)数据库模型图

2)模型表说明

  • ireports_app(报表所属应用或模块)

    1
    2
    3
    4
    5
    6
    CREATE TABLE `ireports_app` (
    `aid` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(50) NOT NULL COMMENT '应用名称',
    `status` tinyint(4) DEFAULT '0' COMMENT '状态',
    PRIMARY KEY (`aid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报表所属应用或模块';
  • ireports_report(报表记录表)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CREATE TABLE `ireports_report` (
    `rid` int(11) NOT NULL AUTO_INCREMENT COMMENT '报表id',
    `rsid` int(11) DEFAULT '0' COMMENT '报表详细设置id',
    `report` varchar(50) NOT NULL COMMENT '报表名称',
    `sql` text NOT NULL COMMENT '报表sql',
    `type` tinyint(4) DEFAULT '0' COMMENT '报表类型',
    `status` tinyint(4) DEFAULT '0' COMMENT '状态',
    PRIMARY KEY (`rid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报表记录表';
  • ireports_report_setting(报表详细设置表)

    1
    2
    3
    4
    5
    6
    7
    CREATE TABLE `ireports_report_setting` (
    `rsid` int(11) NOT NULL AUTO_INCREMENT COMMENT '报表设置id',
    `is_page` tinyint(1) DEFAULT '1' COMMENT '是否分页',
    `table_column_mapping` longtext COMMENT '报表表头字段映射',
    `query_column` text COMMENT '报表查询字段配置',
    PRIMARY KEY (`rsid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='报表详细设置表';
  • ireports_query_type(查询类型表)

    1
    2
    3
    4
    5
    CREATE TABLE `ireports_query_type` (
    `qtid` int(11) NOT NULL AUTO_INCREMENT COMMENT '查询类型id',
    `type` varchar(20) NOT NULL COMMENT '查询类型',
    PRIMARY KEY (`qtid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='查询类型表';

4.技术实现

1)报表数据来源与连接:2个方案

  • 只连接业务员库,每次当添加的报表需要数据时,从基础数据库中同步到业务员库
  • 业务员系统添加对基础数据库的连接,添加一个内测or公测的基础数据库

2)数据连接层

  • 使用mybatis

3)动态报表展示

  • 使用Freemarker + Jquery

后台读取报表配置后,使用Freemarker模板生成页面框架与页面元素。

页面载入后,使用Jquery异步请求报表数据,并展现。

ELK+Kafka企业日志收集平台搭建总结

发表于 2016-09-09 | 更新于 2019-05-22 | 分类于 architecture

3.ELK+Kafka 企业日志收集平台搭建总结

平台架构:

  • 1台生产应用服务器:192.168.1.119
  • 3台zookeeper+kafka集群服务器:192.168.1.245, 192.168.1.246, 192.168.1.247
  • 2台es+kibana集群服务器:192.168.1.162, 192.168.1.163
  • 1台nginx服务器反向代理到kibana集群:192.168.1.244

软件选用

1
2
3
4
5
6
elasticsearch-1.7.3.tar.gz 
Logstash-2.3.*
kibana-4.1.2-linux-x64.tar.gz
以上软件都可以从官网下载:https://www.elastic.co/downloads
java-1.8.65
nginx采用yum安装

平台安装配置

####部署步骤:
1.ES集群安装配置;
2.Logstash客户端配置(直接写入数据到ES集群,写入系统messages日志);
3.Kafka(zookeeper)集群配置;(Logstash写入数据到Kafka消息系统);
4.Kibana部署;
5.Nginx负载均衡Kibana请求;
6.案例:nginx日志收集以及MySQL慢日志收集;
7.Kibana报表基本使用;

1.ES集群安装配置;

  • 需要先安装java1.8
  • 2.获取es软件包

    1
    2
    3
    wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.3.tar.gz
    tar -xf elasticsearch-1.7.3.tar.gz -C /usr/local
    ln -sv /usr/local/elasticsearch-1.7.3 /usr/local/elasticsearch
  • 3.修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@es1 ~]# vim /usr/local/elasticsearch/config/elasticsearch.yml 
32 cluster.name: es-cluster #组播的名称地址
40 node.name: "es-node1 " #节点名称,不能和其他节点重复
47 node.master: true #节点能否被选举为master
51 node.data: true #节点是否存储数据
107 index.number_of_shards: 5 #索引分片的个数
111 index.number_of_replicas: 1 #分片的副本个数
145 path.conf: /usr/local/elasticsearch/config/ #配置文件的路径
149 path.data: /data/es/data #数据目录路径
159 path.work: /data/es/worker #工作目录路径
163 path.logs: /usr/local/elasticsearch/logs/ #日志文件路径
167 path.plugins: /data/es/plugins #插件路径
184 bootstrap.mlockall: true #内存不向swap交换
232 http.enabled: true #启用http
  • 4.创建相关目录

    1
    mkdir /data/es/{data,worker,plugins} -p
  • 5.获取es服务管理脚本

    1
    2
    3
    4
    5
    6
    ​[root@es1 ~]# git clone https://github.com/elastic/elasticsearch-servicewrapper.git
    [root@es1 ~]# mv elasticsearch-servicewrapper/service /usr/local/elasticsearch/bin/
    [root@es1 ~]# /usr/local/elasticsearch/bin/service/elasticsearch install
    Detected RHEL or Fedora:
    Installing the Elasticsearch daemon..
    [root@es1 ~]#

这时就会在/etc/init.d/目录下安装上es的管理脚本啦

  • 修改其配置:

    1
    2
    3
    [root@es1 ~]# 
    set.default.ES_HOME=/usr/local/elasticsearch #安装路径
    set.default.ES_HEAP_SIZE=1024
  • 6.启动es ,并检查其服务是否正常
    es启动方式是进入bin目录

    1
    /usr/local/elasticsearch/bin/

运行

1
./elasticsearch

启动

1
2
3
[root@es1 ~]# netstat -nlpt | grep -E "9200|"9300
tcp 0 0 0.0.0.0:9200 0.0.0.0:* LISTEN 1684/java
tcp 0 0 0.0.0.0:9300 0.0.0.0:* LISTEN 1684/java

访问http://192.168.2.18:9200/ 返回es节点信息,说明安装配置完成.

  • 7.复制同样的步骤和配置到es2,只需要修改node.name即可,其他都与es1相同配置
  • 8.安装es的管理插件
    es官方提供一个用于管理es的插件,可清晰直观看到es集群的状态,以及对集群的操作管理,安装方法如下:
    1
    [root@es1 local]# /usr/local/elasticsearch/bin/plugin -i mobz/elasticsearch-head

安装好之后,访问方式为: http://192.168.2.18:9200/_plugin/head

2.Logstash客户端安装配置

  • 安装前,需要先安装java
  • YUM方式安装Logstash

Download and install the public signing key:

1
rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch

Add the following in your /etc/yum.repos.d/ directory in a file with a .repo suffix, for example logstash.repo

1
2
3
4
5
6
[logstash-2.3]
name=Logstash repository for 2.3.x packages
baseurl=https://packages.elastic.co/logstash/2.3/centos
gpgcheck=1
gpgkey=https://packages.elastic.co/GPG-KEY-elasticsearch
enabled=1

And your repository is ready for use. You can install it with:

1
yum install logstash

此时logstash会安装在目录:/opt/logstash/
进入/opt/logstash/bin/目录
vim logstash.conf
即可对这个logstash客户端进行设置,可以设置输入和输出
输入定义信息来源于何处,输出定义消息发送到哪里

  • logstash一些操作:
    检查配置是否正确
    /opt/logstash/bin/logstash -f logstash.conf –configtest –verbose
    启动logstash
    /opt/logstash/bin/logstash -f logstash.conf

  • 3.Logstash 向es集群写数据
    编写一个logstash配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@webserver1 etc]# vi logstash.conf 
    input { #数据的输入从标准输入
    stdin {}
    }

    output { #数据的输出我们指向了es集群
    elasticsearch {
    hosts => ["192.168.1.162:9200","192.168.1.163:9200"]   #es主机的ip及端口
    }
    }
  • 命令/opt/logstash/bin/logstash -f logstash.conf 启动后,如果有信息产生,就会向es集群写入数据,可以在es页面中看到

  • 例子:将web app的log日志写入es中,使用如下脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    input {
    file {
    path => "/usr/local/log.log"
    start_position => "beginning"
    }
    }

    output {
    elasticsearch {
    hosts => ["192.168.1.162:9200","192.168.1.163:9200"]
    index => "web-app-%{+YYYY-MM}"
    }
    }

3.Kafka(zookeeper)集群配置;(Logstash写入数据到Kafka消息系统);

kafka的软件包中自带zookeeper,并且是解压即可使用。可以官网下载上传服务器,也可直接服务器下载

  • 1.获取软件包.官网:http://kafka.apache.org

    1
    2
    3
    4
    [root@kafka1 ~]# wget http://mirror.rise.ph/apache/kafka/0.8.2.1/kafka_2.11-0.8.2.1.tgz
    [root@kafka1 ~]# tar -xf kafka_2.11-0.8.2.1.tgz -C /usr/local/
    [root@kafka1 ~]# cd /usr/local/
    [root@kafka1 local]# ln -sv kafka_2.11-0.8.2.1 kafka
  • 2.配置zookeeper集群,修改配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@kafka1 ~]# vim /usr/local/kafka/config/zookeeper.propertie
    dataDir=/data/zookeeper
    clienrtPort=2181
    tickTime=2000
    initLimit=20
    syncLimit=10
    server.2=192.168.1.245:2888:3888
    server.3=192.168.1.246:2888:3888
    server.4=192.168.1.247:2888:3888
  • 3.创建zookeeper所需要的目录

    1
    [root@kafka1 ~]# mkdir /data/zookeeper
  • 4.在/data/zookeeper目录下创建myid文件,里面的内容为数字,用于标识主机,如果这个文件没有的话,zookeeper是没法启动的哦

    1
    [root@kafka1 ~]# echo 2 > /data/zookeeper/myid

以上就是zookeeper集群的配置,下面等我配置好kafka之后直接复制到其他两个节点即可

  • 5.kafka配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@kafka1 ~]# vim /usr/local/kafka/config/server.properties 
    broker.id=2      # 唯一,填数字,本文中分别为2/3/4
    prot=9092        # 这个broker监听的端口 
    host.name=192.168.2.22  # 唯一,填服务器IP
    log.dir=/data/kafka-logs # 该目录可以不用提前创建,在启动时自己会创建
    zookeeper.connect=192.168.2.22:2181,192.168.2.23:2181,192.168.2.24:2181  #这个就是zookeeper的ip及端口
    num.partitions=16 # 需要配置较大 分片影响读写速度
    log.dirs=/data/kafka-logs # 数据目录也要单独配置磁盘较大的地方
    log.retention.hours=168 # 时间按需求保留过期时间 避免磁盘满
  • 6.将kafka(zookeeper)的程序目录全部拷贝至其他两个节点

  • 7.修改两个借点的配置,注意这里除了以下两点不同外,都是相同的配置

    1
    2
    3
    4
    5
    6
    (1)zookeeper的配置
    mkdir /data/zookeeper
    echo "x" > /data/zookeeper/myid
    (2)kafka的配置
    broker.id=2
    host.name=192.168.2.22
  • 8.修改完毕配置之后我们就可以启动了,这里先要启动zookeeper集群,才能启动kafka

    1
    2
    [root@kafka1 ~]# /usr/local/kafka/bin/zookeeper-server-start.sh /usr/local/kafka/config/zookeeper.properties &   #zookeeper启动命令
    [root@kafka1 ~]# /usr/local/kafka/bin/zookeeper-server-stop.sh #zookeeper停止的命令
  • 9.zookeeper服务检查

    1
    [root@kafka1~]#  netstat -nlpt | grep -E "2181|2888|3888"

ok. 这时候zookeeper集群已经启动起来了,下面启动kafka,也是依次按照顺序启动

1
2
[root@kafka1 ~]# nohup /usr/local/kafka/bin/kafka-server-start.sh /usr/local/kafka/config/server.properties &   #kafka启动的命令
[root@kafka1 ~]# /usr/local/kafka/bin/kafka-server-stop.sh #kafka停止的命令

注意,跟zookeeper服务一样,如果kafka有问题 nohup的日志文件会非常大,把磁盘占满,这个kafka服务同样可以通过自己些服务脚本来管理服务的启动与关闭。

  • 10,下面我们将webs app上面的logstash的输出改到kafka上面,将数据写入到kafka中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    input {             #这里的输入还是定义的是从日志文件输入
    file {
    type => "web-app"
    path => "/usr/local/log.log"
    start_position => "beginning"
    }
    }

    output {
    #stdout { codec => rubydebug }
    kafka {
    bootstrap_servers => "192.168.1.245:9092,192.168.1.246:9092,192.168.1.247:9092"
    topic_id => "web-app-message"
    compression_type => "snappy"
    }
    }
  • 然后再每台kafka上安装logstash,把kafka的消息发送到es
    使用logstash脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    input {
    kafka {
    zk_connect => "192.168.1.245:2181,192.168.1.246:2181,192.168.1.247:2181"
    topic_id => "web-app-message"
    codec => plain
    reset_beginning => false
    consumer_threads => 5
    decorate_events => true
    }
    }

    output {
    elasticsearch {
    hosts => ["192.168.1.162:9200","192.168.1.163:9200"]
    index => "test-web-app-message-%{+YYYY-MM}"
    }
    }

4.Kibana部署;

我们在两台es上面搭建两套kibana

  • 1.获取kibana软件包

    1
    2
    [root@es1 ~]# wget https://download.elastic.co/kibana/kibana/kibana-4.1.2-linux-x64.tar.gz
    [root@es1 ~]# tar -xf kibana-4.2.0-linux-x64.tar.gz -C /usr/local/
  • 2.修改配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@es1 ~]# cd /usr/local/
    [root@es1 local]# ln -sv kibana-4.1.2-linux-x64 kibana
    `kibana' -> `kibana-4.2.0-linux-x64'
    [root@es1 local]# cd kibana

    [root@es1 kibana]# vim config/kibana.yml
    server.port: 5601 #默认端口可以修改的
    server.host: "0.0.0.0" #kibana监听的ip
    elasticsearch.url: "http://localhost:9200" #由于es在本地主机上面,所以这个选项打开注释即可
  • kibana安装后,直接进入kibana的安装目录
    /user/local/kibana/bin
    运行
    ./kibana
    启动

  • 5.服务检查

    1
    2
    [root@es1 config]# ss -tunl | grep "5601"
    tcp LISTEN 0 511 *:5601 *:*

此时访问es1主机的5601端口,即可看见kibana的页面:
http://192.168.1.163:5601

  • 6.es2上的kibana与es1一样

5.Nginx负载均衡Kibana请求;

  • 1.在nginx-proxy上面yum安装nginx

    1
    yum install -y nignx
  • 2.编写配置文件es.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [root@saltstack-node1 conf.d]# pwd 
    /etc/nginx/conf.d
    [root@saltstack-node1 conf.d]# cat es.conf
    upstream es {
    server 192.168.2.18:5601 max_fails=3 fail_timeout=30s;
    server 192.168.2.19:5601 max_fails=3 fail_timeout=30s;
    }

    server {
    listen 80;
    server_name localhost;

    location / {
    proxy_pass http://es/;
    index index.html index.htm;
    #auth
    auth_basic "ELK Private";
    auth_basic_user_file /etc/nginx/.htpasswd;
    }

    }

3.创建认证

1
2
3
4
5
6
7
8
[root@saltstack-node1 conf.d]# htpasswd -cm /etc/nginx/.htpasswd elk
New password:
Re-type new password:
Adding password for user elk-user
[root@saltstack-node1 conf.d]# /etc/init.d/nginx restart
Stopping nginx: [ OK ]
Starting nginx: [ OK ]
[root@saltstack-node1 conf.d]#

  • 4.直接输入认证用户及密码就可访问啦http://192.168.1.244/

6.案例:nginx日志收集以及MySQL慢日志收集;

  • 先在web app服务器上安装nginx和mysql

  • 1.为了方便nginx日志的统计搜索,这里设置nginx访问日志格式为json

(1)修改nginx主配置文件

说明:如果想实现日志的报表展示,最好将业务日志直接以json格式输出,这样可以极大减轻cpu负载,也省得运维需要写负载的filter过滤正则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@webserver1 nginx]# vim nginx.conf
log_format json '{"@timestamp":"$time_iso8601",'
'"@version":"1",'
'"client":"$remote_addr",'
'"url":"$uri",'
'"status":"$status",'
'"domain":"$host",'
'"host":"$server_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,'
'"referer": "$http_referer",'
'"ua": "$http_user_agent"'
'}';
access_log /var/log/access_json.log json;

(2)收集nginx日志和MySQL日志到消息队列中;这个文件我们是定义在客户端,即生产服务器上面的Logstash文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
input {
file {
type => "web-app"
path => "/usr/local/log.log"
start_position => "beginning"
}
file {
type => "nginx-access"
path => "/var/log/nginx/access.log"
start_position => "beginning"
codec => "json"
}
file {
type => "slow-mysql"
path => "/var/run/mysqld/mysqld-slow.log"
start_position => "beginning"
codec => multiline {
pattern => "^# User@Host"
negate => true
what => "previous"
}
}
}

output {
if [type] == "nginx-access" {
kafka {
bootstrap_servers => "192.168.1.245:9092,192.168.1.246:9092,192.168.1.247:9092"
topic_id => "nginx-access"
compression_type => "snappy"
}
}
if [type] == "slow-mysql" {
kafka {
bootstrap_servers => "192.168.1.245:9092,192.168.1.246:9092,192.168.1.247:9092"
topic_id => "slow-mysql"
compression_type => "snappy"
}
}
if [type] == "web-app" {
kafka {
bootstrap_servers => "192.168.1.245:9092,192.168.1.246:9092,192.168.1.247:9092"
topic_id => "web-app-message"
compression_type => "snappy"
}
}
}

/opt/logstash/bin/logstash -f logstash.conf –configtest –verbose

/opt/logstash/bin/logstash -f logstash.conf

(3)Logstash 从kafka集群中读取日志存储到es中,这里的定义logstash文件是在三台kafka服务器上面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
input {
kafka {
zk_connect => "192.168.1.245:2181,192.168.1.246:2181,192.168.1.247:2181"
topic_id => "web-app-message"
codec => plain
reset_beginning => false
consumer_threads => 5
decorate_events => true
}
kafka {
zk_connect => "192.168.1.245:2181,192.168.1.246:2181,192.168.1.247:2181"
type => "nginx-access"
topic_id => "nginx-access"
codec => plain
reset_beginning => false
consumer_threads => 5
decorate_events => true
}
kafka {
zk_connect => "192.168.1.245:2181,192.168.1.246:2181,192.168.1.247:2181"
type => "slow-mysql"
topic_id => "slow-mysql"
codec => plain
reset_beginning => false
consumer_threads => 5
decorate_events => true
}
}

output {
if [type] == "nginx-access" {
elasticsearch {
hosts => ["192.168.1.162:9200","192.168.1.163:9200"]
index => "nginx-access-%{+YYYY-MM}"
}
}
if [type] == "slow-mysql" {
elasticsearch {
hosts => ["192.168.1.162:9200","192.168.1.163:9200"]
index => "slow-mysql-%{+YYYY-MM}"
}
}
if [type] == "web-app-message" {
elasticsearch {
hosts => ["192.168.1.162:9200","192.168.1.163:9200"]
index => "test-web-app-message-%{+YYYY-MM}"
}
}
}

(4)创建nginx-access 日志索引
(5)创建MySQL慢日志索引

这两个都是在kibana的页面上创建配置

7.Kibana报表基本使用;

[dev][collect][2016-08]collect-of-dev

发表于 2016-09-06 | 更新于 2019-05-22 | 分类于 collect

2016-08

2016-08-26

  • RabbitMQ Configuration
    https://www.rabbitmq.com/configure.html

  • RabbitMQ用户角色及权限控制
    http://blog.csdn.net/zyz511919766/article/details/42292655

  • RabbitMQ Installing on Windows
    https://www.rabbitmq.com/install-windows.html

  • RabbitMQ Installing on RPM-based Linux (CentOS, Fedora, OpenSuse, RedHat)
    https://www.rabbitmq.com/install-rpm.html

  • CentOS6.5安装RabbitMQ
    http://www.jianshu.com/p/0d3bf6402e15

2016-08-25

  • ELK下载
    https://www.elastic.co/downloads

  • ELK+Kafka 企业日志收集平台(一)
    http://blog.sctux.com/?p=445

  • ELK+Kafka 企业日志收集平台(二)
    http://blog.sctux.com/?p=451

  • https://www.quora.com/What-are-some-other-great-free-web-tools-like-Trello

2016-08-22

  • 微服务架构下的开发部署实践(1)
    https://zhuanlan.zhihu.com/p/21563604?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

  • 领域驱动设计和实践
    http://www.infoq.com/cn/articles/cjq-ddd

  • 教你成为全栈工程师(Full Stack Developer) 四十五-一文读懂hadoop、hbase、hive、spark分布式系统架构
    http://www.shareditor.com/blogshow/?blogId=96&hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

  • 聊一聊排序算法
    http://mp.weixin.qq.com/s?__biz=MzAxMjA5ODQwMQ==&mid=2455058728&idx=1&sn=6b0e55cc9a3c34775013f39ab08a6ac7#rd
    https://github.com/barretlee/algorithms

  • 最简MVP框架
    http://www.jianshu.com/p/e0feb16105f9?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
    https://github.com/wolearn/MvpFrame

  • 可用性高达五个9!支付系统高可用架构设计实战
    http://dbaplus.cn/news-21-591-1.html

  • Gson源码分析以其所包含注解的用法
    http://lliuguangbo.github.io/2016/08/07/Gson-Source-Code-Analyze-One/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

  • React Native开源项目-嘎嘎商城客户端(持续更新中)
    http://www.lcode.org/react-native-source-gagamall/
    https://github.com/jiangqqlmj/GaGaMall

  • ActiveMQ高可用集群方案
    http://wosyingjun.iteye.com/blog/2314683

  • gitbook Zookeeper:分布式进程协同
    https://www.gitbook.com/book/mymonkey110/zookeeper-distributed-process-coordination/details

2016-08-16

  • 全面分析 Spring 的编程式事务管理及声明式事务管理
    https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/

2016-08-16

  • Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos
    http://fabiomaffioletti.me/blog/2014/04/15/distributed-transactions-multiple-databases-spring-boot-spring-data-jpa-atomikos/
    https://github.com/fabiomaffioletti/mul-at

  • JTA 深度历险 - 原理与实现
    http://www.ibm.com/developerworks/cn/java/j-lo-jta/

  • Java事务之八——分布式事务(Spring+JTA+Atomikos+Hibernate+JMS)
    http://www.cnblogs.com/davenkin/archive/2013/03/19/java-tranaction-8.html

  • 如何实现XA式、非XA式Spring分布式事务
    http://www.importnew.com/15812.html

  • Java事务设计策略 微型书
    http://www.infoq.com/cn/minibooks/JTDS#idp_register

  • 【转】JDBC事务和JTA (XA)事务
    http://kazge.com/archives/962.html

2016-08-15

  • 美团点评技术团队
    http://tech.meituan.com/

  • 消息队列设计精要
    http://tech.meituan.com/mq-design.html

  • 阿里中间件团队博客
    http://jm.taobao.org/

  • Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos
    http://fabiomaffioletti.me/blog/2014/04/15/distributed-transactions-multiple-databases-spring-boot-spring-data-jpa-atomikos/
    https://github.com/fabiomaffioletti/mul-at

  • GitHub 中国区前 100 名到底是什么样的人?
    http://mt.sohu.com/20160407/n443539407.shtml?qq-pf-to=pcqq.discussion

  • Spring分布式事务配置(atomikos)
    http://sadwxqezc.github.io/HuangHuanBlog/framework/2016/05/29/Spring%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E9%85%8D%E7%BD%AE.html?utm_source=tuicool&utm_medium=referral

  • 基于spring boot项目的多数据源配置与分布式事务处理总结
    http://hungryant.github.io/java/2015/11/26/java-spring-boot-jta.html

2016-08-13

爬虫专题

  • WebMagic
    http://webmagic.io/docs/zh/
    https://github.com/YihuaWanglv/webmagic
  • Maven 那点事儿
    http://my.oschina.net/huangyong/blog/194583

2016-08-12

  • Base: An Acid Alternative
    http://queue.acm.org/detail.cfm?id=1394128

  • 分布式事务演进
    http://yongpoliu.com/distributed-tx-evolution/

  • 系统幂等以及常用实现方式
    http://yongpoliu.com/idempotent/

  • 实现maven依赖的全局排除
    http://maven.apache.org/enforcer/maven-enforcer-plugin/
    http://yongpoliu.com/maven-global-exclude/

  • bi分析统计工具
    http://www.tableau.com/zh-cn/products/cloud-bi

  • 如何用消息系统避免分布式事务?
    http://www.cnblogs.com/LBSer/p/4715395.html

  • MySQL两阶段提交
    http://blog.csdn.net/jesseyoung/article/details/37970271

2016-08-11

  • Java自动化测试框架TestNG之入门篇
    http://www.jianshu.com/p/a74adec98eff

  • Arquillian Guides
    http://arquillian.org/guides/getting_started/?utm_source=cta

  • 自动化单元测试实践之路
    http://www.infoq.com/cn/articles/road-of-automated-unit-testing-practices

  • 8个超实用的Java测试工具和框架
    http://www.imooc.com/article/1154

  • 使用 Selenium 实现基于 Web 的自动化测试
    https://www.ibm.com/developerworks/cn/web/1209_caimin_seleniumweb/

  • 用 STAF+Selenium 实现并行的自动化测试框架
    https://www.ibm.com/developerworks/cn/java/j-lo-parallelautotest/

  • Java Fluent Restful API自动化测试框架
    http://www.cnblogs.com/jinsdu/p/4606113.html

  • HTTP API自动化测试从手工到平台的演变
    http://www.infoq.com/cn/articles/http-api-automated-test-from-manual-to-platform

  • 快速入门测试驱动开发(TDD)
    http://wwsun.github.io/posts/tdd.html

  • 使用 REST-Assured 测试 REST API 的进阶技巧和最佳实践
    https://www.ibm.com/developerworks/cn/java/j-lo-rest-assured2/

2016-08-10

  • Sharding-JDBC
    http://dangdangdotcom.github.io/sharding-jdbc/

  • [blog]庄周梦蝶
    http://fnil.net/

  • Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目
    https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md
    https://github.com/Qihoo360/Atlas

  • RDBMS分布式两阶段提交与Zookeeper的Paxos同步算法
    http://blog.csdn.net/victory0508/article/details/48003527

  • 分布式系统的事务处理
    http://coolshell.cn/articles/10910.html

  • 分布式事务 - 最终一致性(一)
    https://segmentfault.com/a/1190000005969526

  • 介绍下用消息队列实现分布式事务
    http://blog.chinaunix.net/uid-20047304-id-4515035.html

2016-08-03

  • 解放程序猿(媛)的双手—iOS UI自动化测试
    http://tmq.qq.com/2016/06/uitestingiosautomation/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

  • 5小时搞定谷歌原生自动化框架UiAutomator1.0
    http://tmq.qq.com/2016/06/androidautotestframwork-uiautomator/

  • 有赞延迟队列设计
    http://tech.youzan.com/queuing_delay/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

spring事务用法演进

发表于 2016-08-18 | 更新于 2019-05-22 | 分类于 java-spring

Spring事务用法演进

  • 内容

  • 事务用法演进

编程式事务管理

基于底层 API 的编程式事务管理

  • 配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl">
    <property name="bankDao" ref="bankDao"/>
    <property name="txManager" ref="transactionManager"/>
    <property name="txDefinition">
    <bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
    <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
    </bean>
    </property>
    </bean>
  • TransactionDefinition 类型的属性,它用于定义一个事务

  • PlatformTransactionManager 类型的属性,用于执行事务管理操作

  • 程序代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    private TransactionDefinition txDefinition;
    private PlatformTransactionManager txManager;
    ......
    public boolean transfer(Long fromId, Long toId, double amount) {
    TransactionStatus txStatus = txManager.getTransaction(txDefinition);
    boolean result = false;
    try {
    result = bankDao.transfer(fromId, toId, amount);
    txManager.commit(txStatus);
    } catch (Exception e) {
    result = false;
    txManager.rollback(txStatus);
    System.out.println("Transfer Error!");
    }
    return result;
    }
    }
  • 事务管理的代码散落在业务逻辑代码中,破坏了原有代码的条理性,并且每一个业务方法都包含了类似的启动事务、提交/回滚事务的样板代码。

基于TransactionTemplate的编程式事务管理

  • 配置文件

    1
    2
    3
    4
    5
    <bean id="bankService"
    class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
    <property name="bankDao" ref="bankDao"/>
    <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
  • 程序示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    private TransactionTemplate transactionTemplate;
    ......
    public boolean transfer(final Long fromId, final Long toId, final double amount) {
    return (Boolean) transactionTemplate.execute(new TransactionCallback(){
    public Object doInTransaction(TransactionStatus status) {
    Object result;
    try {
    result = bankDao.transfer(fromId, toId, amount);
    } catch (Exception e) {
    status.setRollbackOnly();
    result = false;
    System.out.println("Transfer Error!");
    }
    return result;
    }
    });
    }
    }
  • 在数据访问层非常常见的模板回调模式

  • 以匿名内部类的方式实现 TransactionCallback 接口,并在其 doInTransaction() 方法中书写业务逻辑代码

声明式事务管理

  • 不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过等价的基于标注的方式)
  • 声明式事务管理由Spring AOP实现

基于TransactionInterceptor的声明式事务管理

  • 示例配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <beans...>
    ......
    <bean id="transactionInterceptor"
    class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributes">
    <props>
    <prop key="transfer">PROPAGATION_REQUIRED</prop>
    </props>
    </property>
    </bean>

    <bean id="bankServiceTarget" class="footmark.spring.core.tx.declare.origin.BankServiceImpl">
    <property name="bankDao" ref="bankDao"/>
    </bean>

    <bean id="bankService"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="bankServiceTarget"/>
    <property name="interceptorNames">
    <list>
    <idref bean="transactionInterceptor"/>
    </list>
    </property>
    </bean>
    ......
    </beans>
  • TransactionInterceptor定义相关的事务规则,有两个主要的属性:transactionManager和transactionAttributes

  • transactionManager,用来指定一个事务管理器,并将具体事务相关的操作委托给它;
  • transactionAttributes,Properties 类型,主要用来定义事务规则,该属性的每一个键值对中,键指定的是方法名,方法名可以使用通配符,而值就表示相应方法的所应用的事务属性。
  • ProxyFactoryBean, 组装 target 和advice. 通过 ProxyFactoryBean 生成的代理类就是织入了事务管理逻辑后的目标类。

事务属性取值的书写规则:

1
传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常]
  • 传播行为是唯一必须设置的属性,其他都可以忽略,Spring为我们提供了合理的默认值
  • 传播行为的取值必须以“PROPAGATION_”开头,具体包括:PROPAGATION_MANDATORY、PROPAGATION_NESTED、PROPAGATION_NEVER、PROPAGATION_NOT_SUPPORTED、PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_SUPPORTS,共七种取值。
  • 隔离级别的取值必须以“ISOLATION_”开头,具体包括:ISOLATION_DEFAULT、ISOLATION_READ_COMMITTED、ISOLATION_READ_UNCOMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE,共五种取值。
  • 如果事务是只读的,那么我们可以指定只读属性,使用“readOnly”指定。否则我们不需要设置该属性。
  • 超时属性的取值必须以“TIMEOUT_”开头,后面跟一个int类型的值,表示超时时间,单位是秒。
  • 不影响提交的异常是指,即使事务中抛出了这些类型的异常,事务任然正常提交。必须在每一个异常的名字前面加上“+”。异常的名字可以是类名的一部分。比如“+RuntimeException”、“+tion”等等。
  • 导致回滚的异常是指,当事务中抛出这些类型的异常时,事务将回滚。必须在每一个异常的名字前面加上“-”。异常的名字可以是类名的全部或者部分,比如“-RuntimeException”、“-tion”等等。
  • 两个示例
    1
    2
    3
    <property name="*Service">
    PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,+AbcException,+DefException,-HijException
    </property>

针对所有方法名以 Service 结尾的方法,使用 PROPAGATION_REQUIRED 事务传播行为,事务的隔离级别是 ISOLATION_READ_COMMITTED,超时时间为20秒,当事务抛出 AbcException 或者 DefException 类型的异常,则仍然提交,当抛出 HijException 类型的异常时必须回滚事务。这里没有指定”readOnly”,表示事务不是只读的。

1
<property name="test">PROPAGATION_REQUIRED,readOnly</property>

针对所有方法名为 test 的方法,使用 PROPAGATION_REQUIRED 事务传播行为,并且该事务是只读的。

基于TransactionProxyFactoryBean的声明式事务管理

  • 示例配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <beans......>
    ......
    <bean id="bankServiceTarget"
    class="footmark.spring.core.tx.declare.classic.BankServiceImpl">
    <property name="bankDao" ref="bankDao"/>
    </bean>

    <bean id="bankService"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="target" ref="bankServiceTarget"/>
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributes">
    <props>
    <prop key="transfer">PROPAGATION_REQUIRED</prop>
    </props>
    </property>
    </bean>
    ......
    </beans>
  • 显式为每一个业务类配置一个TransactionProxyFactoryBean的做法将使得代码显得过于刻板

基于命名空间的声明式事务管理

  • 示例配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <beans......>
    ......

    <tx:advice id="bankAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    <tx:method name="transfer" propagation="REQUIRED"/>
    </tx:attributes>
    </tx:advice>

    <aop:config>
    <aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))"/>
    <aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
    </aop:config>
    ......
    </beans>
  • 如果默认的事务属性就能满足要求,那么代码简化为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <beans......>
    ......
    <tx:advice id="bankAdvice" transaction-manager="transactionManager">

    <aop:config>
    <aop:pointcut id="bankPointcut" expression="execution(**.transfer(..))"/>
    <aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
    </aop:config>
    ......
    </beans>
  • 使用切点表达式,就不需要针对每一个业务类创建一个代理对象.

基于注解@Transactional的声明式事务管理

  • @Transactional 可以作用于接口、接口方法、类以及类方法上
  • 当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

  • 示例配置:

    1
    2
    3
    4
    5
    6
    7
    <!-- 配置事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
    p:dataSource-ref="dataSource">
    </bean>

    <!-- enables scanning for @Transactional annotations -->
    <tx:annotation-driven transaction-manager="txManager" />
  • 代码示例:

    1
    2
    3
    4
    @Transactional(propagation = Propagation.REQUIRED)
    public boolean transfer(Long fromId, Long toId, double amount) {
    return bankDao.transfer(fromId, toId, amount);
    }
  • 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。

  • @Transactional 注解应该只被应用到 public 方法上. 在protected、private或者默认可见性的方法上使用@Transactional 注解,将被忽略,也不会抛出任何异常。

事务属性

Required(需要)

  • 若事务上下文已存在,则使用,如果不存在,则为此方法开启一个新事务

Mandatory(强制必须)

  • 强制事务上下文必须存在,若不存在,则抛出TransactionRequiredException异常

RequiresNew(需要新的)

  • 总是开启新事务,前一个事务若存在则会被挂起
  • 此属性在此场景是很有用:一个事务如果需要与其外围包裹事务相独立,不受其执行结果的影响,自行完成提交(比如记录日志)

Supports(支持)

  • 告知容器,对象方法并不需要一个事务上下文,但当调用到这个方法而事务上下文恰巧存在时,则该方法会使用它
  • 可用于查询的方法当中,如果此查询是在一个正在进行的事务中完成的,对目标方法应用Supports属性会让容器使用当前事务上下文,参考数据库操作记录,从而将事务中作出的各种修改液包括到查询结果中

NotSupported(不支持)

  • 告知容器此方法不使用事务
  • 若一个事务已存在,容器会将事务暂停直至此方法结束
  • 此属性在方法逻辑中有排斥事务上下文代码存在时很有用,可以暂时屏蔽一些不需要或不能用事务的逻辑

Never(不用)

  • 告知容器不允许有事务上下文存在。若调用方法前事务存在,则抛出异常

PROPAGATION_NESTED

  • 告知spring进行事务嵌套,并采用Required属性

事务传播级别

  • 这些事务隔离级别设置需要依赖于底层数据库。底层数据库支持,这些设置才会生效

TransactionReadUncommitted

  • 允许事务读取其他事务在提交到数据库之前产生的未提交更改。

TransactionReadCommitted

  • 允许多个事务访问同一份数据,但将未提交的数据对其他事务隐藏,直至数据提交

TransactionRepeatableRead

  • 保持了事务彼此隔绝。
  • 保证一旦在某一事务中服务了数据库的一个值集,在后续的每次查询操作中都读到同样的值(除非此事务拿到这些数据的读写锁,并自行更改了数据)
  • 在此级别下,一个事务如果要更改数据,而这一数据被其他事务读取时,此事务需要等待占用数据事务提交的操作(或直接返回失败)

TransactionSerializable

  • java支持的最高的事务隔离级别
  • 交错发生的事务被“堆迭”起来,以致同一时间点仅仅有一个事务具备访问目标数据的权力
  • 性能会受到很大影响,而数据一致性将会极大提高

分布式事务

JTA和JTS

jta:java transaction api

  • 开发人员用于事务管理的接口
  • UserTransaction接口

    1
    2
    3
    4
    begin();
    commit();
    rollback();
    getStatus();
  • TransactionManager接口

    1
    2
    suspend();
    resume();

jts:java transaction service

  • 开源或商用的实现了jta的底层事务服务

要进行事务管理,我们需要两个东西:事务管理器和资源管理器

  • 资源管理器(Resource Manager),对于数据库,就是数据源
  • 事务管理器(Transaction Manager)
    控制JTA事务,管理事务生命周期,并协调资源
    在JTA中,事务管理器抽象为TransactionManager,并通过底层事务服务(JTS)实现
    负责控制和管理实际资源(数据库或JMS队列)

分布式事务/XA事务

  • 分布式事务和单机事务的区别就是,单机事务是事务管理器管理一个资源,而分布式事务则是事务管理器管理多个数据资源.

XA环境

在同一个处理单元中,需要协调多个数据资源完成逻辑,并保证ACID准备,则需要XA事务保证

XA接口

  • XA支持两阶段提交协议

实例:

  • 使用spring boot + jta + atomikos实现分布式事务管理的代码例子
  • 资金在库(atomikos_one),红包在库(atomikos_two). 资金账号1转10元到资金账号2;红包账号2转10元到红包账号1

表数据

  • capital_account

  • red_packet_account

程序代码

  • 配置2个数据源
    1
    2
    3
    4
    5
    6
    7
    order.datasource.url=jdbc:mysql://localhost:3306/atomikos_two
    order.datasource.username=root
    order.datasource.password=root

    customer.datasource.url=jdbc:mysql://localhost:3306/atomikos_one
    customer.datasource.username=root
    customer.datasource.password=root

atomikos的maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions</artifactId>
<version>3.9.3</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>3.9.3</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-hibernate3</artifactId>
<version>3.9.3</version>
<exclusions>
<exclusion>
<artifactId>hibernate</artifactId>
<groupId>org.hibernate</groupId>
</exclusion>
</exclusions>
</dependency>

AtomikosJtaPlatform这个类指明了,Atomikos需要我们提供UserTransaction和TransactionManager的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
public class AtomikosJtaPlatform extends AbstractJtaPlatform {
private static final long serialVersionUID = 1L;
static TransactionManager transactionManager;
static UserTransaction transaction;
@Override
protected TransactionManager locateTransactionManager() {
return transactionManager;
}
@Override
protected UserTransaction locateUserTransaction() {
return transaction;
}
}

  • transactionManager等配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    @Configuration
    @ComponentScan
    @EnableTransactionManagement
    public class MainConfig {
    @Bean
    public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
    }
    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setShowSql(true);
    hibernateJpaVendorAdapter.setGenerateDdl(true);
    hibernateJpaVendorAdapter.setDatabase(Database.MYSQL);
    return hibernateJpaVendorAdapter;
    }
    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
    UserTransactionImp userTransactionImp = new UserTransactionImp();
    userTransactionImp.setTransactionTimeout(10000);
    return userTransactionImp;
    }
    @Bean(name = "atomikosTransactionManager", initMethod = "init"
    , destroyMethod = "close")
    public TransactionManager atomikosTransactionManager() throws Throwable {
    UserTransactionManager userTransactionManager = new UserTransactionManager();
    userTransactionManager.setForceShutdown(false);
    AtomikosJtaPlatform.transactionManager = userTransactionManager;
    return userTransactionManager;
    }
    @Bean(name = "transactionManager")
    @DependsOn({ "userTransaction", "atomikosTransactionManager" })
    public PlatformTransactionManager transactionManager() throws Throwable {
    UserTransaction userTransaction = userTransaction();
    AtomikosJtaPlatform.transaction = userTransaction;
    TransactionManager atomikosTransactionManager = atomikosTransactionManager();
    return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }
    }

数据库1的数据源配置CustomerConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Configuration
@DependsOn("transactionManager")
@EnableJpaRepositories(basePackages = "com.iyihua.sample.repository.customer"
, entityManagerFactoryRef = "customerEntityManager", transactionManagerRef = "transactionManager")
@EnableConfigurationProperties(CustomerDatasourceProperties.class)
public class CustomerConfig {
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Autowired
private CustomerDatasourceProperties customerDatasourceProperties;

@Primary
@Bean(name = "customerDataSource", initMethod = "init", destroyMethod = "close")
public DataSource customerDataSource() {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(customerDatasourceProperties.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(customerDatasourceProperties.getPassword());
mysqlXaDataSource.setUser(customerDatasourceProperties.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("xads1");
return xaDataSource;
}
@Primary
@Bean(name = "customerEntityManager")
@DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean customerEntityManager() throws Throwable {
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
properties.put("javax.persistence.transactionType", "JTA");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJtaDataSource(customerDataSource());
entityManager.setJpaVendorAdapter(jpaVendorAdapter);
entityManager.setPackagesToScan("com.iyihua.sample.domain.customer");
entityManager.setPersistenceUnitName("customerPersistenceUnit");
entityManager.setJpaPropertyMap(properties);
return entityManager;
}
}

数据库2的数据源配置OrderConfig

1
2
3
4
5
6
7
8
9
@Configuration
@DependsOn("transactionManager")
@EnableJpaRepositories(basePackages = "com.iyihua.sample.repository.order"
, entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
@EnableConfigurationProperties(OrderDatasourceProperties.class)
public class OrderConfig {


}

  • 业务方法:资金在库(atomikos_one),红包在库(atomikos_two)资金账号1转10元到资金账号2;红包账号2转10元到红包账号1**
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Service
    public class StoreServiceImpl implements StoreService {
    @Transactional()
    public void transfer() {
    CapitalAccount ca1 = capitalAccountRepository.findOne(1l);
    CapitalAccount ca2 = capitalAccountRepository.findOne(2l);
    RedPacketAccount rp1 = redPacketAccountRepository.findOne(1l);
    RedPacketAccount rp2 = redPacketAccountRepository.findOne(2l);
    BigDecimal capital = BigDecimal.TEN;
    BigDecimal red = BigDecimal.TEN;
    ca1.transferFrom(capital);
    ca2.transferTo(capital);
    capitalAccountRepository.save(ca1);
    capitalAccountRepository.save(ca2);
    rp2.transferFrom(red);
    rp1.transferTo(red);
    redPacketAccountRepository.save(rp1);
    redPacketAccountRepository.save(rp2);
    }
    }

get and run demo:

https://github.com/YihuaWanglv/spring-boot-jta-atomikos-sample

  • git clone https://github.com/YihuaWanglv/spring-boot-jta-atomikos-sample.git
  • import db script in folder “docs”
  • import project into ide and run App.java or build project and run the jar
  • visit utl:http://localhost:8082/save to see saveTest

java自动化测试整理

发表于 2016-08-12 | 更新于 2019-05-22 | 分类于 java

java自动化测试整理

1. 自动化测试的4个关键部分

  • 使用svn/git作为代码版本管理
  • 使用maven构建项目,依赖和目录统一
  • 使用junit/testng+mockito写单元测试
  • 使用jenkins执行项目构建和测试任务
  • 使用Sonar作为自动化单元测试反馈报告统一展现平台

2. web自动化测试管理工具

  • 使用 Selenium 实现基于 Web 的自动化测试
  • 使用 Rest-Assured 测试 REST API
  • api测试,从手工到平台的演变:运用web+httpclient实现,测试的可配置

3. restapi的自动化测试之路

  • Rest-Assured或其他工具,编写针对api的单元测试;
  • 新代码提交,自动触发构建,成功部署服务器;
  • 自动运行使用 Rest-Assured 编写的单元测试,对 REST API 进行测试

4. 自动化测试工具脑图

【转】-支付宝架构与技术

发表于 2016-08-10 | 更新于 2019-05-22 | 分类于 architecture

支付宝的开源分布式消息中间件–Metamorphosis(MetaQ)
  Metamorphosis (MetaQ) 是一个高性能、高可用、可扩展的分布式消息中间件,类似于LinkedIn的Kafka,具有消息存储顺序写、吞吐量大和支持本地和XA事务等特性,适用于大吞吐量、顺序消息、广播和日志数据传输等场景,在淘宝和支付宝有着广泛的应用,现已开源。
  Metamorphosis是淘宝开源的一个Java消息中间件。关于消息中间件,你应该听说过JMS规范,以及一些开源实现,如ActiveMQ和HornetQ等。Metamorphosis也是其中之一。
  Metamorphosis的起源是我从对linkedin的开源MQ–现在转移到apache的kafka的学习开始的,这是一个设计很独特的MQ系统,它采用pull机制,而不是一般MQ的push模型,它大量利用了zookeeper做服务发现和offset存储,它的设计理念我非常欣赏并赞同,强烈建议你阅读一下它的设计文档,总体上说metamorphosis的设计跟它是完全一致的。但是为什么还需要meta呢?
  简单概括下我重新写出meta的原因:
  Kafka是scala写,我对scala不熟悉,并且kafka整个社区的发展太缓慢了。
  有一些功能是kakfa没有实现,但是我们却需要:事务、多种offset存储、高可用方案(HA)等
  Meta相对于kafka特有的一些功能:
  文本协议设计,非常透明,支持类似memcached stats的协议来监控broker
  纯Java实现,从通讯到存储,从client到server都是重新实现。
  提供事务支持,包括本地事务和XA分布式事务
  支持HA复制,包括异步复制和同步复制,保证消息的可靠性
  支持异步发送消息
  消费消息失败,支持本地恢复
  多种offset存储支持,数据库、磁盘、zookeeper,可自定义实现
  支持group commit,提升数据可靠性和吞吐量。
  支持消息广播模式
  一系列配套项目:python客户端、twitter storm的spout、tail4j等。
  因此meta相比于kafka的提升是巨大的。meta在淘宝和支付宝都得到了广泛应用,现在每天支付宝每天经由meta路由的消息达到120亿,淘宝也有每天也有上亿的消息量。
  Meta适合的应用:
  日志传输,高吞吐量的日志传输本来就是kafka的强项
  消息广播功能,如广播缓存配置失效。
  数据的顺序同步功能,如mysql binlog复制
  分布式环境下(broker,producer,consumer都为集群)的消息路由,对顺序和可靠性有极高要求的场景。
  作为一般MQ来使用的其他功能

总体结构:

内部结构:

1…345…9
Wanglv Yihua

Wanglv Yihua

82 日志
20 分类
206 标签
RSS
© 2019 Wanglv Yihua
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Muse v6.4.1