Quantcast
Channel: 李志强个人博客
Viewing all 222 articles
Browse latest View live

sqlserver快照,启用基于行版本控制的隔离级别

$
0
0

  在sqlserver标准的已提交读(read committed)隔离级别下,读写操作相互阻塞。未提交读(read uncommitted)虽然不会有这种阻塞,但是读操作可能会读到脏数据,这是大部分用户不能接受的。    ORACLE使用的是另一种处理方式:在任何一个修改之前,先对修改前的版本做一个复制,后续的一切读操作都会去读这个复制的版本,修改将创建一个新的版本。在这种处理方式下,读写操作不会互相阻塞。使用这种行版本控制机制的好处,是系统的并发性比较高,但是缺点是用户读到的虽然不是一个脏数据,但是可能是个正在被修改马上就要过期的数据。如果根据这个过期的值做数据修改,可能会产生逻辑错误。    有些用户为了更高的并发性而不在乎这种缺点,所以更喜欢ORACLE的那种处理方法。
为了满足这部分用户的需求,SQL2005也引入了这种机制,来实现类似的功能。所以选取行版本控制隔离级别也可以成为消除阻塞和死锁的一种手段。–查询数据库状态 select name,user_access,user_access_desc, snapshot_isolation_state,snapshot_isolation_state_desc, is_read_committed_snapshot_on from sys.databases GO —启用指定数据库的快照隔离 ALTER DATABASE [dbName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO ALTER DATABASE [dbName] SET ALLOW_SNAPSHOT_ISOLATION ON GO ALTER DATABASE [dbName] SET READ_COMMITTED_SNAPSHOT ON GO ALTER DATABASE [dbName] SET MULTI_USER GO
    开启了行版本控制之后,sqlserver会把行版本存放在tempdb里。修改的数据越多,需要存储的信息越多,对sqlserver额外的负载就越大。所以如果一个应用要从其他隔离级别转向使用行版本控制,需要做特别的测试,以确保现有的软硬件配置能支持额外的负荷,应用程序能够达到相似的响应速度。

CentOS 7 升级gcc/g++编译器

$
0
0

  gcc的升级必须要使用源码进行升级,也就说,必须要使用源码进行编译才行。我的7.2的CentOS目前自带的gcc是4.8.5的,gcc从4.8之后开始支持C++11,但是鉴于现在C++14、C++17都已经出来了,所以还是把编译器升级一下,才能紧跟发展,尝试使用14/17的新特性。gcc源码下载地址:https://gcc.gnu.org/。

第一步:下载源代码

 查了资料步骤上多了几个,重做一下:

  首先:

yum -y install texinfo

  如果不执行这个命令的话,那么在执行第四步的配置的时候,会出现makeinfo:could not find this command。

  从:ftp://ftp.gnu.org/gnu/gcc/gcc-8.2.0/下载源码包:gcc-8.2.0.tar.gz。使用命令:tar -zxvf gcc-8.2.0.tar.gz解压。当然也可以在:https://github.com/gcc-mirror/gcc下载源码。下载过程如下:

  选择gcc版本,在Branches这里选择gcc-8这个分支:

  接下来点击旁边的Tags,可以选择gcc-8.2.0-Release

第二步:安装依赖库

  据说原来升级gcc的时候超级麻烦因为它依赖了mpfr、gmp、mpc 和isl共四个库,它们下载起来也很麻烦,现在事情变得简单了很多, 在gcc目录下执行一次执行以下命令:

./contrib/download_prerequisites          #作用是自动下载gcc的4个依赖包

  可能会出现如下错误:

复制代码
[root@CentOs64-7 gcc-8.2.0]# ./contrib/download_prerequisites 
2019-01-21 10:38:33 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
2019-01-21 10:38:39 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2" [1]
2019-01-21 10:38:44 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2019-01-21 10:38:50 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 [1658291] -> "./isl-0.18.tar.bz2" [1]
gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.18.tar.bz2: OK
tar (child): lbzip2: Cannot exec: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
tar: Error is not recoverable: exiting now
error: Cannot extract package from gmp-6.1.0.tar.bz2
复制代码

  这个问题其实就是因为tar解包的时候没有解成功。这是因为机器上没有安装bzip2,使用如下命令安装bzip2:

yum -y install bzip2

  安装这个之后,把解压后的目录删了,再重新走一遍上面的过程,这次就OK了,4个依赖包下载成功。

复制代码
[root@CentOs64-7 gcc-8.2.0]# ./contrib/download_prerequisites 
2019-01-21 10:48:24 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
2019-01-21 10:48:30 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2" [1]
2019-01-21 10:48:34 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2019-01-21 10:48:39 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 [1658291] -> "./isl-0.18.tar.bz2" [1]
gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.18.tar.bz2: OK
All prerequisites downloaded successfully.
复制代码

  如果想要自己安装这些依赖包的话,可以参考这篇博客:(https://blog.csdn.net/yndu_13/article/details/82842408),但是我没有照着这个操作,就是没有验证到底是否行得通……

第三步:配置

  然后使用命令:

mkdir build
cd build

  进入build目录后,再执行下面的配置命令。

  如果你只需要支持C/C++编译器,那么在gcc目录下执行如下配置命令:

../configure  --prefix=/usr --enable-multilib --enable-languages=c,c++ -disable-multilib

  否则,执行:

../configure  --prefix=/usr --enable-multilib

  这条命令的作用实际上就是生成合适的Makefile,执行的过程中出现了一个警告:

configure: WARNING: using in-tree isl, disabling version check
*** This configuration is not supported in the following subdirectories:
     gnattools gotools target-libada target-libhsail-rt target-libgfortran target-libbacktrace target-libgo target-libffi target-libobjc target-liboffloadmic
    (Any other directories should still work fine.)

  说明一下,这个警告,我看了很多人的博客,都没有提到过,有的博客倒是把它列出来了,但是却没有给出解决的办法。

  配置成功以后,执行命令:

yum groupinstall "Development Tools" 

第四步:make

  第三步执行无误后,在gcc目录下使用make目录。建议使用单任务make,不要使用多任务,多任务有可能会编译报错。

  然而安装失败了……

复制代码
checking whether -lc should be explicitly linked in... no
checking dynamic linker characteristics... configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES.
make[2]: *** [configure-stage1-zlib] 错误 1
make[2]: 离开目录“/root/gcc-8.2.0”
make[1]: *** [stage1-bubble] 错误 2
make[1]: 离开目录“/root/gcc-8.2.0”
make: *** [all] 错误 2
复制代码

  先把原来安装的东西都清理一下:

make distclean

  这个问题,就是我把执行了一下 yum -y install texinfo,然后把整个过程重新走了一遍,就没有问题了。

第四步

  安装,执行命令

make install

  等待安装结束后就能正常使用gcc了。现在使用gcc -v 检查版本的话,就是gcc 8.2.0。在make的过程中也有一些警告,目前尚不知这些警告会造成何种影响,这些警告有点儿多,没有逐一记录下来,如果有后来者看到这篇博客,并遇到了和我一样的困扰,并且解决了这个问题,烦请告之,感激不尽。

  升级gcc/g++的必要性,现在下载到的CentOS镜像中自带的gcc版本是4.8.5,gcc从4.8开始支持C++11,但是在以后的编码工作中势必会用到C++14、C++17乃至更新的标准下的新特性,既然标准库已经造出了轮子,为什么我们不用呢?而要使用这些新特性,你就必须要获得编译器的支持。

补充:

  升级gcc的一个更加简单的做法,但是这个做法的缺点是只支持64位程序而无32位支持。

  采用CentOS的一个第三方库SCL(软件选集),SCL可以在不覆盖原系统软件包的情况下安装新的软件包与老软件包共存并且可以使用scl命令切换,不过也有个缺点就是只支持64位的。还有devtoolset-4(gcc 5.2)及之前的版本都已经结束支持,只能通过其他方法安装。

  本次升级到gcc8,命令如下:

yum -y install centos-release-scl
yum -y install devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils
scl enable devtoolset-8 bash  #启动gcc8

  你要哪个版本的就把第2条命令中的数字8改成你要的主版本号就可以了。这样升级到的是最新的版本。例如8升级到的是8.2.0而不是8.1。

  通过scl命令启动gcc,这个只是暂时的,当你的shell关闭后或者重启就会恢复原来的版本,要想一直使用升级后的版本可以使用如下命令:

echo "source /opt/rh/devtoolset-8/enable" >>/etc/profile

InnoDB并发如此高,原因竟然在这?

$
0
0

《InnoDB行锁,如何锁住一条不存在的记录?》埋了一个坑,没想到评论反响剧烈,大家都希望深挖下去。原计划写写InnoDB的锁结束这个case,既然呼声这么高,干脆全盘系统性的写写InnoDB的并发控制,锁,事务模型好了。

体系相对宏大,一篇肯定写不完,容我娓娓道来,通俗地说清楚来龙去脉。

一、并发控制

为啥要进行并发控制?

并发的任务对同一个临界资源进行操作,如果不采取措施,可能导致不一致,故必须进行并发控制(Concurrency Control)。

技术上,通常如何进行并发控制?

通过并发控制保证数据一致性的常见手段有:

锁(Locking)

数据多版本(Multi Versioning)

二、锁

如何使用普通锁保证一致性?

普通锁,被使用最多:

(1)操作数据前,锁住,实施互斥,不允许其他的并发任务操作;

(2)操作完成后,释放锁,让其他任务执行;

如此这般,来保证一致性。

普通锁存在什么问题?

简单的锁住太过粗暴,连“读任务”也无法并行,任务执行过程本质上是串行的。

于是出现了共享锁与排他锁:

共享锁(Share Locks,记为S锁),读取数据时加S锁

排他锁(eXclusive Locks,记为X锁),修改数据时加X锁

共享锁与排他锁的玩法是:

共享锁之间不互斥,简记为:读读可以并行

排他锁与任何锁互斥,简记为:写读,写写不可以并行

可以看到,一旦写数据的任务没有完成,数据是不能被其他任务读取的,这对并发度有较大的影响。

画外音:对应到数据库,可以理解为,写事务没有提交,读相关数据的select也会被阻塞。

有没有可能,进一步提高并发呢?

即使写任务没有完成,其他读任务也可能并发,这就引出了数据多版本。

三、数据多版本

数据多版本是一种能够进一步提高并发的方法,它的核心原理是:

(1)写任务发生时,将数据克隆一份,以版本号区分;

(2)写任务操作新克隆的数据,直至提交;

(3)并发读任务可以继续读取旧版本的数据,不至于阻塞;

如上图:

  1. 最开始数据的版本是V0;
  2. T1时刻发起了一个写任务,这是把数据clone了一份,进行修改,版本变为V1,但任务还未完成;
  3. T2时刻并发了一个读任务,依然可以读V0版本的数据;
  4. T3时刻又并发了一个读任务,依然不会阻塞;

可以看到,数据多版本,通过“读取旧版本数据”能够极大提高任务的并发度。

提高并发的演进思路,就在如此:

普通锁,本质是串行执行

读写锁,可以实现读读并发

数据多版本,可以实现读写并发

画外音:这个思路,比整篇文章的其他技术细节更重要,希望大家牢记。

好,对应到InnoDB上,具体是怎么玩的呢?

四、redo, undo,回滚段

在进一步介绍InnoDB如何使用“读取旧版本数据”极大提高任务的并发度之前,有必要先介绍下redo日志,undo日志,回滚段(rollback segment)。

为什么要有redo日志?

数据库事务提交后,必须将更新后的数据刷到磁盘上,以保证ACID特性。磁盘随机写性能较低,如果每次都刷盘,会极大影响数据库的吞吐量。

优化方式是,将修改行为先写到redo日志里(此时变成了顺序写),再定期将数据刷到磁盘上,这样能极大提高性能。

画外音:这里的架构设计方法是,随机写优化为顺序写,思路更重要。

假如某一时刻,数据库崩溃,还没来得及刷盘的数据,在数据库重启后,会重做redo日志里的内容,以保证已提交事务对数据产生的影响都刷到磁盘上。

一句话,redo日志用于保障,已提交事务的ACID特性。

为什么要有undo日志?

数据库事务未提交时,会将事务修改数据的镜像(即修改前的旧版本)存放到undo日志里,当事务回滚时,或者数据库奔溃时,可以利用undo日志,即旧版本数据,撤销未提交事务对数据库产生的影响。

画外音:更细节的,

对于insert操作,undo日志记录新数据的PK(ROW_ID),回滚时直接删除;

对于delete/update操作,undo日志记录旧数据row,回滚时直接恢复;

他们分别存放在不同的buffer里。

一句话,undo日志用于保障,未提交事务不会对数据库的ACID特性产生影响。

什么是回滚段?

存储undo日志的地方,是回滚段。

undo日志和回滚段和InnoDB的MVCC密切相关,这里举个例子展开说明一下。

栗子:

t(id PK, name);

数据为:

1, shenjian

2, zhangsan

3, lisi

此时没有事务未提交,故回滚段是空的。

接着启动了一个事务:

start trx;

delete (1, shenjian);

update set(3, lisi) to (3, xxx);

insert (4, wangwu);

并且事务处于未提交的状态。

可以看到:

(1)被删除前的(1, shenjian)作为旧版本数据,进入了回滚段;

(2)被修改前的(3, lisi)作为旧版本数据,进入了回滚段;

(3)被插入的数据,PK(4)进入了回滚段;

接下来,假如事务rollback,此时可以通过回滚段里的undo日志回滚。

画外音:假设事务提交,回滚段里的undo日志可以删除。

可以看到:

(1)被删除的旧数据恢复了;

(2)被修改的旧数据也恢复了;

(3)被插入的数据,删除了;

事务回滚成功,一切如故。

四、InnoDB是基于多版本并发控制的存储引擎

《大数据量,高并发量的互联网业务,一定要使用InnoDB》提到,InnoDB是高并发互联网场景最为推荐的存储引擎,根本原因,就是其多版本并发控制(Multi Version Concurrency Control, MVCC)。行锁,并发,事务回滚等多种特性都和MVCC相关。

MVCC就是通过“读取旧版本数据”来降低并发事务的锁冲突,提高任务的并发度。

核心问题:

旧版本数据存储在哪里?

存储旧版本数据,对MySQL和InnoDB原有架构是否有巨大冲击?

通过上文undo日志和回滚段的铺垫,这两个问题就非常好回答了:

(1)旧版本数据存储在回滚段里;

(2)对MySQL和InnoDB原有架构体系冲击不大;

InnoDB的内核,会对所有row数据增加三个内部属性:

(1)DB_TRX_ID,6字节,记录每一行最近一次修改它的事务ID;

(2)DB_ROLL_PTR,7字节,记录指向回滚段undo日志的指针;

(3)DB_ROW_ID,6字节,单调递增的行ID;

InnoDB为何能够做到这么高的并发?

回滚段里的数据,其实是历史数据的快照(snapshot),这些数据是不会被修改,select可以肆无忌惮的并发读取他们。

快照读(Snapshot Read),这种一致性不加锁的读(Consistent Nonlocking Read),就是InnoDB并发如此之高的核心原因之一。

这里的一致性是指,事务读取到的数据,要么是事务开始前就已经存在的数据(当然,是其他已提交事务产生的),要么是事务自身插入或者修改的数据。

什么样的select是快照读?

除非显示加锁,普通的select语句都是快照读,例如:

select * from t where id>2;

这里的显示加锁,非快照读是指:

select * from t where id>2 lock in share mode;

select * from t where id>2 for update;

问题来了,这些显示加锁的读,是什么读?会加什么锁?和事务的隔离级别又有什么关系?

本节的内容已经够多了,且听下回分解。

总结

(1)常见并发控制保证数据一致性的方法有锁,数据多版本;

(2)普通锁串行,读写锁读读并行,数据多版本读写并行;

(3)redo日志保证已提交事务的ACID特性,设计思路是,通过顺序写替代随机写,提高并发;

(4)undo日志用来回滚未提交的事务,它存储在回滚段里;

(5)InnoDB是基于MVCC的存储引擎,它利用了存储在回滚段里的undo日志,即数据的旧版本,提高并发;

(6)InnoDB之所以并发高,快照读不加锁;

(7)InnoDB所有普通select都是快照读;

画外音:本文的知识点均基于MySQL5.6。

设置Gradle的本地仓库路径

$
0
0

gradle的默认仓库路径为用户目录下的.gradle目录,gradle并没有像maven那样提供配置文件,若要修改默认仓库路径,我们可以设置环境变量GRADLE_USER_HOME,windows下同理。我把仓库设置在gradle目录下
Linux:

export GRADLE_HOME=/usr/local/gradle
export PATH=$GRADLE_HOME/bin:$PATH
export GRADLE_USER_HOME=$GRADLE_HOME/.gradle

Windows:

GRADLE_USER_HOME=c:/gradle/.gradle

Gradle使用mavenLocal()以及自定义jar包缓存路径

$
0
0

2018-03-21 00:00:55 只喝82年的雪碧 阅读数 9221更多分类专栏: Java版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/qq_23085893/article/details/79633934

最近在尝试使用gradle代替maven创建web项目

在build.gradle文件中,使用mavenLocal() 发现并不生效

repositories {    mavenLocal() //直接使用本地maven仓库    maven { url "http://maven.aliyun.com/nexus/content/groups/public" }    mavenCentral() }

经过一番资料查找,发现使用mavenLocal() 时Gradle默认会按以下顺序去查找本地的maven仓库:USER_HOME/.m2/settings.xml >> M2_HOME/conf/settings.xml >> USER_HOME/.m2/repository。注意,环境变量要加入M2_HOME, 我们配环境时很多时候都是使用MAVEN_HOME或者直接在path中输入bin路径了,导致mavenLocal无法生效。

另外,如果本地没有相关jar包,gradle会在下载到USER_HOME/.gradle文件夹下,若想让gradle下载到指定文件夹,配置GRADLE_USER_HOME环境变量

win10 vpn 720错误解决办法

$
0
0

以下办法即可完美解决!

解决办法:

1.打开如图所示此电脑中管理按钮

2.然后找到如图所示的WAN Miniport(IP),选择卸载/删除该设备。(注意不要删除错了)

3.重启电脑重新连接宽带即可。

k8s实践Centos7

$
0
0

https://blog.51cto.com/3241766/2405624

一、所有节点安装docker
1)安装docker
wget https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce
2)配置docker
配置代理可选
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<-‘EOF’
[Service]
Environment=”HTTP_PROXY=http://10.68.4.22:808″
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

3)配置国内镜像加速地址
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-‘EOF’
{
“registry-mirrors”: [“https://ouw84i2o.mirror.aliyuncs.com”],
“exec-opts”: [“native.cgroupdriver=systemd”]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

二、安装k8s
1)配置yum源下载
cat < /etc/yum.repos.d/kubernetes.repo

[kubernetes]

name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

yum install -y kubelet kubeadm kubectl
2)禁用swap
swapoff -a
sed -i.bak ‘/swap/s/^/#/’ /etc/fstab
3)host
cat >> /etc/hosts << EOF
10.68.5.196 master
10.68.5.194 node1
10.68.5.195 node2
EOF
3)防火墙配置开放相应端口
firewall-cmd –add-port=6443/tcp –zone=public –permanent
firewall-cmd –add-port=10250/tcp –zone=public –permanent
firewall-cmd –reload
4)下载k82镜像

[root@master ~]

# more image.sh

!/bin/bash

url=registry.cn-hangzhou.aliyuncs.com/google_containers
version=v1.16.2
images=(kubeadm config images list --kubernetes-version=$version|awk -F '/' '{print $2}')
for imagename in ${images[@]} ; do
docker pull $url/$imagename
docker tag $url/$imagename k8s.gcr.io/$imagename
docker rmi -f $url/$imagename
done
5)
加载环境变量

[root@master ~]

#
echo “export KUBECONFIG=/etc/kubernetes/admin.conf” >>~/.bash_profile
source .bash_profile

6)安装pod网络
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

xx)初始化master
kubeadm init –apiserver-advertise-address 10.68.5.196 –pod-network-cidr=10.244.0.0/16

Nginx架构分析

$
0
0

Nginx模块化

  Nginx基于模块化设计,每个模块是一个功能实现,分布式开发,团队协作

  Nginx涉及到的模块分为五大类:核心模块、标准HTTP模块、可选HTTP模块、邮件模块、第三方模块

  编译后的源码目录 /usr/local/src/nginx-1.14.0/objs/ngx_modules.c

Nginx的web请求机制

   并行处理:多进程、多线程、异步

  高并发处理方案:开多个进程,每个进程处理一个请求;开多个线程(是进程的一个子单元,节省资源;多个线程共享一个内存块,同一个内存块的其他线程崩溃,同时都崩溃),每个线程处理一个请求;异步机制。

  同步机制:(通信机制)同步、异步发生在当客户端发起请求后,服务端处理客户端的请求时。 同步机制,是指客户端发送请求后,需要等待服务端(内核)返回信息后,再继续发送下一个请求。 在同步机制中,所有的请求在服务器端得到同步,即发送方和接收方对请求的处理步调是一致的。

  异步机制:(通信机制)异步机制,是指客户端发出一个请求后,不等待服务端(内核)返回信息,就继续发送下一个请求。 在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完后再通知发送方。

  举例:一家酒店前台,在旺季的高峰时间段会接很多预定酒席的电话。 如果是同步机制情况下,前台每接一个电话后先不挂掉电话,而是去查询有无剩余酒席,查到结果后,告诉客户。 如果是异步机制情况下,前台每接一个预定电话直接回复客户,一会回复,此时前台把查询这件事情交给了另外的同事, 该前台挂掉电话后,继续处理其他客户的事情,当另外的同事查询到结果后再通知给前台,前台再通知客户。

  阻塞:(进程调用)阻塞与非阻塞发生在IO调度中,比如内核到磁盘IO。 阻塞方式下,进程/线程在获取最终结果之前,被系统挂起了,也就是所谓的阻塞了,在阻塞过程中该进程什么都干不了, 直到最终结果反馈给它时,它才恢复运行状态。

  非阻塞:(进程调用)非阻塞方式和阻塞相反,进程/线程在获取最终结果之前,并没有进入被挂起的状态,而是该进程可以继续执行新的任务。 当有最终结果反馈给该进程时,它再把结果交给客户端。

  举例:依然是酒店前台接待预定酒席电话的案例。 此时角色不再是前台,而是她的查询有无剩余酒席的同事。如果是阻塞方式,该同事在查询有无剩余酒席的过程中,需要傻傻地 等待酒店管理系统给他返回结果,在此期间不能做其他事情。 如果是非阻塞,该同事在等待酒店管理系统给他返回结果这段时间,可以做其他事情,比如可以通知前台剩余酒席的情况。

   Nginx的请求机制:Nginx之所以可以支持高并发,是因为Nginx用的是异步非阻塞的机制,而Nginx是靠事件驱动模型来实现这种机制的。 在Nginx的事件驱动模型下,客户端发起的所有请求在服务端都会被标记为一个事件,Nginx会把这些事件收集到“事件收集器”里, 然后再把这些事件交给内核去处理

事件驱动模型

  事件驱动模型是实现异步非阻塞的一个手段。事件驱动模型中,一个进程(线程)就可以了。 对于web服务器来说,客户端A的请求连接到服务端时,服务端的某个进程(Nginx worker process)会处理该请求, 此进程在没有返回给客户端A结果时,它又去处理了客户端B的请求。 服务端把客户端A以及客户端B发来的请求作为事件交给了“事件收集器”, 而“事件收集器”再把收集到的事件交由“事件发送器”发送给“事件处理器”进行处理。 最后“事件处理器”处理完该事件后,通知服务端进程,服务端进程再把结果返回给客户端A、客户端B。 在这个过程中,服务端进程做的事情属于用户级别的,而事件处理这部分工作属于内核级别的。 也就是说这个事件驱动模型是需要操作系统内核来作为支撑的。

  Nginx的事件驱动模型,支持select、poll、epoll、rtsig、kqueue、/dev/poll、eventport等。 最常用的是前三种,其中kqueue模型用于支持BSD系列平台的事件驱动模型。kqueue是poll模型的一个变种,本质上和epoll一样。 /dev/poll是Unix平台的事件驱动模型,其主要在Solaris7及以上版本、HP/UX11.22及以上版本、IRIX6.5.15及以上版本、 Tru64 Unix 5.1A及以上版本的平台使用。 eventport是用于支持Solaris10及以上版本的事件驱动模型。

  selected模型:Linux和Windows都支持,使用select模型的步骤是: 1. 创建所关注事件的描述符集合,对于一个描述符,可以关注其上面的读(Read)事件、写(Write)事件以及异常发生(Exception)事件。 在select模型中,要创建这3类事件描述符集合。 2. 调用底层提供的select()函数,等待事件发生。 3. 轮询所有事件描述符集合中的每一个事件描述符,检查是否有相应的事件发生,如果有就进行处理。

  poll模型:poll模型是Linux平台上的事件驱动模型,在Linux2.1.23中引入的,Windows平台不支持该模型。 poll模型和select模型工作方式基本相同,区别在于,select模型创建了3个描述符集合,而poll模型只创建一个描述符集合。

  epoll模型:epoll模型属于poll模型的变种,在Linux2.5.44中引入。epoll比poll更加高效,原因在于它不需要轮询整个描述符集合, 而是Linux内核会关注事件集合,当有变动时,内核会发来通知。

Nginx架构

  Nginx服务器使用 master/worker 多进程模式。 主进程(Master process)启动后,会接收和处理外部信号; 主进程启动后通过fork() 函数产生一个或多个子进程(work process),每个子进程会进行进程初始化、 模块调用以及对事件的接收和处理等工作。

  主进程

1234567891011主要功能是和外界通信和对内部其他进程进行管理,具体来说有以下几点: * 读取Nginx配置文件并验证其有效性和正确性 * 建立、绑定和关闭socket * 按照配置生成、管理工作进程 * 接收外界指令,比如重启、关闭、重载服务等指令 * 日志文件管理

  子进程(worker process)

123456789101112131415是由主进程生成,生成数量可以在配置文件中定义。该进程主要工作有: * 接收客户端请求 * 将请求依次送入各个功能模块进行过滤处理 * IO调用,获取响应数据 * 与后端服务器通信,接收后端服务器处理结果 * 数据缓存,访问缓存索引,查询和调用缓存数据 * 发送请求结果,响应客户端请求 * 接收主进程指令,如重启、重载、退出等

MySQL核心参数优化

$
0
0

back_log参数的作用

指定MySQL可能的TCP/IP的连接数量(一个TCP/IP连接占256k),默认是50。
当MySQL主线程在很短的时间内得到非常多的连接请求,该参数就起作用,之后主线程花些时间(尽管很短)检查连接并且启动一个新线程。
back_log参数的值指出在MySQL暂时停止响应新请求之前的短时间内多少个请求可以被存在堆栈中。如果系统在一个短时间内有很多连接,则需要增大该参数的值,该参数值指定到来的TCP/IP连接的侦听accept队列的大小。
不同的操作系统在这个accept队列大小上有它自己的限制,设定back_log高于你的操作系统的限制将是无效的。

参考值:

back_log=300 # 或 back_log=500

thread_cache_size参数的作用

thread_cache_size线程池,线程缓存。这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能。
每建立一个连接,都需要一个线程来与之匹配,此参数用来缓存空闲的线程,以至不被销毁,如果线程缓存中有空闲线程,这时候如果建立新连接,MYSQL就会很快的响应连接请求。
可根据物理内存设置规则如下:
1G ―> 8
2G ―> 16
3G ―> 32
大于3G ―> 64

参考值:

table_open_cache参数的作用

table_open_cache,表高速缓存的大小。

当某一连接访问一个表时,MySQL会检查当前已缓存表的数量。如果该表已经在缓存中打开,则会直接访问缓存中的表已加快查询速度;如果该表未被缓存,则会将当前的表添加进缓存并进行查询。

在执行缓存操作之前,table_cache用于限制缓存表的最大数目:如果当前已经缓存的表未达到table_cache,则会将新表添加进来;若已经达到此值,MySQL将根据缓存表的最后查询时间、查询率等规则释放之前的缓存。

参考值:

1table_open_cache=1024

学习笔记

###CPU的优化

# innodb_thread_concurrency设置的值约等CPU数
innodb_thread_concurrency=32

# 连接的优化

内存的优化

123# 关闭查询缓存,缓存到应用层(如redis),不建议在MYSQL层面开始,5.6有BUGquery_cache_type=0query_cache_size=0

IO的优化

1234567891011121314151617181920212223242526# 单实例时物理内存的60-70%innodb_buffer_pool_size=50G # 每秒后台进程处理IO数据的上限,一般设置总IO的75%左右。 SSD设置成20000innodb_io_capacity=20000 # innodb redo日志组数量(iblog)innodb_log_files_in_group=4 # innodb redo日志组文件大小innodb_log_file_size=1000M # RAID使用直接写,提高性能innodb_flush_method=O_DIRECT # 脏页达到50%就写磁盘innodb_max_dirty_pages_pct=50 # 设置一个表对应一个文件,保持默认innodb_file_per_table=on # 设置PAGE大小(默认16k)innodb_page_size=4k # SSD盘设置为0innodb_flush_neighbors=0

连接的优化

# 指定MySQL可能的TCP/IP的连接数量,现在一般都是长连接,这个值不建议设置过大 back_log=300 # 最大的连接数 max_connections=3000 # 最大的用户连接数(和上面差20,是留给管理用的) max_user_connections=2980 # 表描述符缓存大小,可减少文件打开/关闭次数 table_open_cache=1024 # 线程池,线程缓存 thread_cache_size=512 # 连接超时断开 wait_timeout=120 # 交互超时断开 interactive_timeout=120

数据库一致性优化

12innodb_flush_log_at_trx_commit=1sync_binlog=1

迁移神技 XTTS-恩墨小王子再战32TB跨平台U2L

$
0
0

XTTS(Cross Platform TransportableTablespaces) 跨平台迁移表空间,它是 Oracle 8i开始就引入的一种基于表空间传输的物理迁移方法,命名为 TTS,经历各个版本的不断演进,从 11gR2 开始,在相对停机时间要求日益减少的情况,为了应对越来越大的数据量跨平台迁移,Oracle 推出了新的解决方案—加强版 XTTS(以下简称 XTTS),XTTS 使用增量备份的方式实现跨平台的数据迁移,从真正意义上大大缩短停机时间。在 U2L 如火如荼的今天,通过 XTTS 快捷、高效、平稳、安全的将 Oracle 数据库“小型机+集中式存储”环境迁移至“X86 架构平台+分布式存储”已然成为一大神技。

案例介绍

某省交管核心系统自上线运行6年以来,从最初 GB 为单位的数量级上升到今天 32TB 的业务数据量,其中照片信息的 LOB 字段占有 27TB,随着近几年信息化行业深化改革发展,信息化、互联网+、大数据已经成为交管业务支撑不可或缺的组成元素,但该系统却存在严重问题,已然不能满足现有业务的发展。为解决这套老旧的核心业务系统,通过调研,最终云和恩墨为客户采用 ZDATA 分布式存储方案,组建一个高速、安全、稳定的高性能分布式存储数据库架构,通过去除10年老旧 HPUX 机器,采用高配置的 X86 PC 服务器作为计算和存储节点,不仅提供强大的 CPU、IO、Memory 支持能力,还为后续的横向扩容存储提供不停机服务,可如何在有限的停机时间内进行这大批量的数据迁移成为本项目的一个难点。

1XTTS 概述

XTTS (CrossPlatform Transportable Tablespaces) 跨平台迁移表空间,是 Oracle 自10g推出的一个用来移动单个表空间数据以及创建一个完整的数据库从一个平台移动到另一个平台的迁移备份方法。它是 Oracle 8i 开始就引入的一种基于表空间传输的物理迁移方法,命名为 TTS,不过8i的表空间迁移仅支持相同平台、相同块大小之间的表空间传输,然而在那个年代还未像今天一样技术日新月异,TTS 的光芒一直被埋没在历史的尘埃里,从 Oracle 9i 开始,TTS 开始支持同平台中,不同块大小的表空间传输,这个时候很多数据库管理员就注意到了 TTS 在实际工作中的应用,不过由于每次移动表空间都需要停机、停业务,而9i的 TTS 只能在相同平台之间进行数据移动,相比 Oracle RMAN 本身的快捷方便,更多人更愿意选择使用 RMAN 进行数据备份、数据移动,基于这些原因,Oracle 10g 时代引入了跨平台的表空间传输方案 XTTS,标志着第一代 XTTS 的诞生。

如图一:TTS 和 XTTS 迁移对比图

在 Oracle10.1 中第一代 XTTS 是基于表空间的传输,到 Oracle 11gR1 后,跨平台数据的迁移可以支持传输表空间中的某个特定分区,不过在数据移动过程中,仍然需要将主库设置为 read only 只读状态、停机、停业务下才能进行数据迁移,对于业务不可间断的系统仍旧需要花费大量的停机时间才能达到跨平台物理迁移的效果,所以把 11gR2 以前的 XTTS 技术称作第一代 XTTS 技术。从 11gR2 开始,为了应对越来越大的数据量,相对停机时间要求日益减少的情况,Oracle 推出了新的解决方案—加强版 XTTS(以下简称 XTTS),使用增量备份方式的实现跨平台的数据迁移。从真正意义上讲,能够减少停机时间、进行增量备份的 XTTS,才真正是今天所说的 XTTS。

XTTS 各版本的功能比对如下,表一:XTTS 各版本功能比对表

版本说明跨平台不同块增量备份
Oracle 8i
Oracle 9i
Oracle 10g
Oracle 10gR2
Oracle 11gR1
Oracle 11gR2
Oracle 12c

2XTTS 迁移步骤


在 Oracle11gR2 以后,Oracle 推出了通过前滚数据文件,拷贝数据后再进行多次增量备份的 XTTS 来完成迁移过程,在这个过程中通过开启块跟踪特性,根据 SCN 号来执行一系列的增量备份,并且通过对块跟踪文件的扫描,来完成增量数据的增量备份应用,最后在通过一定的停机时间,在源库 read only 的状态下进行最后一次增量备份转换应用,使得整个迁移过程的停机时间同源库数据块的变化率成正比。这样大大的缩短了停机时间。

3XTTS 迁移方式

XTTS 是基于一组 rman-xttconvert_2.0 的脚本文件包来实现跨平台的数据迁移,主要包含 Perl script xttdriver 和 xttdriver Perl 脚本。Perl script xttdriver.pl 是备份、转换、应用的执行脚本,xtt.properties 是属性文件,其中包含XTTS配置的路径、参数。

采用 XTTS 迁移方式,具备跨平台字序转换和全量初始化加增量 merge 的功能,非常适用于异构 OS 跨平台迁移,成为数据库实施人员中公认的大数据量跨平台迁移的最佳选择。

传统的 TTS 传输表空间要求数据由源端到目标端传输的整个过程中,表空间必须置于 read only 模式,严重影响业务可用性。XTTS 方式可以在业务正常运行的情况下,进行物理全量初始化,增量 block 备份,数据高低字节序转码,增量 block 应用,保持目标端与源端数据的同步,整个过程不影响源端数据库使用。在最后的增量 block 应用完毕后,利用停机窗口进行数据库切换,显著地减少了停机时间。

rman-xttconvert_2.0 包参数说明如下表:

参数意义
tablespaces=TS1,TS2  需要传输的表空间
platformid=2        源库的 platform_id,v$database 中得到
srcdir=src1,src2    当使用 dbms_file_transfer 时使用,表示源库存放数据文件的路径
dstdir=dst1,dst2    当使用 dbms_file_transfer 时使用,表示目标库存放数据文件的路径
srclink=ttslink      从目标端指向源端的 dblink,当使用 dbms_file_transfer 时使用
dfcopydir=/storage  源端用于存放数据文件的 copy,使用 rman 时使用
backupformat=/storage源端用于存放增量备份的目录,无论哪种方式都需要设置
stageondest=/storage目标端存放数据文件 copy 目录,和存放增量备份的目录
storageondest=/oradata/prod/%U  数据文件的最终存放点
backupondest=/storage增量备份格式转换后的输出目录
cnvinst_home=      不同的增量转换目录使用的时候设置该参数
cnvinst_sid        不同中转 sid 使用的时候使用
parallel=3        默认为3
rollparallel=2
Getfileparallel=8默认8,使用 rman 时的并行设置

方式一:dbms_file_transfer

DBMS_FILE_TRANSFER 包是 Oracle 提供的一个用于复制二进制数据库文件或在数据库之间传输二进制文件的程序包,在 XTTS 迁移中,利用不同的参数进行数据文件传输转换完成迁移。


方式二:RMANBackup

RMAN Backup 方式是基于 RMAN 备份原理,通过使用 rman-xttconvert_2.0 包提供的参数,对数据库进行基于表空间的备份,将备份生产的备份集写到本地或者 NFS 盘上,然后在通过 rman-xttconvert_2.0 包中包含的不同平台之间数据文件格式转换的包对进行数据文件格式转换,最后通过记录的表空间 FILE_ID 号生产元数据的导入脚本,通过 db_link 执行完成。

方式三:手工 XTTS 迁移

手工脚本执行 XTTS 迁移是云和恩墨根据 Oracle 提供的 rman-xttconvert_2.0 包迁移步骤从原理入手结合 dbms_file_transfer 和 rman backup 方式集合实际工作需求,手工编写的一套专门用于大数据量跨平台的表空间传输迁移脚本,整套脚本从源库、中间库、目标库三个方面详细的通过手工脚本的方式,把需要进行的迁移工作根据任务以及子任务的方式固化,形成一套可执行的迁移技术方案。

4XTTS 前置条件检查


前置条件

如前面概述所示,传输表空间技术从 Oracle8i 诞生,甲骨文公司经过多个版本的不停的改进完善,时至今日已经发展成为跨平台大数据量迁移的一大利器,尤其从 Oracle11.2.0.3 以后 XTTS 推出使用跨平台增量备份的方式,通过迁移不同字节序格式系统之间的数据,大大的减少了停机的时间,在方便的同时,看一看,使用 XTTS 进行数据迁移需要具备的那些前置条件?

如下表所示:

当然以上所说的目标端数据库版本均为11.2.0.4版本或者以上,如果在使用过程中,目标库的版本是11.2.0.3或者更低,那么需要创建一个单独的11.2.0.4版本数据库作为中间库来在目标端进行数据文件的格式转换,而使用 DBMS_FILE_TRANSFER 包目标端的数据库版本必须是11.2.0.4。

5XTTS 32TB 实战案例分享


实践是检验真理的唯一标志,为贴近实际,下面通过一个跨平台迁移32TB数据库的 XTTS 实战案例,来解析 XTTS 在大数据量迁移过程中的手工脚本应用情况,以下案例从 XTTS 原理出发,涉及操作系统、NFS 存储、rman 备份、系统字节序转换、数据验证以及网络知识。

系统现状评估

主机生产库主库为3节点集群,其中2台为 HP 8640
存储HP  XP24000
应用Websphere(大约20台主机,其中14台为HP小机环境,其他为 Windows 环境)
数据库连接数单节点连接数约为260-300
容灾备份无容灾环境
数据容量约32TB、使用的集中存储 XP24000 已经满了 无法扩容

A.  3节点 RAC 架构不合理

B.  集中存储使用10年以上、计算节点服务器设备老旧

C.  资源配置低

D.  数据爆发式增长

E.  业务应用模块增多、数据库表存放 LOB 字段

F.  物理扩容到达瓶颈

G.  基层业务人员反馈系统各种不好用


迁移需求分析

A.  HPUX11.31 迁移到 Linux

B.  数据库总量 32TB

C.  LOB 字段大小 27TB

D.  单个数据库表空间 17TB

E.  数据库版本11.2.0.3(无任何补丁)

F.  计划内停机切换时间8小时

G.  计划内完成时间15天

H.  数据库账号密码不能改变

I.  无应用测试(根本没有应用程序)

J.  无资源提供测试环境(存储、资源)


迁移方案选型

通过需求调研分析后,因系统涉及到30多 TB 数据量,并且业务停机时间只有8个小时,另外需要跨平台进行数据迁移,我方经过几次测试论证后,排除如下方案,在此也请各位思考一下,如果遇到此类需求作为 DBA 应该如何应对?

最终选择了最具挑战的 XTTS 来完成这次 32TB 的跨平台迁移挑战。


资源配置情况

配置类型源  库目标库
数据库版本11.2.0.311.2.0.4.160419
数据库名称orclorcl
数据库字符集AMERICAN_AMERICA.ZHS16GBKAMERICAN_AMERICA.ZHS16GBK
数据库节点RAC 3节点RAC 4节点
操作系统版本HPUX11.31Linux6.5
磁盘组大小35TB80TB
数据库大小32TB
Block size1638416384


第一步:XTTS 环境检查

检查项源  库目标库
时区是否一致时区为东八区东八区
字符集是否一致16GBK16GBK
检查目标端补丁情况需打最新PSU
组件检查包含源库组件
key compression索引组织表存在需手工重建
表空间规范检查不同磁盘组下数据文件名称命名相同
TEMP表空检查存在需手导入
检查目标端的db_files参数10244096
检查源端compatible参数不可以是windows  且大于10.2.011.2.0.4                                
检查表空间自包含存在自包含 需手工MOVE
用户,DBLINK,PROFILE,PRIV需手工创建


第二歩:开启块跟踪

Block change tracking 进程记录自从上一次0级备份以来数据块的变化,并把这些信息记录在跟踪文件中。RMAN 使用这个文件判断增量备份中需要备份的变更数据。这极大的提高了备份性能和速度,RMAN 可以不再扫描整个文件以查找变更数据。

SQL> ALTER DATABASE ENABLE BLOCK CHANGE TRACKING USING  FILE ‘+SATADATA/changetracking.chg’;Database altered.


第三歩:挂载 NFS 存储

NFS 存储挂载在源库和目标库之间,用于传输数据文件和增量备份节省数据文件的传输时间。

mount  -o  llock,rw,bg,vers=3,proto=tcp,noac,forcedirectio,hard,nointr,timeo=600,rsize=32768,wsize=32768,suid  10.160.118.236:/dump1 /dump1

NFS 共享存储挂载说明:

源端,目标端需要挂载 35T 存储用于存放所有数据文件的镜像文件,建议使用 ntp 的方式将存储远程从源端挂载到目标端,减少备份传送时间,如下图 XTTS 迁移工作示意图—— NFS 存储初始化挂载

第四歩:SCN 确认记录

SCN(System Chang Number)作为 Oracle 中的一个重要机制,在数据恢复、Data Guard、Streams 复制、RAC 节点间的同步等各个功能中起着重要作用,在此需确认 SCN,且该 SCN 号用于后续增量备份的起始点。

alter system checkpoint;select current_scn from v$database;


第五歩:开始 RMAN Copy

基于数据文件的 RMAN COPY 生成的文件存放于挂载的 NFS 目录下。

rman target / <<EOFrun{allocate channel c1 type disk;allocate channel c2 type disk;backup as copy datafile 18,19,20,21,22…….. format  ‘/dump1/enmo/copy/enmo_%U’;release channel c1;release channel c2;}EOF

第六歩:数据文件格式转换

A.  Convert 用于转换数据文件的字节序

B.  转换后的新数据文件直接写入新环境的磁盘组

C.  转换过程消耗目标端的 CPU 资源

D.  此处需要关注目标端磁盘组的大小,避免造成磁盘组满引起转换失败

convert  from platform ‘HP-UX IA (64-bit)’ datafile ‘/dump1/ccm/vvstart_tabs.dbf’  format ‘+FLASHDATA/ORCL/DATAFILE/vvstart_new_01.dbf’;

第七歩:增量备份阶段

A.  开启块跟踪后基于块进行快速增量

B.  增量备份前先查询并记录当前的 SCN

C.  根据全备时记录的 SCN1000 进行增备

D.  增量备份文件存放于 NFS 存储上

E.  增量备份后生成的字节序是 HPUX 的需进一步转换

set until scn=1850backup incremental from scn 1000 datafile  18,19,20,21,22…… format ‘/dump1/enmo/incr/copy_%d_%T_%U’;3;
set until scn=1850backup incremental from scn 1000 datafile  18,19,20,21,22…… format ‘/dump1/enmo/incr/copy_%d_%T_%U’;3;


第八步:增量转换应用

增量备份的转换和应用是两个过程,首先是增量备份集从 HPUX 平台转换成 Linux 平台格式,转换完毕后的备份集在 Linux 平台数据库才能识别。

sys.dbms_backup_restore.backupBackupPiece(bpname  => ‘/dump1/enmo/incr/copy_ORCL_20160707_78ra40o7_1_1’,fname =>  ‘/dump1/enmo/incr/copy_ORCL_20160707_78ra40o7_1_1_conv’,handle =>  handle,media=> media,comment=>  comment, concur=> concur,recid=> recid,stamp => stamp, check_logical  => FALSE,copyno=> 1,deffmt=> 0,  copy_recid=> 0,copy_stamp => 0,npieces=> 1,dest=> 0,pltfrmfr=>  4);

其次是增量备份集的应用,这个过程和 rman recover 的原理是一样的。

sys.dbms_backup_restore.restoreBackupPiece(done  => done, params => null, outhandle => outhandle,outtag => outtag,  failover => failover);

第九歩:循环进行增量备份

循环进行增量备份操作在正式环境的切割之前进行,其目的是为了减少最后一次数据库表空间 readonly 时生产环境的停机时间,需要特别注意的是操作之前务必查询并记录当前 SCN 号。这个 SCN 号是下一次开始增量备份的起点。

如图所示:

图十三:循环增量备份图

第十步:正式切割准备

正式切换的准备阶段是整个 XTTS 迁移过程中最重要的一步,为保证数据的一致性,需要在源库停止业务后,对活动的数据库会话进行查杀处理,并且在 read only 表空间之前需要进行几次检查点检查和 redo log 日志切换保证在无数据在内存的情况下才能进行下一步操作,另外针对计划窗口任务的 JOB 需要提前关闭 JOB 避免因 JOB 执行、批处理等导致数据不一致。


图十四:切割准备工作示意图

第十一歩:最后一次增量备份

最后一次增量备份是在生产源库表空间全部 read only 的情况下进行的,需要根据前一次记录的 SCN 号进行最后一次增量备份、转换、应用,在转换应用之后建议把新环境做一个闪回点或者进行一次全备。作为下一步导入元数据失败的回退方案。

如图所示:


图十五:最后一次增量备份示意图


第十二歩:元数据导入导出

A.  导出时排除系统表空间

B.  导出需在表空间 read only 下才能进行

C.  导入报错及终止

D.  导入可能会遇到 type 不存在的情况

E.  建议使用数据泵进行

如下表所示,在源库导出表空间的元数据

exp \’/ as sysdba\’transport_tablespace=ytablespaces=’TBS_NAME’STATISTICS=nonefile=/dump1/enmo/exp/orcl_XTTS_0715.dmp

根据导出的 dmp 包导入元数据

imp \’/ as sysdba\’transport_tablespace=yTABLESPACES=’TBS_NAME’file=/dump1/enmo/exp/orcl_XTTS0715.dmplog=/dump1/enmo/exp/orcl_imp_XTTS0715.logdatafiles=(‘+FLASHDATA/orcl/datafile/VIO_DATA_u01′,’+FLASHDATA/orcl/datafile/base_image_fno65’)


第十三歩:元对象导入导出

A.  开始导入之前先把表空间 read write

B.  可以使用 dblink 进行远程不落地导入

C.  指定需要的 schemas

D.  导入存在权限不足可进行手工授权

E.  导入完毕后即可开始验证

如下表所示:

1、迁移列表 schema 对象导入impdp “‘/ as sysdba'”  metrics=yes network_link=ENMO_TEST  schemas=VIO EXCLUDE=table,index content=metadata_only  directory=enmo_exp  logfile=imp_full_metadata_`date +”%d%H%M”`.log2、临时表导入3、组织索引表创建4、其他手工导入用户


第十四歩:数据校验收尾阶段

A.  统计信息收集或者导入

EXEC DBMS_STATS.gather_schema_stats(‘DRV_ZW’,  estimate_percent => 10,degree => 64);

B.  无效对象重新检查编译

sqlplus / as sysdba <<EOFDECLARE   threads pls_integer  := 150;BEGIN    utl_recomp.recomp_parallel(threads);END;/

C.  对象数量比对

select owner,object_type,count (*) from dba_objectswhere owner  =’用户名称’group by owner,object_typeorder by owner,object_type;

D.  主键索引核对

select count(1),a.status from dba_constraints a where  a.owner=’用户名称and a.constraint_type=’P’ GROUP BY A.status;

E.  大表数据校验

–num_rows行数验证select  table_name,num_rows from all_tables where owner=’用户名称’ group by table_name,num_rowshaving  num_rows>500 order by table_name;–大小验证 select owner, segment_name, bytes / 1024 /  1024  from dba_segments where segment_type = ‘TABLE’   and owner = ‘用户名称’;

F.  账号权限、同义词验证

Set lines 180Col object_name  for a40select  object_name,object_type,status from dba_objects where owner in (‘账号名称’) and status<>’VALID’;

G.  数据文件头状态

select  STATUS,ERROR,TABLESPACE_NAME from V$DATAFILE_HEADER;

H.  表空间校验

确认owner用户的DEFAULT_TABLESPACE, TEMPORARY_TABLESPACE 以及所有用户在相关表空间上的配额情况将之前创建的owner用户的默认表空间改为正确的默认表空间

I.  启动数据库

启动监听,应用开始连接测试srvctl start  scan_listener删除测试用户信息:drop user  enmoXTTStest cascade;drop public  database link enmo_test;

验证结果比对表如下:

数据校对项结果
测试数据比对True
迁移列表的表空间数量比对True
Schema数量比对True
对象数比对True
表记录数比对True
包、函数、存储过程、索引等状态比对True
权限比对True
同义词比对True
临时表数量比对True


第十五歩:回退方案

触发条件:迁移切换失败进行

A.  前提条件:在不影响现有生产环境后续的可用性的情况下进行切换

B.  回退条件:仅需把源生产数据库表空间置换为 read write 、源库 JOB 进程调整为1000、源库监听启动

C.  回退时间:执行回退方案可保证在5分钟之内完成

D.  回退影响:本次切换失败

6XTTS 风险预估


A.  第一次全量备份消耗源生产库资源需关注

B.  全量备份挂载 NFS 会占用网络流量

C.  筛选排除系统表空间需认真仔细

D.  自包含检查需排除系统表空间

E.  使用exp导元数据可能会遇到 BUG 然后遇到 BUG 大神也救不了

F.  最后一次增量备份 read only 源库表空间可能会因活动会话占用 表空间 read only 过慢

G.  切换之前一定要先对目标库做一个 rman 全备 避免失败无法回退

H.  每次增量备份之前都需记录 SCN

7XTTS 总结

对于数据库的跨平台迁移,大家所熟悉的方法有很多,每种方法都各有利弊,关键还要看实际需求再来决定使用哪一种方式更能切合业务,提高工作效率,作为我个人而言,我比较喜欢采用物理迁移的方式,这样少了很多繁琐的数据校验过程,而且物理迁移或多或少能提高迁移速度,节省不少时间,尤其是面对超过十多个 TB 的数据库时,而这一章节向大家推荐的 XTTS 在面对 U2L 大数量迁移中更能发挥其优势,不过 XTTS 也是有很多不为人知的坑的,个人建议如果想使用好 XTTS 这个方法,需要对 XTTS 的原理非常熟悉,尽量采用手工脚本的方式来进行数据迁移,官方推出的 DBMS_FILE_TRANSFER 包由于 BUG 太多,在同步过程中经常会遇到很多莫名其妙的错误而中断,所以我不建议大家使用。对于 RMAN backup 的方式,因为本身 rman_xttconvert_2.0.zip 包是通过执行不同参数来自动的方式进行数据文件的拷贝、转换、应用以及增量等,需要大家对它的执行过程非常熟悉才不容易造成混乱,如果当您面对需要传输的表空间非常多的时候,建议还是采用手工的方式进行会比较保险。

oracle 列转行

$
0
0

SELECT LISTAGG(T.COLUMN_NAME,’,’) within group(order by T.COLUMN_ID) FROM USER_TAB_COLUMNS T WHERE T.TABLE_NAME=’table1′;

Java 调式、热部署、JVM 背后的支持者 Java Agent

$
0
0

前言:

我们平时写 Java Agent 的机会确实不多,也可以说几乎用不着。但其实我们一直在用它,而且接触的机会非常多。下面这些技术都使用了 Java Agent 技术,看一下你就知道为什么了。  

各个 Java IDE 的调试功能,例如 eclipse、IntelliJ ;

热部署功能,例如 JRebel、XRebel、 spring-loaded;

各种线上诊断工具,例如 Btrace、Greys,还有阿里的 Arthas;

各种性能分析工具,例如 Visual VM、JConsole 等;

Java Agent 直译过来叫做 Java 代理,还有另一种称呼叫做 Java 探针。首先说 Java Agent 是一个 jar 包,只不过这个 jar 包不能独立运行,它需要依附到我们的目标 JVM 进程中。我们来理解一下这两种叫法。

代理:比方说我们需要了解目标 JVM 的一些运行指标,我们可以通过 Java Agent 来实现,这样看来它就是一个代理的效果,我们最后拿到的指标是目标 JVM ,但是我们是通过 Java Agent 来获取的,对于目标 JVM 来说,它就像是一个代理;

探针:这个说法我感觉非常形象,JVM 一旦跑起来,对于外界来说,它就是一个黑盒。而 Java Agent 可以像一支针一样插到 JVM 内部,探到我们想要的东西,并且可以注入东西进去。

拿上面的几个我们平时会用到的技术举例子。拿 IDEA 调试器来说吧,当开启调试功能后,在 debugger 面板中可以看到当前上下文变量的结构和内容,还可以在 watches 面板中运行一些简单的代码,比如取值赋值等操作。还有 Btrace、Arthas 这些线上排查问题的工具,比方说有接口没有按预期的返回结果,但日志又没有错误,这时,我们只要清楚方法的所在包名、类名、方法名等,不用修改部署服务,就能查到调用的参数、返回值、异常等信息。

上面只是说到了探测的功能,而热部署功能那就不仅仅是探测这么简单了。热部署的意思就是说再不重启服务的情况下,保证最新的代码逻辑在服务生效。当我们修改某个类后,通过 Java Agent 的 instrument 机制,把之前的字节码替换为新代码所对应的字节码。

Java Agent 结构

Java Agent 最终以 jar 包的形式存在。主要包含两个部分,一部分是实现代码,一部分是配置文件。

配置文件放在 META-INF 目录下,文件名为 MANIFEST.MF 。包括以下配置项:

Manifest-Version: 版本号
Created-By: 创作者
Agent-Class: agentmain 方法所在类
Can-Redefine-Classes: 是否可以实现类的重定义
Can-Retransform-Classes: 是否可以实现字节码替换
Premain-Class: premain 方法所在类

入口类实现 agentmain 和 premain 两个方法即可,方法要实现什么功能就由你的需求决定了。

Java Agent 实现和使用

接下来就来实现一个简单的 Java Agent,基于 Java 1.8,主要实现两点简单的功能:

1、打印当前加载的所有类的名称;

2、监控一个特定的方法,在方法中动态插入简单的代码并获取方法返回值;
在方法中插入代码主要是用到了字节码修改技术,字节码修改技术主要有 javassist、ASM,已经 ASM 的高级封装可扩展 cglib,这个例子中用的是 javassist。所以需要引入相关的 maven 包。 

<dependency>    <groupId>javassist</groupId>    <artifactId>javassist</artifactId>    <version>3.12.1.GA</version></dependency>

实现入口类和功能逻辑

入口类上面也说了,要实现 agentmain 和 premain 两个方法。这两个方法的运行时机不一样。这要从 Java Agent 的使用方式来说了,Java Agent 有两种启动方式,一种是以 JVM 启动参数 -javaagent:xxx.jar 的形式随着 JVM 一起启动,这种情况下,会调用 premain方法,并且是在主进程的 main方法之前执行。另外一种是以 loadAgent 方法动态 attach 到目标 JVM 上,这种情况下,会执行 agentmain方法。

代码实现如下: 

package kite.lab.custom.agent;import java.lang.instrument.Instrumentation;public class MyCustomAgent {    /**     * jvm 参数形式启动,运行此方法     * @param agentArgs     * @param inst     */    public static void premain(String agentArgs, Instrumentation inst){        System.out.println("premain");        customLogic(inst);    }    /**     * 动态 attach 方式启动,运行此方法     * @param agentArgs     * @param inst     */    public static void agentmain(String agentArgs, Instrumentation inst){        System.out.println("agentmain");        customLogic(inst);    }    /**     * 打印所有已加载的类名称     * 修改字节码     * @param inst     */    private static void customLogic(Instrumentation inst){        inst.addTransformer(new MyTransformer(), true);        Class[] classes = inst.getAllLoadedClasses();        for(Class cls :classes){            System.out.println(cls.getName());        }    }}

我们看到这两个方法都有参数 agentArgs 和 inst,其中 agentArgs 是我们启动 Java Agent 时带进来的参数,比如-javaagent:xxx.jar agentArgs。Instrumentation Java 开放出来的专门用于字节码修改和程序监控的实现。我们要实现的打印已加载类和修改字节码也就是基于它来实现的。其中 inst.getAllLoadedClasses()一个方法就实现了获取所以已加载类的功能。

inst.addTransformer方法则是实现字节码修改的关键,后面的参数就是实现字节码修改的实现类,代码如下:

public class MyTransformer implements ClassFileTransformer {    @Override    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {        System.out.println("正在加载类:"+ className);        if (!"kite/attachapi/Person".equals(className)){            return classfileBuffer;        }        CtClass cl = null;        try {            ClassPool classPool = ClassPool.getDefault();            cl = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));            CtMethod ctMethod = cl.getDeclaredMethod("test");            System.out.println("获取方法名称:"+ ctMethod.getName());            ctMethod.insertBefore("System.out.println(\" 动态插入的打印语句 \");");            ctMethod.insertAfter("System.out.println($_);");            byte[] transformed = cl.toBytecode();            return transformed;        }catch (Exception e){            e.printStackTrace();        }        return classfileBuffer;    }}

以上代码的逻辑就是当碰到加载的类是 kite.attachapi.Person的时候,在其中的 test 方法开始时插入一条打印语句,打印内容是”动态插入的打印语句”,在test方法结尾处,打印返回值,其中$_就是返回值,这是 javassist 里特定的标示符。

MANIFEST.MF 配置文件

在目录 resources/META-INF/ 下创建文件名为 MANIFEST.MF 的文件,在其中加入如下的配置内容:

Manifest-Version: 1.0Created-By: fengzhengAgent-Class: kite.lab.custom.agent.MyCustomAgentCan-Redefine-Classes: trueCan-Retransform-Classes: truePremain-Class: kite.lab.custom.agent.MyCustomAgent

配置打包所需的 pom 设置

最后 Java Agent 是以 jar 包的形式存在,所以最后一步就是将上面的内容打到一个 jar 包里。

在 pom 文件中加入以下配置

<build>    <plugins>        <plugin>            <groupId>org.apache.maven.plugins</groupId>            <artifactId>maven-assembly-plugin</artifactId>            <configuration>                <archive>                    <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>                </archive>                <descriptorRefs>                    <descriptorRef>jar-with-dependencies</descriptorRef>                </descriptorRefs>            </configuration>        </plugin>    </plugins></build>

用的是 maven 的 maven-assembly-plugin 插件,注意其中要用 manifestFile 指定 MANIFEST.MF 所在路径,然后指定 jar-with-dependencies ,将依赖包打进去。

上面这是一种打包方式,需要单独的 MANIFEST.MF 配合,还有一种方式,不需要在项目中单独的添加 MANIFEST.MF 配置文件,完全在 pom 文件中配置上即可。

<build>    <plugins>        <plugin>            <groupId>org.apache.maven.plugins</groupId>            <artifactId>maven-assembly-plugin</artifactId>            <executions>                <execution>                    <goals>                        <goal>attached</goal>                    </goals>                    <phase>package</phase>                    <configuration>                        <descriptorRefs>                            <descriptorRef>jar-with-dependencies</descriptorRef>                        </descriptorRefs>                        <archive>                            <manifestEntries>                                <Premain-Class>kite.agent.vmargsmethod.MyAgent</Premain-Class>                                <Agent-Class>kite.agent.vmargsmethod.MyAgent</Agent-Class>                                <Can-Redefine-Classes>true</Can-Redefine-Classes>                                <Can-Retransform-Classes>true</Can-Retransform-Classes>                            </manifestEntries>                        </archive>                    </configuration>                </execution>            </executions>        </plugin>    </plugins></build>

这种方式是将 MANIFEST.MF 的内容全部写作 pom 配置中,打包的时候就会自动将配置信息生成 MANIFEST.MF 配置文件打进包里。

运行打包命令

接下来就简单了,执行一条 maven 命令即可。

mvn assembly:assembly

最后打出来的 jar 包默认是以「项目名称-版本号-jar-with-dependencies.jar」这样的格式生成到 target 目录下。

运行打包好的 Java Agent

首先写一个简单的测试项目,用来作为目标 JVM,稍后会以两种方式将 Java Agent 挂到这个测试项目上。

package kite.attachapi;import java.util.Scanner;public class RunJvm {    public static void main(String[] args){        System.out.println("按数字键 1 调用测试方法");        while (true) {            Scanner reader = new Scanner(System.in);            int number = reader.nextInt();            if(number==1){                Person person = new Person();                person.test();            }        }    }}

以上只有一个简单的 main 方法,用 while 的方式保证线程不退出,并且在输入数字 1 的时候,调用 person.test()方法。

以下是 Person 类

package kite.attachapi;public class Person {    public String test(){        System.out.println("执行测试方法");        return "I'm ok";    }}

以命令行的方式运行

因为项目是在 IDEA 里创建的,为了省事儿,我就直接在 IDEA 的 「Run/Debug Configurations」里加参数了。

-javaagent:/java-agent路径/lab-custom-agent-1.0-SNAPSHOT-jar-with-dependencies.jar

然后直接运行就可以看到效果了,会看到加载的类名称。然后输入数字键 “1”,会看到字节码修改后的内容。 

以动态 attach 的方式运行

测试之前先要把这个测试项目跑起来,并把之前的参数去掉。运行后,找到这个它的进程id,一般利用jps -l即可。

动态 attach 的方式是需要代码实现的,实现代码如下:

public class AttachAgent {    public static void main(String[] args) throws Exception{        VirtualMachine vm = VirtualMachine.attach("pid(进程号)");        vm.loadAgent("java-agent路径/lab-custom-agent-1.0-SNAPSHOT-jar-with-dependencies.jar");    }}

运行上面的 main 方法 并在测试程序中输入“1”,会得到上图同样的结果。 

发现了没,我们到这里实现的简单的功能是不是和 BTrace 和 Arthas 有点像呢。我们拦截了指定的一个方法,并在这个方法里插入了代码而且拿到了返回结果。如果把方法名称变成可配置项,并且把返回结果保存到一个公共位置,例如一个内存数据库,是不是我们就可以像 Arthas 那样轻松的检测线上问题了呢。当然了,Arthas 要复杂的多,但原理是一样的。

sun.management.Agent 的实现

不知道你平时有没有用过 visualVM 或者 JConsole 之类的工具,其实,它们就是用了 management-agent.jar 这个Java Agent 来实现的。如果我们希望 Java 服务允许远程查看 JVM 信息,往往会配置上一下这些参数:

-Dcom.sun.management.jmxremote-Djava.rmi.server.hostname=192.168.1.1-Dcom.sun.management.jmxremote.port=9999-Dcom.sun.management.jmxremote.rmi.port=9999-Dcom.sun.management.jmxremote.authenticate=false-Dcom.sun.management.jmxremote.ssl=false

这些参数都是 management-agent.jar 定义的。

我们进到 management-agent.jar 包下,看到只有一个 MANIFEST.MF 配置文件,配置内容为:

Manifest-Version: 1.0Created-By: 1.7.0_07 (Oracle Corporation)Agent-Class: sun.management.AgentPremain-Class: sun.management.Agent

可以看到入口 class 为 sun.management.Agent,进到这个类里面可以找到 agentmain 和 premain,并可以看到它们的逻辑。在这个类的开始,能看到我们前面对服务开启远程 JVM 监控需要开启的那些参数定义。 

文章来源:https://www.cnblogs.com/fengzheng/p/11502963.html 

中台,我信了你的邪

$
0
0

中台,我信了你的邪

  文/苏建勋

  中台不是万能药,大象吃这个药,强身健体;蚂蚁吃这个药,一击毙命。

  “中台”概念火了一年多后,露出它狰狞的一面。

  多位行业人士对 36 氪说,由于盲目上中台,深圳一家女装企业的 CIO 被开除;在华南一个有几十人的 CIO(首席信息官,是 Chief Information Officer 的缩写)社群内,2019 年由于中台项目失误导致离职、调岗的高管就有十几个。

  “一分钱都不给,让你们滚出茅台。”中台服务公司“云徙科技”的一名前高管对 36 氪说,由于茅台对该公司承建的中台项目极不满意,一度如此放话。

  茅台的中台项目因为甲方有名、金额大,一度是最引人瞩目的中台案子,也极具代表性。36 氪了解到,茅台虽然最终没和云徙中断合作,但拖了至少 13 个月才正式签约;业界都说茅台是个“超级大单”,但最后云徙拿到的钱只刚过千万,云徙创始人包志刚对 36 氪承认,“的确没有收回成本”。

  到了去年底,阿里巴巴董事长兼 CEO 张勇在湖畔大学分享时也说:如果一个企业奔着中台做中台,就是死。

  如今的失望,来自于最初极高的期望。

  “中台”概念最初得以流行,的确有其需求基础。

  联想 BT/IT 部门企业架构总监杨若东一筹莫展之际,“中台”是他能找到最好的解药。2017 年时,联想集团提出要向云、数据中心、AI 等新业务延伸,但新的业务部门成立,要不要成立一个新的 IT 部门去支持它?

  “不可能。”杨若东飞快算了笔账:联想成立一个新 BU ,往往需要百人的 IT 团队,这意味着一年的预算不断上涨,就算这笔钱能申请下来,几个月内也根本招不够人。但业务可等不及,冲在一线的销售们巴不得三个月搭好系统,六个月可以卖,一年之内有收入。

  杨若东遍寻之后找到的,是一本由阿里中间件首席架构师钟华所写的《企业 IT 架构转型之道》,副标题是“阿里巴巴中台战略思想与架构实战”。下单看过之后,杨若东发现“问题被解答了”,他立刻又买下二十本送给同事。

  一开篇,这本书就以芬兰游戏公司 Supercell 为例,认为它能以几个人的小团队在几周内开发出一款新游戏,得益于把游戏开发过程中公共通用的素材和算法做了沉淀。

  随即,这本书说到阿里巴巴从 2009 年成立“共享事业部”,到 2015 年启动“中台战略”的历史,不仅从道理上说了做中台的好处,还举出了实例:阿里仅用 1 个半月上线了团购平台,也就是聚划算,而同类团购平台“投入的研发资源可能是阿里的几十倍,准备时间可能是阿里的几倍”,“最大的功劳就来自于当时已经正常运转两年的阿里共享服务体系”。


图片来源:《企业 IT 架构转型之道》

  “中台”恍若一剂支撑新业务快速崛起的良方,同时还能省钱。在互联网公司呼号红利到顶和减员提效的 2019 年,一时蔚然成风。

  “中台”也被视作字节跳动能成为“App 工厂”的基础:一位 IT 领域资深人士告诉 36 氪,技术出身的张一鸣,创立今日头条时就融入了中台架构;36 氪也在 2019 年 3 月独家报道,字节跳动搭建了“直播中台”,将三个产品的直播技术和运营团队抽出和合并,来支撑它旗下的所有直播业务。

  腾讯在 2019 年 5 月的入局,宣布将进一步开放数据中台和技术中台,更是将这一波“中台崇拜”推进至高潮。

  “中台”随之在 2019 年成为 VC 们下注的赛道:不少投资人相信,大量传统公司没有 IT 能力自建中台,第三方服务商就有了市场。2019 年第四季度,三家中台服务商相继宣布获得融资:滴普科技完成 3500 万美元 A 轮融资、云徙科技完成 3.5 亿元 B 轮融资、袋鼠云完成数亿元 B 轮融资。

  “但我们现在都在反思:中台把客户的期望值拉得太高了。”一位阿里云前高管对 36 氪说。中台既不是一套软件,也不是一套服务器,而是一种理念、一套方法论,这最终导致客户“接不住”。

  第三方公司的销售为了拿下客户,也会夸大中台的效果。云徙前技术骨干周宏告诉 36 氪,他发现,销售去客户那讲 PPT 的时候,“什么都承诺,什么东西都有,”造成一种中台能“包治百病”的感觉。

  这就造成了一个极为吊诡的现象:一时间大家都在说中台,似乎什么都可以往“中台”里装。有业务中台、数据中台、技术中台、安全中台、AI 中台……从来没有一个“风口”,像中台这样说不清、道不明。

  一、真假中台

  迷惑,是许多人入局中台之初的关键词。

  周宏就是如此。他刚加入云徙科技不久、在一名架构师拜访客户时,架构师拿出一套 PPT,在客户面前口若悬河地讲了几个小时后,周宏与客户一样,都被这个 PPT “迷倒了”。

  “我当时看完之后,觉得这辈子的技术大概是白干了。”周宏对 36 氪说。 

  周宏在互联网巨头做过大项目、带过超百人的技术团队,从业近 20 年,可眼前这份漂亮的 PPT 里,谈到的技术方案让他闻所未闻,他打定主意要跟这位同事好好请教。从客户那里出来,周宏满是敬佩地说:“X哥,以后要跟你好好学习,你技术太牛了。”

  对方的回复让周宏感到震惊:“我没干过技术啊”。“那你刚才讲的东西,我觉得都很深奥。”周宏不解。

  “哦,这些都是我这里抄一点,那里抄一点,最后合起来的。”对方解释说。

  周宏向 36 氪展示了一个类似的 PPT,在 PPT 第二页“茅台云商平台战略构想”中,几乎聚合了所有时下的热门互联网理念:O2O、B2B、B2C、众筹、物联网、金融服务、区块链……


周宏向 36 氪展示“无所不能”的中台  图片由受访者提供

  “看到这里很容易被唬住,你会觉得这套方案简直无所不能。”周宏说。但这显然不现实。

  在“中台”萌芽的早期,没人知道“中台”怎么干,那些掉进“中台”迷宫的企业都有一个共同点:为做而做,缺乏清晰目标。

  被问到茅台的“中台”项目目标是什么时,周宏回答说,正是因为“目标不清楚,所以(项目)做了很久。”

  “你说我们要不要做个中台?”地产信息化服务商“明源云”的副总裁童继龙时常被这么问,发问的往往是手里握有百亿项目的地产行业高管。“只要是提出这个问题的,大多是看到别人做了,自己着急,也想跟风做一个。”

  但客户要赶上趋势,服务商想挣钱,所有人为了一个概念蜂拥而上。但真做起来,才往往发现无从下手。

  一家炼油厂和云徙碰出的一个场景是:当用户去加油站加油,“中台”可以告诉油厂,用户加了多少油;加油站还剩多少油,以便油厂规划生产和销售策略。但真去实地考察后才发现,油厂归油厂,加油站归属于中石化,炼油厂其实拿不到加油站的数据。

  为了跑通这一场景,云徙和炼油厂开了半个多月的会,还在方案里加入了公众号、小程序,最后还是无济于事。“这就是个听起来很美、但实际上没用的场景,因为根本没法产品化。”

  更让人恼火的是,中台真的实施起来,出人意料地贵,也出人意料地耗费时间。

  不同于通常只涉及一个部门的 SaaS 软件项目,由于强调“打通”,中台项目往往意味者要跟所有部门梳理业务,所以耗费人力特别多,而人力成本是导致“中台”项目花钱最凶的部分。

  以云徙为例,多位员工告诉 36 氪,他们给客户的报价大概是 3000 元左右/人/天;以茅台项目为例,50 位员工进驻茅台,一天就是 15 万的人头费,何况茅台项目延期了一年。(备注:“人/天”费用只存在于项目合同期内,项目延期后甲方就不再付费,乙方则需支付违约金。)

  在云徙内部有“三大战役”一说,指的是它早期重要的三家客户:茅台、珠江啤酒、以及日化直销公司“如新”。据 36 氪了解,三家公司签约金额都在千万以上,且都出现了项目延期的情况。其中,茅台延期近两年、如新一期项目延期近 10 个月。

  周宏记得,为了让客户签下“交付确认书”,一位销售曾传授“经验”:在下雪天的时候,只穿一件单衣在客户楼下站着,“最好冻得发抖”,等客户出来的时候再去签约。

  这也是为什么茅台会大发雷霆,CIO 们会因为盲目上中台而“下台”。

  “问题严重的话,一个是花钱的 CIO,一个是赚钱的业务负责人,你觉得老板会怎么取舍?”一位技术负责人对 36 氪说。

  在脑子一热上中台之前,其实每家企业都应该先问一句自己:你真的需要中台吗?

  在此之前还有一个更基础的问题:中台究竟是什么?

  几乎很难在业界得到一条关于中台的恒定解释,但有一条关键标准:是否能够复用。

  联想的会议上,当下属汇报中台进展有多么顺利的时候,首席信息官 Arthur Hu 提出了质疑:“现在有这么多中台服务,面上貌似挺好的,但是少一块信息:调用中台的服务数量是多少?”通过调用次数判断中台的利用效率,是联想 IT 中台的一条 KPI,也是一个明确的方法论。

  这也是百果科技研发总监姚杨的检验标准。他曾接待过推销“中台”产品的销售,对方讲了没几句,姚杨就没了兴致。对方卖的“中台”,是把一个大模块拆成一个个的小中心,业内一般管这叫“微服务”,已经是个老概念。看起来跟中台很像,但是如果这些小中心只是被拆开、但没法复用,就只是“伪中台”。

  重复利用,这才是“中台”的源起。

  因此,被咨询要不要做中台时,童继龙一般会反问对方两个问题:1、你的规模大到足够消化中台吗?2、中台能给你带来什么商业价值?

  往往只有规模够大的企业,才会有多个业务,才会有重复建设的问题。童继龙抛出一个略微惊悚的比喻:“别把中台当作万能药。大象吃这个药,强身健体,蚂蚁吃这个药,一击毙命。

  拿联想来说,它开发过一个“配置器”功能,可以帮消费者、渠道商自行订制 CPU 等电脑组件,但梳理业务的时候联想发现,不同部门里,竟然散落着 5、6 个相似的配置器。那么中台做配置器,对联想来说就是有效的。

  但这也是所谓“业务中台”让人迷惑的地方:每个行业的需求都不一样,能被复用的东西也不一样。联想中台可以做配置器,但这放在其他公司就是莫名其妙。

  业内一般认为,同行业的中台配置相似度较高。这也是第三方服务商们能获得投资的原因:在茅台做完项目后,同样的东西改一改可以卖给洋河大曲,但这只是个假设。即使是阿里巴巴的电商中台,放在其他的电商业务里,比如“茅台云商”,也不一定能用起来。因为每家公司的组织架构、业务逻辑都是千差万别的。

  二、不是 IT 问题,而是组织问题

  从 PPT 回到现实业务,一切需要重新验证。

  云徙给茅台的 PPT 里,一张中台全景图与阿里巴巴沉淀 10 年的中台架构颇为相似,看上去也井井有条——大中台里包裹着“业务”与“数据”两个框,框里分门别类的装着“用户中心”、“会员中心”、“商品中心”……PPT 再往后翻,每个“框”和“中心”怎么建,说明书都写得明明白白。


图片由受访者提供

  “这个架构图画得是好看的,但实施起来,所有东西都不是这样。”周宏说。

  茅台的业务和天猫一样吗?当然不。2017 年 5 月,云徙近三十位员工陆续进驻茅台,他们手捧阿里巴巴的中台心得,以为能照猫画虎地搬进茅台,但很快,他们被一个个从未想到的场景困住了。

  “别说建系统,你连电脑都带不进茅台的仓库。”云徙前高管王峰回忆到。在项目调研初期,他们发现茅台仓储的工人抗拒信息化,只接受用手写单据的形式记录货品。

  不同于一般公司,茅台酒压根不愁卖。几番了解后王峰才明白:管理茅台仓库的人,每个月有一定比例的报损额。“他们可以把这些茅台酒报损后再拿去卖,但如果用电脑扫描进 ERP 的话,就没法操作了。”

  对于云徙落地中台的困难,包志刚对 36 氪表示:在茅台项目进展的高峰,云徙最多投入过 70 人,以基于场景开发需求。

  包志刚也承认,由于中台涉及企业的复杂业务重构,且在项目期间,茅台内部也发生重大组织变化,这对于云徙这样一家需要从 0 到 1 的创业公司来说,的确是巨大挑战。(36 氪注:2018 年 11 月,茅台集团宣布撤销旗下电商公司董事长聂永职务;2019 年 5 月,聂永以涉嫌受贿罪被逮捕;2019 年 12 月,茅台集团宣布电商公司解散。)

  对“中台”一度感到困惑的还有王健。作为软件及咨询公司 ThoughtWorks 的首席架构师,在 2017 年底,当王健为一家国际 500 强公司客户服务中台项目时,他被客户问住了:怎么证明他所展示的中台架构是正确的?王健当时哑口无言,他心里也犯嘀咕:阿里的中台看上去是成功了,可它的成功仅仅是因为中台吗?

  王健将这些困惑都写在了公众号《白话中台战略》系列里。随着他对中台理解的推进,不管怎么写,这个本属于 IT 架构的议题,却越来越离不开“组织”:若将中台纯粹当作技术概念,那么其中的“分布式、微服务,早已是老套的 IT 名词;但阿里中台之所以成功,倚靠的不仅是技术,更是敏捷的组织变革。

  事实确实如此。2015 年末,在张勇提出“大中台、小前台”的组织战略后,阿里巴巴在 2016-2019 年内,进行过 19 次组织调整,当中涉及诸多高管换岗、部门合并,均为拉通中台提供了基础。

  但阿里式的组织调整,对于不少企业来说属于敏感问题。“这好比皇帝对诸侯说,来,明年我要把你们各自的地盘都重新划分一下。”一位咨询公司的分析师给 36 氪举例,“可有几个皇帝敢这么说?一说都造反了,这也是为什么企业在谈中台的时候,很容易避而不谈组织层面。”

  当中台面临“组织”问题,也就是“人”的问题,难度远远超越所谓的 IT、技术与互联网架构。

  一旦遇到“人”的问题,即便是将中台运用得炉火纯青的阿里巴巴,也难有更好的应对之举。

  李小强就吃过客户的闭门羹,他是阿里云智能新零售乳业线的负责人。2019 年初,李小强试图为一家国内一线乳业品牌提供数据中台服务,在与该品牌 CIO 达成合作意向后,他们一起飞往上海,准备和该品牌电商公司的负责人聊聊“怎么把数据打通。”

  可到了会议室,当李小强提出要将电商数据接入整体的数据中台后,遭到了对方的强烈反对,“CIO 和电商负责人拍了桌子”,最后,这位电商负责人摔门离开。

  这种组织内的博弈让李小强始料未及。“你要接对方的数据,就意味着他所有的业务你都可以看到,这是一个版块负责人天生的防御。”李小强对 36 氪说。

  正在联想大刀阔斧进行中台设计的杨若东,很快也遇到了组织变革的难题。

  杨若东向 36 氪回忆起这场改革,在白板上画下三个大方框,分别代表联想的 PC、手机、服务器业务,又在大方框里各自画出小方框,代表销售、研发、供应链等通用职能的 IT 支持团队,而推动中台项目,就要把大方框里的小方框,逐个抽出来再合并为新的 IT 部门。

  “IT 行业都有一个欲望,就是大家即使在重复建设,也要把自己的团队变得更大,这是天性。杨若东对 36 氪说。最终,联想 BT/IT 的 1800 名员工还是完成了这场调整。杨若东在白板上画下一条长长的线——“2017.09-2019.04”,这场改革费时近 20 个月。


杨若东画下的联想 BT/IT 部门的改革草图。拍摄:苏建勋

  三、反思中台

  2019 年初,阿里云智能事业群总裁行癫组织内部战略会,参会者为阿里 P9 (资深专家)以上员工与部门负责人。会上,行癫围绕“中台”展开讨论,他提出:“阿里给客户的中台架构,输出的究竟是什么?”

  一位在场的阿里云前高管告诉 36 氪,技术出身、风格务实的行癫认为:一方面,阿里自身的“中台化”仍在探索中,“只完成了 30%”;另外,如果阿里云一味冲在前面做总集成商——客户的特性可能千差万别,总包就要做定制化方案和实施——会透支阿里云的品牌。多位阿里云内部人士向 36 氪承认,现在想以总集成商的身份拿客户,需要部门特批。

  一位与阿里云合作紧密的 IT 厂商发现,目前阿里云正主推“数据中台”而不是“业务中台”,原因是阿里云无法满足所有业务场景,但数据中台的产品更能标准化。

  “更务实,而不是谨慎。”谈及阿里巴巴对于推进中台的态度变化,阿里云战略市场部总经理郭继军对 36 氪说。他认为所谓务实,就是以前不知道水深水浅,不知道中台怎么在行业里应用,经过两年的客户实践后,现在知道能给客户提供的、不能提供的价值分别是什么了。

  阿里巴巴集团 CEO 张勇最近再次提出的警示则是:中台并不适用于每家公司的每个阶段。在独立业务拓展期、突破期,“一定用独立团、独立师、独立旅建制来做”,否则就会变成瓶颈;但发展到一定阶段,出现太多山头时,就要“关停并转、要合并同类项。问管理要效率,取消重复性建设。”

  阿里巴巴的中台就经历过不受待见的日子。钟华在书中曾写到:“共享业务事业部”要同时满足淘宝和天猫的业务支持,就算再怎么加班加点,也很难及时周到地满足两大业务部门的业务需求,员工则是有苦说不出,只能默默流泪。

  百果园的情况如出一辙。

  百果园子公司“百果科技”筹建中台后,为了把中台复用起来,规定:只要涉及前端应用项目开发,必须经过中台系统,否则禁止调用数据库。

  强制复用后,百果园旗下果多美、杰记、超奇等品牌内的会员、订单、交易等功能被统归至中台,当这些品牌自己的 IT 团队需要调取这些功能时,就要先等百果科技的中台部门做出来。

  问题又回到了组织与人性上。“你的系统不是自己写出来的,而是复用别人的,这就需要你把后背交给兄弟们。”沈欣说。

  百果科技 CMO 沈欣告诉 36 氪,为了鼓励部门间的复用,百果科技实行了不少柔性策略,比如免罚机制:如果是因为复用中台导致的宕机、订单丢失等问题,可以免于处罚。“如果不建立这种信任文化,每个人就会把锅扔到中台头上,中台很快就淹没在唾沫里面了。”

  “如果没有得到’一把手’的支持和认可,中台是非常非常难走下去的。郭继军对 36 氪说。

  如何获得“一把手”的支持?换句话说,CEO 和 CIO 们熬过千难万险上了中台,图什么?

  阿里巴巴用近十年的验证给出了初步回答,郭继军说,阿里巴巴的中台支持了集团灵活变阵,如果没有中台,变阵一次,底下的系统要重建一次,这根本无法实现。

  可不是谁都能长成阿里巴巴,大多数企业经营者有着务实的需求。但不同于前台业务,一个“双 11”结束可以讲赚了多少钱,而中台的经济价值,其实很难算出一个数字。做或者不做,有时候就在于 CEO 信或者不信。

  中台如今走到了价值验证的关键路口。

  (据受访者意愿,周宏、王峰为化名。36 氪实习生岳佳彤、淡忠奎对本文亦有贡献。)

Linux内核常见参数的优化

$
0
0

主要是指在Linux系统中针对服务应用而进行的系统内核参数调整,优化没有的标准,根据实际需求优化才是最合适的。

编辑内核配置文件

vim /etc/sysctl.conf     #添加或是修改以下参数
参数及简单说明

net.ipv4.tcp_fin_timeout = 2           #保持在FIN-WAIT-2状态的时间,使系统可以处理更多的连接。此参数值为整数,单位为秒。
net.ipv4.tcp_tw_reuse = 1              #开启重用,允许将TIME_WAIT socket用于新的TCP连接。默认为0,表示关闭。
net.ipv4.tcp_tw_recycle = 1            #开启TCP连接中TIME_WAIT socket的快速回收。默认值为0,表示关闭。
net.ipv4.tcp_syncookies = 1            #开启SYN cookie,出现SYN等待队列溢出时启用cookie处理,防范少量的SYN攻击。默认为0,表示关闭。
net.ipv4.tcp_keepalive_time = 600      #keepalived启用时TCP发送keepalived消息的拼度。默认位2小时。
net.ipv4.tcp_keepalive_probes = 5      #TCP发送keepalive探测以确定该连接已经断开的次数。根据情形也可以适当地缩短此值。
net.ipv4.tcp_keepalive_intvl = 15      #探测消息发送的频率,乘以tcp_keepalive_probes就得到对于从开始探测以来没有响应的连接杀除的时间。默认值为75秒,也就是没有活动的连接将在大约11分钟以后将被丢弃。对于普通应用来说,这个值有一些偏大,可以根据需要改小.特别是web类服务器需要改小该值。
net.ipv4.ip_local_port_range = 1024 65000 #指定外部连接的端口范围。默认值为32768 61000。
net.ipv4.tcp_max_syn_backlog = 262144  #表示SYN队列的长度,预设为1024,这里设置队列长度为262 144,以容纳更多的等待连接。
net.ipv4.tcp_max_tw_buckets =5000      #系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数值将立刻被清楚并输出警告信息。默认值为180000。对于squid来说效果不是很大,但可以控制TIME_WAIT套接字最大值,避免squid服务器被拖死。 
net.ipv4.tcp_syn_retries = 1           #表示在内核放弃建立连接之前发送SYN包的数量。
net.ipv4.tcp_synack_retries = 1        #设置内核放弃连接之前发送SYN+ACK包的数量。
net.core.somaxconn = 16384             #定义了系统中每一个端口最大的监听队列的长度, 对于一个经常处理新连接的高负载 web服务环境来说,默认值为128,偏小。
net.core.netdev_max_backlog = 16384    #表示当在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许发送到队列的数据包的最大数量。
net.ipv4.tcp_max_orphans = 16384       #表示系统中最多有多少TCP套接字不被关联到任何一个用户文件句柄上。如果超过这里设置的数字,连接就会复位并输出警告信息。这个限制仅仅是为了防止简单的DoS攻击。此值不能太小。 
生效配置

sysctl -p

作者:kalid
链接:https://www.jianshu.com/p/3096a8e6a36f
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CC攻击原理及防范方法和如何防范CC攻击

$
0
0

一、 CC攻击的原理: 

  CC攻击的原理就是攻击者控制某些主机不停地发大量数据包给对方服务器造成服务器资源耗尽,一直到宕机崩溃。CC主要是用来消耗服务器资源的,每个人都有这样的体验:当一个网页访问的人数特别多的时候,打开网页就慢了,CC就是模拟多个用户(多少线程就是多少用户)不停地进行访问那些需要大量数据操作(就是需要大量CPU时间)的页面,造成服务器资源的浪费,CPU长时间处于100%,永远都有处理不完的连接直至就网络拥塞,正常的访问被中止。

二、CC攻击的种类:   

CC攻击的种类有三种,直接攻击,代理攻击,僵尸网络攻击,直接攻击主要针对有重要缺陷的 WEB 应用程序,一般说来是程序写的有问题的时候才会出现这种情况,比较少见。僵尸网络攻击有点类似于 DDOS 攻击了,从 WEB 应用程序层面上已经无法防御,所以代理攻击是CC 攻击者一般会操作一批代理服务器,比方说 100 个代理,然后每个代理同时发出 10 个请求,这样 WEB 服务器同时收到 1000 个并发请求的,并且在发出请求后,立刻断掉与代理的连接,避免代理返回的数据将本身的带宽堵死,而不能发动再次请求,这时 WEB 服务器会将响应这些请求的进程进行队列,数据库服务器也同样如此,这样一来,正常请求将会被排在很后被处理,就象本来你去食堂吃饭时,一般只有不到十个人在排队,今天前面却插了一千个人,那么轮到你的机会就很小很小了,这时就出现页面打开极其缓慢或者白屏。

三、CC攻击与DDOS的区别

       1) 什么是DDoS攻击?

DDoS攻击就是分布式的拒绝服务攻击,DDoS攻击手段是在传统的DoS攻击基础之上产生的一类攻击方式。单一的DoS攻击一般是采用一对一方式的,随着计算机与网络技术的发展,DoS攻击的困难程度加大了。于是就产生了DDoS攻击,它的原理就很简单:计算机与网络的处理能力加大了10倍,用一台攻击机来攻击不再能起作用,那么DDoS就是利用更多的傀儡机来发起进攻,以比从前更大的规模来进攻受害者。常用的DDoS软件有:LOIC

在这里补充两点:第一就是DDOS攻击不仅能攻击计算机,还能攻击路由器,因为路由器是一台特殊类型的计算机;第二是网速决定攻击的好和快,比如说,如果你一个被限制网速的环境下,它们的攻击效果不是很明显,但是快的网速相比之下更加具有攻击效果。

        2)什么是CC攻击?

CC攻击全称Challenge Collapsar,中文意思是挑战黑洞,因为以前的抵抗DDoS攻击的安全设备叫黑洞,顾名思义挑战黑洞就是说黑洞拿这种攻击没办法

   3)两者区别

DDoS是针对IP的攻击,而CC攻击的是服务器资源。

四、CC攻击的变异品种 慢速攻击

  1)什么是慢速攻击

一说起慢速攻击,就要谈谈它的成名历史了。HTTP Post慢速DoS攻击第一次在技术社区被正式披露是2012年的OWASP大会上,由Wong Onn Chee 和 Tom Brennan共同演示了使用这一技术攻击的威力。

这个攻击的基本原理如下:对任何一个开放了HTTP访问的服务器HTTP服务器,先建立了一个连接,指定一个比较大的content-length,然后以非常低的速度发包,比如1-10s发一个字节,然后维持住这个连接不断开。如果客户端持续建立这样的连接,那么服务器上可用的连接将一点一点被占满,从而导致拒绝服务。

和CC攻击一样,只要Web服务器开放了Web服务,那么它就可以是一个靶子,HTTP协议在接收到request之前是不对请求内容作校验的,所以即使你的Web应用没有可用的form表单,这个攻击一样有效。

在客户端以单线程方式建立较大数量的无用连接,并保持持续发包的代价非常的低廉。实际试验中一台普通PC可以建立的连接在3000个以上。这对一台普通的Web server,将是致命的打击。更不用说结合肉鸡群做分布式DoS了。

鉴于此攻击简单的利用程度、拒绝服务的后果、带有逃逸特性的攻击方式,这类攻击一炮而红,成为众多攻击者的研究和利用对象。
  2)慢速攻击的分类

发展到今天,慢速攻击也多种多样,其种类可分为以下几种:

Slow headers:Web应用在处理HTTP请求之前都要先接收完所有的HTTP头部,因为HTTP头部中包含了一些Web应用可能用到的重要的信息。攻击者利用这点,发起一个HTTP请求,一直不停的发送HTTP头部,消耗服务器的连接和内存资源。抓包数据可见,攻击客户端与服务器建立TCP连接后,每30秒才向服务器发送一个HTTP头部,而Web服务器再没接收到2个连续的\r\n时,会认为客户端没有发送完头部,而持续的等等客户端发送数据。

Slow body:攻击者发送一个HTTP POST请求,该请求的Content-Length头部值很大,使得Web服务器或代理认为客户端要发送很大的数据。服务器会保持连接准备接收数据,但攻击客户端每次只发送很少量的数据,使该连接一直保持存活,消耗服务器的连接和内存资源。抓包数据可见,攻击客户端与服务器建立TCP连接后,发送了完整的HTTP头部,POST方法带有较大的Content-Length,然后每10s发送一次随机的参数。服务器因为没有接收到相应Content-Length的body,而持续的等待客户端发送数据。

Slow read:客户端与服务器建立连接并发送了一个HTTP请求,客户端发送完整的请求给服务器端,然后一直保持这个连接,以很低的速度读取Response,比如很长一段时间客户端不读取任何数据,通过发送Zero Window到服务器,让服务器误以为客户端很忙,直到连接快超时前才读取一个字节,以消耗服务器的连接和内存资源。抓包数据可见,客户端把数据发给服务器后,服务器发送响应时,收到了客户端的ZeroWindow提示(表示自己没有缓冲区用于接收数据),服务器不得不持续的向客户端发出ZeroWindowProbe包,询问客户端是否可以接收数据。

使用较多的慢速攻击工具有:Slowhttptest和Slowloris。   3)哪些服务器易被慢速攻击

慢速攻击主要利用的是thread-based架构的服务器的特性,这种服务器会为每个新连接打开一个线程,它会等待接收完整个HTTP头部才会释放连接。比如Apache会有一个超时时间来等待这种不完全连接(默认是300s),但是一旦接收到客户端发来的数据,这个超时时间会被重置。正是因为这样,攻击者可以很容易保持住一个连接,因为攻击者只需要在即将超时之前发送一个字符,便可以延长超时时间。而客户端只需要很少的资源,便可以打开多个连接,进而占用服务器很多的资源。

经验证,Apache、httpd采用thread-based架构,很容易遭受慢速攻击。而另外一种event-based架构的服务器,比如nginx和lighttpd则不容易遭受慢速攻击。   4)如何防护慢速攻击

Apache服务器现在使用较多的有三种简单防护方式。

mod_reqtimeout:Apache2.2.15后,该模块已经被默认包含,用户可配置从一个客户端接收HTTP头部和HTTPbody的超时时间和最小速率。如果一个客户端不能在配置时间内发送完头部或body数据,服务器会返回一个408REQUEST TIME OUT错误。配置文件如下:

< IfModule mod_reqtimeout.c >

RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500

< /IfModule >

mod_qos:Apache的一个服务质量控制模块,用户可配置各种不同粒度的HTTP请求阈值,配置文件如下:

复制代码
复制代码
< IfModule mod_qos.c >

/# handle connections from up to 100000 different IPs

QS_ClientEntries 100000

/# allow only 50 connections per IP

QS_SrvMaxConnPerIP 50

/# limit maximum number of active TCP connections limited to 256

MaxClients 256

/# disables keep-alive when 180 (70%) TCP connections are occupied

QS_SrvMaxConnClose 180

/# minimum request/response speed (deny slow clients blocking the server, keeping connections open without requesting anything

QS_SrvMinDataRate 150 1200

< /IfModule >
复制代码
复制代码

mod_security:一个开源的WAF模块,有专门针对慢速攻击防护的规则,配置如下:

SecRule RESPONSE_STATUS “@streq 408” “phase:5,t:none,nolog,pass, setvar:ip.slow_dos_counter=+1, expirevar:ip.slow_dos_counter=60, id:’1234123456′”

SecRule IP:SLOW_DOS_COUNTER “@gt 5” “phase:1,t:none,log,drop,

msg:’Client Connection Dropped due to high number of slow DoS alerts’, id:’1234123457′”

传统的流量清洗设备针对CC攻击,主要通过阈值的方式来进行防护,某一个客户在一定的周期内,请求访问量过大,超过了阈值,清洗设备通过返回验证码或者JS代码的方式。这种防护方式的依据是,攻击者们使用肉鸡上的DDoS工具模拟大量http request,这种工具一般不会解析服务端返回数据,更不会解析JS之类的代码。因此当清洗设备截获到HTTP请求时,返回一段特殊JavaScript代码,正常用户的浏览器会处理并正常跳转不影响使用,而攻击程序会攻击到空处。

而对于慢速攻击来说,通过返回验证码或者JS代码的方式依然能达到部分效果。但是根据慢速攻击的特征,可以辅助以下几种防护方式:1、周期内统计报文数量。一个TCP连接,HTTP请求的报文中,报文过多或者报文过少都是有问题的,如果一个周期内报文数量非常少,那么它就可能是慢速攻击;如果一个周期内报文数量非常多,那么它就可能是一个CC攻击。2、限制HTTP请求头的最大许可时间。超过最大许可时间,如果数据还没有传输完成,那么它就有可能是一个慢速攻击。

简单的Nginx防CC方式 

实验

Nginx配置

复制代码
复制代码
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    server {
        #限制每ip每秒不超过20个请求,漏桶数burst为5
        #brust的意思就是,如果第1秒、2,3,4秒请求为19个,
        #第5秒的请求为25个是被允许的。
        #但是如果你第1秒就25个请求,第2秒超过20的请求返回503错误。
        #nodelay,如果不设置该选项,严格使用平均速率限制请求数,
        #第1秒25个请求时,5个请求放到第2秒执行,
        #设置nodelay,25个请求将在第1秒执行。
        limit_req   zone=one  burst=1 nodelay;
    }
}
复制代码
复制代码

上面样本的配置是什么意思呢?

  • $binary_remote_addr 表示:客户端IP地址
  • zone 表示漏桶的名字
  • rate 表示nginx处理请求的速度有多快
  • burst 表示峰值
  • nodelay 表示是否延迟处理请求,还是直接503返回给客户端,如果超出rate设置的情况下。

详细的可以参考官方说明文档:Module ngx_http_limit_req_module

模拟请求

这里我们需要Apache Benchmark这个小工具来生成请求

//1个用户持续100s的时间向服务器发送请求
ab -t 100 -c 1 -vvv http://example.com/

Nginx配置样本一

复制代码
复制代码
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    server {
        limit_req   zone=one  burst=1 nodelay;
    }
}
复制代码
复制代码

ab测试结果如下所示:

数据成功的请求数失败的请求数请求时间每秒成功的请求数
110019438101.1950.98
210017651100.6550.99
39725735100.4240.96
410126791100.0001.01
59819051100.5140.98
平均9921733.2100.5570.98

以上失败的请求在Nginx上生成的错误日志如下显示

复制代码
复制代码
2015/05/09 12:48:57 [error] 6564#0: *2219 limiting requests, excess: 1.273 by zone "one", client: 10.0.2.2, server: example.com, request: "GET / HTTP/1.0", host: "example.com"
2015/05/09 12:48:57 [error] 6564#0: *2220 limiting requests, excess: 1.272 by zone "one", client: 10.0.2.2, server: example.com, request: "GET / HTTP/1.0", host: "example.com"
2015/05/09 12:48:57 [error] 6564#0: *2221 limiting requests, excess: 1.271 by zone "one", client: 10.0.2.2, server: example.com, request: "GET / HTTP/1.0", host: "example.com"
2015/05/09 12:48:57 [error] 6564#0: *2222 limiting requests, excess: 1.270 by zone "one", client: 10.0.2.2, server: example.com, request: "GET / HTTP/1.0", host: "example.com"
2015/05/09 12:48:57 [error] 6564#0: *2223 limiting requests, excess: 1.269 by zone "one", client: 10.0.2.2, server: example.com, request: "GET / HTTP/1.0", host: "example.com"
2015/05/09 12:48:57 [error] 6564#0: *2224 limiting requests, excess: 1.268 by zone "one", client: 10.0.2.2, server: example.com, request: "GET / HTTP/1.0", host: "example.com"
复制代码
复制代码

如上ab测试中如果是失败的请求,nginx的limit_req模块会统一返回503给客户端,浏览器上面显示的是这个样子的。

Nginx配置样本二

在配置二里面,我把burst(峰值)提高到了10

复制代码
复制代码
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    server {
        limit_req   zone=one  burst=10 nodelay;
    }
}
复制代码
复制代码
数据成功的请求数失败的请求数请求时间每秒成功的请求数
111019042100.1441.09
211122271101.7141.09
311118466100.5041.10
411116468101.2851.09
511112770100.5961.10
平均11017803100.7881.09

从数据来看,提高了burst值,明显nginx成功的请求数上去了。

Nginx配置样本三

在样本二的基础上,我们把nodelay去除掉

复制代码
复制代码
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    server {
        limit_req   zone=one  burst=10;
    }
}
复制代码
复制代码
数据成功的请求数失败的请求数请求时间每秒成功的请求数
1960100.2231.09
2980100.2380.97
31000100.7610.99
4960100.0740.95
5970100.0210.96
平均97.40100.2630.97

从这里的数据可以看到将nodelay的参数去掉的话,成功的请求数在100左右而失败的请求数变成0了,为什么呢?

  • 有nodelay参数的时候,nginx正常是及时处理当前的请求的并响应数据给客户端,但是如果超过limit_req_module的限制,那么会统一返回503给客户端。
  • 无nodelay参数的时候,nginx正常是及时处理当前的请求的并响应数据给客户端,但是如果超过limit_req_module的限制,那么会将此此请求缓存「就先这么理解」起来稍后再处理,所以也就不会出现大量的失败请求数了。

存在的问题

虽然用limit_req_module可以一定上的防止CC攻击,但是有误杀概率;国内宽带用户的IP地址已经大量内网化,几百人共享一个IP的可能性是很大的。

五、应用层DDoS的防御理论:

问题模型描述:

每一个页面,都有其资源消耗权重,静态资源,权重较低,动态资源,权重较高。对于用户访问,有如下:

用户资源使用频率=使用的服务器总资源量/s

命题一:对于正常访问的用户,资源使用频率必定位于一个合理的范围,当然会存在大量正常用户共享ip的情况,这就需要日常用户访问统计,以得到忠实用户ip白名单。

命题二:资源使用频率持续异常的,可断定为访问异常的用户。

防御体系状态机:

1.在系统各项资源非常宽裕时,向所有ip提供服务,每隔一段时间释放一部分临时黑名单中的ip成员;

2.在系统资源消耗达到某一阈值时,降低Syn包接受速率,循环:分析最近时间的日志,并将访问异常的ip加入临时黑名单;

3.若系统资源消耗慢慢回降至正常水平,则恢复Syn包接受速率,转到状态1;若目前策略并未有效地控制住系统资源消耗的增长,情况继续恶劣至一极限阈值,转到状态4;

4.最终防御方案,使用忠实用户ip白名单、异常访问ip黑名单策略,其他访问可慢慢放入,直到系统资源消耗回降至正常水平,转到状态1。

上述的防御状态机,对于单个攻击IP高并发的DDOS,变化到状态3时,效果就完全体现出来了,但如果防御状态机进行到4状态,则有如下两种可能:

1.站点遭到了攻击群庞大的、单个IP低并发的DDOS攻击;

2.站点突然间有了很多访问正常的新用户。

六、建议后续工作:

保守:站点应尽快进行服务能力升级。

积极:尽所能,追溯攻击者。

追溯攻击者:

CC:proxy-forward-from-ip

单个IP高并发的DDOS:找到访问异常的、高度可疑的ip列表,exploit,搜集、分析数据,因为一个傀儡主机可被二次攻占的概率很大(但不建议这种方法)

单个IP低并发的DDOS:以前极少访问被攻击站点,但是在攻击发生时,却频繁访问我们的站点,分析日志得到这一部分ip列表

追溯攻击者的过程中,snat与web proxy增加了追踪的难度,如果攻击者采用多个中继服务器的方法,追溯将变得极为困难。

防御者:

1.应对当前系统了如指掌,如系统最高负载、最高数据处理能力,以及系统防御体系的强项与弱点

2.历史日志的保存、分析

3.对当前系统进行严格安全审计

4.上报公安相关部分,努力追溯攻击者

5.网站,能静态,就一定不要动态,可采取定时从主数据库生成静态页面的方式,对需要访问主数据库的服务使用验证机制。

6.防御者应能从全局的角度,迅速及时地发现系统正在处于什么程度的攻击、何种攻击,在平时,应该建立起攻击应急策略,规范化操作,免得在急中犯下低级错误

对历史日志的分析这时将会非常重要,数据可视化与统计学的方法将会很有益处:

1.分析每个页面的平均访问频率

2.对访问频率异常的页面进行详细分析 分析得到ip-页面访问频率

3.得到对访问异常页面的访问异常ip列表

4.对日志分析得到忠实用户IP白名单

5.一般一个页面会关联多个资源,一次对于这样的页面访问往往会同时增加多个资源的访问数,而攻击程序一般不会加载这些它不感兴趣的资源,所以,这也是一个非常好的分析突破点

防御思路

因为CC攻击通过工具软件发起,而普通用户通过浏览器访问,这其中就会有某些区别。想办法对这二者作出判断,选择性的屏蔽来自机器的流量即可。

初级

普通浏览器发起请求时,除了要访问的地址以外,Http头中还会带有Referer,UserAgent等多项信息。遇到攻击时可以通过日志查看访问信息,看攻击的流量是否有明显特征,比如固定的Referer或UserAgent,如果能找到特征,就可以直接屏蔽掉了。

中级

如果攻击者伪造了Referer和UserAgent等信息,那就需要从其他地方入手。攻击软件一般来说功能都比较简单,只有固定的发包功能,而浏览器会完整的支持Http协议,我们可以利用这一点来进行防御。

首先为每个访问者定义一个字符串,保存在Cookies中作为Token,必须要带有正确的Token才可以访问后端服务。当用户第一次访问时,会检测到用户的Cookies里面并没有这个Token,则返回一个302重定向,目标地址为当前页面,同时在返回的Http头中加入set cookies字段,对Cookies进行设置,使用户带有这个Token。

客户端如果是一个正常的浏览器,那么就会支持http头中的set cookie和302重定向指令,将带上正确的Token再次访问页面,这时候后台检测到正确的Token,就会放行,这之后用户的Http请求都会带有这个Token,所以并不会受到阻拦。

客户端如果是CC软件,那么一般不会支持这些指令,那么就会一直被拦在最外层,并不会对服务器内部造成压力。

高级

高级一点的,还可以返回一个网页,在页面中嵌入JavaScript来设置Cookies并跳转,这样被伪造请求的可能性更小

Token生成算法

Token需要满足以下几点要求

1,每个IP地址的Token不同

2, 无法伪造

3, 一致性,即对相同的客户端,每次生成的Token相同

Token随IP地址变化是为了防止通过一台机器获取Token之后,再通过代理服务区进行攻击。一致性则是为了避免在服务器端需要存储已经生成的Token。

推荐使用以下算法生成Token,其中Key为服务器独有的保密字符串,这个算法生成的Token可以满足以上这些要求。

Token = Hash( UserAgent + client_ip + key )

本文主要讲述了DDoS攻击之一的CC攻击工具实现,以及如何防御来自应用层的DDoS攻击的理论总结。接下来的文章,笔者将会实现一个工作于内核态的、具有黑名单功能的防火墙模块,以对应于上述防御状态机中的防火墙单元,它实现了自主地动态内存管理,使用hash表管理ip列表,并可以自定义hash表的modular。

七、 简易CC攻击防御策略 

确定Web服务器正在或者曾经遭受CC攻击,那如何进行有效的防范呢?

(1).取消域名绑定 
  一般cc攻击都是针对网站的域名进行攻击,比如我们的网站域名是“www.abc.com”,那么攻击者就在攻击工具中设定攻击对象为该域名然后实施攻击。 对于这样的攻击我们的措施是取消这个域名的绑定,让CC攻击失去目标。

(2).域名欺骗解析 
  如果发现针对域名的CC攻击,我们可以把被攻击的域名解析到127.0.0.1这个地址上。我们知道127.0.0.1是本地回环IP是用来进行网络测试的,如果把被攻击的域名解析到这个IP上,就可以实现攻击者自己攻击自己的目的,这样他再多的肉鸡或者代理也会宕机,让其自作自受。

(3).更改Web端口 
  一般情况下Web服务器通过80端口对外提供服务,因此攻击者实施攻击就以默认的80端口进行攻击,所以,我们可以修改Web端口达到防CC攻击的目的。运行IIS管理器,定位到相应站点,打开站点“属性”面板,在“网站标识”下有个TCP端口默认为80,我们修改为其他的端口就可以了。

(4).屏蔽IP 
  我们通过命令或在查看日志发现了CC攻击的源IP,就可以在防火墙中设置屏蔽该IP对Web站点的访问,从而达到防范攻击的目的。

转:https://www.cnblogs.com/wpjamer/p/9030259.html


如何防范CC攻击

服务器如何防范CC攻击
CC攻击是DDOS(分布式拒绝服务)的一种,相比其它的DDOS攻击CC似乎更有技术含量一些.这种攻击你见不到虚假IP,见不到特别大的异常流量,但造成服务器无法进行正常连接,听说一条ADSL足以搞掂一台高性能的Web服务器.由此可见其危害性,称其为“Web杀手”也毫不为过.最让站长们忧虑的是这种攻击技术含量低,利用工具和一些IP代理一个初、中级的电脑水平的用户就能够实施攻击.因此,大家有必要了解CC攻击的原理及如果发现CC攻击和对其的防范措施.

  1、攻击原理

  CC攻击的原理就是攻击者控制某些主机不停地发大量数据包给对方服务器造成服务器资源耗尽,一直到宕机崩溃.CC主要是用来攻击页面的,每个人都有这样的体验:当一个网页访问的人数特别多的时候,打开网页就慢了,CC就是模拟多个用户(多少线程就是多少用户)不停地进行访问那些需要大量数据操作(就是需要大量CPU时间)的页面,造成服务器资源的浪费,CPU长时间处于100%,永远都有处理不完的连接直至就网络拥塞,正常的访问被中止.

  2、攻击症状

  CC攻击有一定的隐蔽性,那如何确定服务器正在遭受或者曾经遭受CC攻击呢?我们可以通过以下三个方法来确定.

  (1).命令行法

  一般遭受CC攻击时,Web服务器会出现80端口对外关闭的现象, 因为这个端口已经被大量的垃圾数据堵塞了正常的连接被中止了.我们可以通过在命令行下输入命令netstat -an来查看,如果看到类似如下有大量显示雷同的连接记录基本就可以被CC攻击了:


  …… 
  TCP 192.168.1.3:80 192.168.1.6:2203 SYN_RECEIVED 4 
  TCP 192.168.1.3:80 192.168.1.6:2203 SYN_RECEIVED 4 
  TCP 192.168.1.3:80 192.168.1.6:2203 SYN_RECEIVED 4 
  TCP 192.168.1.3:80 192.168.1.6:2203 SYN_RECEIVED 4 
  TCP 192.168.1.3:80 192.168.1.6:2203 SYN_RECEIVED 4 …… 
  




  其中“192.168.1.6”就是被用来代理攻击的主机的IP,“SYN_RECEIVED”是TCP连接状态标志,意思是“正在处于连接的初始同步状态 ”,表明无法建立握手应答处于等待状态.这就是攻击的特征,一般情况下这样的记录一般都会有很多条,表示来自不同的代理IP的攻击.

(2).批处理法

  上述方法需要手工输入命令且如果Web服务器IP连接太多看起来比较费劲,我们可以建立一个批处理文件,通过该脚本代码确定是否存在CC攻击.打开记事本键入如下代码保存为CC.bat:


@echo off 
  time /t >>log.log 
  netstat -n -p tcp |find “:80”>>Log.log 
  notepad log.log 
  exit 
  上面的脚本的含义是筛选出当前所有的到80端口的连接.当我们感觉服务器异常是就可以双击运行该批处理文件,然后在打开的log.log文件中查看所有的连接.如果同一个IP有比较多的到服务器的连接,那就基本可以确定该IP正在对服务器进行CC攻击.



  (3).查看系统日志

  上面的两种方法有个弊端,只可以查看当前的CC攻击,对于确定Web服务器之前是否遭受CC攻击就无能为力了,此时我们可以通过Web日志来查,因为Web日志忠实地记录了所有IP访问Web资源的情况.通过查看日志我们可以Web服务器之前是否遭受CC攻击,并确定攻击者的IP然后采取进一步的措施.

  Web日志一般在C:\WINDOWS\system32\LogFiles\HTTPERR目录下,该目录下用类似httperr1.log的日志文件,这个文件就是记录Web访问错误的记录.管理员可以依据日志时间属性选择相应的日志打开进行分析是否Web被CC攻击了.(图3)  


 默认情况下,Web日志记录的项并不是很多,我们可以通过IIS进行设置,让Web日志记录更多的项以便进行安全分析.其操作步骤是:

  “开始→管理工具”打开“Internet信息服务器”,展开左侧的项定位到到相应的Web站点,然后右键点击选择“属性”打开站点属性窗口,在“网站”选项卡下点击“属性”按钮,在“日志记录属性”窗口的“高级”选项卡下可以勾选相应的“扩展属性”,以便让Web日志进行记录.比如其中的“发送的字节数”、“接收的字节数”、“所用时间”这三项默认是没有选中的,但在记录判断CC攻击中是非常有用的,可以勾选.另外,如果你对安全的要求比较高,可以在“常规”选项卡下对“新日志计划”进行设置,让其“每小时”或者“每一天”进行记录.为了便于日后进行分析时好确定时间可以勾选“文件命名和创建使用当地时间”.



  3、CC攻击防御策略

  确定Web服务器正在或者曾经遭受CC攻击,那如何进行有效的防范呢?笔者依据个人经验,提供如下防御措施.

  (1).取消域名绑定

  一般cc攻击都是针对网站的域名进行攻击,比如我们的网站域名是“www.isbese.net”,那么攻击者就在攻击工具中设定攻击对象为该域名然后实施攻击.

  对于这样的攻击我们的措施是在IIS上取消这个域名的绑定,让CC攻击失去目标.具体操作步骤是:打开“IIS管理器”定位到具体站点右键“属性”打开该站点的属性面板,点击IP地址右侧的“高级”按钮,选择该域名项进行编辑,将“主机头值”删除或者改为其它的值(域名). 



  笔者实例模拟测试,取消域名绑定后Web服务器的CPU马上恢复正常状态,通过IP进行访问连接一切正常.但是不足之处也很明显,取消或者更改域名对于别人的访问带来了不变,另外,对于针对IP的CC攻击它是无效的,就算更换域名攻击者发现之后,他也会对新域名实施攻击. (2).域名欺骗解析

  如果发现针对域名的CC攻击,我们可以把被攻击的域名解析到127.0.0.1这个地址上.我们知道127.0.0.1是本地回环IP是用来进行网络测试的,如果把被攻击的域名解析到这个IP上,就可以实现攻击者自己攻击自己的目的,这样他再多的肉鸡或者代理也会宕机,让其自作自受.

  另外,当我们的Web服务器遭受CC攻击时把被攻击的域名解析到国家有权威的政府网站或者是网警的网站,让其网警来收拾他们.

  现在一般的Web站点都是利用类似“新网”这样的服务商提供的动态域名解析服务,大家可以登录进去之后进行设置.

  (3).更改Web端口

  一般情况下Web服务器通过80端口对外提供服务,因此攻击者实施攻击就以默认的80端口进行攻击,所以,我们可以修改Web端口达到防CC攻击的目的.运行IIS管理器,定位到相应站点,打开站点“属性”面板,在“网站标识”下有个TCP端口默认为80,我们修改为其他的端口就可以了.

  (4).IIS屏蔽IP

  我们通过命令或在查看日志发现了CC攻击的源IP,就可以在IIS中设置屏蔽该IP对Web站点的访问,从而达到防范IIS攻击的目的.在相应站点的“属性”面板中,点击“目录安全性”选项卡,点击“IP地址和域名现在”下的“编辑”按钮打开设置对话框.在此窗口中我们可以设置“授权访问”也就是“白名单”,也可以设置“拒绝访问”即“黑名单”.比如我们可以将攻击者的IP添加到“拒绝访问”列表中,就屏蔽了该IP对于Web的访问.

(5).IPSec封锁

  IPSec是优秀的系统防火墙,在排除其他还有别的类型的DDOS攻击时,针对CC攻击可以用设置IP策略来对付攻击.以219.128.*.43这个IP为例子,笔者实际操作对该IP的访问封锁.

  第一步:“开始→管理工具”,打开“本地安全设置”,右键点击“IP安全策略,在本地机器”选择“创建IP安全策略”,然后点击“下一步”,输入策略“名称”和“描述”.然后默认一路“下一步”创建了一个名为“封CC攻击”的IPSec策略.

  第二步:右键点击“IP安全策略,在本地机器”选择“管理IP筛选器表和筛选器操作”,在打开的窗口中点“添加”,在“IP 筛选器列表”窗口添人同第一步的名称和描述信息.取消“使用添加向导”的勾选,然后点击“添加”.在“IP 筛选器 属性”窗口的“地址”选项下设置“源地址”为“192.168.1.6”,目标地址为“我的IP地址”,取消对“镜像”的勾选;点击“协议”选项卡,设置“协议类型”为“TCP”,设置“协议端口”为“从任意端口”到“此端口80”最后确定退出. 

 第三步:在“新规则 属性”窗口中点选刚才创建的“封CC攻击”规则,点击“筛选器操作”选项卡下的“添加”,点选“安全措施”下的“阻止”,在“常规”选项卡下为该筛选器命名为“阻止CC攻击”然后确定退出.

  第四步:点选刚才创建的“阻止CC攻击”筛选器,一路“确定”退出IP策略编辑器,可以看到在组策略窗口的中创建成功一个名为“封CC攻击”的策略,然后右键点击该策略选择“指派”.这样就实现了对该IP的封锁.

 (6).防火墙

  除了利用上述方法外,还可以通过第三方的防火墙进行防范,打开防护墙创建相应防火墙规则就可以了,笔者以天网防火墙为例进行演示.

  打开天网防火墙进入“IP规则管理”窗口,点击“增加规则”,然后输入规则的名称、描述等信息.数据包协议类型选择“TCP”,数据包方向为“接收”,对方IP地址为“指定地址”然后输入该IP地址,本地端口勾选“已授权程序开放的端口”,对方端口不填表示所有端口,TCP标志位勾选“SYN”,当满足上面条件是选择“拦截”,同时还勾选“记录”、“警告”、“发声”.最后“确定”退出,点“保存规则”应该该规则即可.

  总结:本文以Web服务器为例讲述了如何判断CC攻击以及如何防CC攻击.其实,除了Web服务器对于其他的服务器也可以进行类似的防CC攻击设置.


DDoS攻击相信大家多多少少都听过一点,网络上各种D阔、C阔,天天打这个打那个,到处接单,说自己能打多少流量,打死了就发群上问别人,死了没,死了没???

那么DDoS攻击的原理到底是什么呢?DDoS全称:分布式拒绝服务(DDoS:Distributed Denial of Service)。信息安全的三要素——“保密性”、“完整性”和“可用性”中,拒绝服务攻击,针对的目标正是“可用性”。该攻击方式利用目标系统网络服务功能缺陷或者直接消耗其系统资源,使得该目标系统无法提供正常的服务。拒绝服务攻击问题一直得不到合理的解决,目前还是世界性难题,究其原因是因为这是由于网络协议本身的安全缺陷造成的,(这里不细说,详情自行百度)从而拒绝服务攻击也成为了攻击者的终极手法。攻击者进行拒绝服务攻击,实际上让服务器实现两种效果:一是迫使服务器的缓冲区满,不接收新的请求;二是使用IP欺骗,迫使服务器把合法用户的连接复位,影响合法用户的连接。

那么CC攻击的原理又是什么呢,我们经常听别人说,接D单、CC单,CC不也是拒绝服务攻击吗?和DDOS两者有什么区别呢?很多人都分不清楚DDoS攻击和CC攻击的区别。CC攻击全称Challenge Collapsar,中文意思是挑战黑洞,因为以前的抵抗DDoS攻击的安全设备叫黑洞,顾名思义挑战黑洞就是说黑洞拿这种攻击没办法,新一代的抗DDoS设备已经改名为ADS(Anti-DDoS System),基本上已经可以完美的抵御CC攻击了。CC攻击的原理是通过代理服务器或者大量肉鸡模拟多个用户访问目标网站的动态页面,制造大量的后台数据库查询动作,消耗目标CPU资源,造成拒绝服务。CC不像DDoS可以用硬件防火墙来过滤攻击,CC攻击本身的请求就是正常的请求。我们都知道网站的页面有静态和动态之分,动态网页是需要与后台数据库进行交互的,比如一些论坛用户登录的时候需要去数据库查询你的等级、权限等等,当你留言的时候又需要查询权限、同步数据等等,这就消耗很多CPU资源,造成静态网页能打开,但是需要和数据库交互的动态网页打开慢或者无法打开的现象。这种攻击方式相对于前两种实现要相对复杂一些,但是防御起来要简单的多,提供服务的企业只要尽量少用动态网页并且让一些操作提供验证码就能抵御一般的CC攻击。

这里能看出来DDoS和CC的区别,DDoS攻击打的是网站的服务器,而CC攻击是针对网站的页面攻击的,用术语来说就是,一个是WEB网络层拒绝服务攻击(DDoS),一个是WEB应用层拒绝服务攻击(CC),网络层就是利用肉鸡的流量去攻击目标网站的服务器,针对比较本源的东西去攻击,服务器瘫痪了,那么运行在服务器上的网站肯定也不能正常访问了。而应用层就是我们用户看得到的东西,就比如说网页,CC攻击就是针对网页来攻击的,CC攻击本身是正常请求,网站动态页面的正常请求也会和数据库进行交互的,当这种”正常请求”达到一种程度的时候,服务器就会响应不过来,从而崩溃。每次双十一,在大家都忙着准备抢购商品的时候,各大电商平台的机房往往是灯火通明,紧张观察一切动态,各种流量清洗设备,软件硬件都用上了,就是怕到时候服务器崩掉了,那损失可不止一点,电商平台在这方面的投入资金也是比较大的。双十一前夕曾有人笑说, xxxx年最大的DDOS攻击即将来临。如何联系我:【我的公司】www.xinzhenkj.com(信真科技)【技术咨询】www.laohuzx.com 【万里虎】www.bravetiger.cn (团队博客) 【QQ】3396726884

图书购买京东链接***微信小程序商城开发实战***


CentOS7快速从vim7升到vim8

$
0
0
rpm -Uvh http://mirror.ghettoforge.org/distributions/gf/gf-release-latest.gf.el7.noarch.rpm
rpm --import http://mirror.ghettoforge.org/distributions/gf/RPM-GPG-KEY-gf.el7
yum -y remove vim-minimal vim-common vim-enhanced sudo
yum -y --enablerepo=gf-plus install vim-enhanced sudo

使用acme.sh脚本申请Let’s Encrypt 泛域名SSL证书

$
0
0

安装acme.sh

以下命令请在Linux系统执行,root和普通用户均可安装:

 #安装

curl  https://get.acme.sh | sh

#让alias生效

source ~/.bashrc 

设置DNS API

目前泛域名证书仅支持DNS验证,acme.sh通过DNS提供商的API自动完成操作,因此需要先设置DNS API,以CloudXNS为例。

使用acme.sh脚本申请Let’s Encrypt 泛域名SSL证书-技术宅

在CloudXNS后台 – 用户中心 – API管理可以看到API KEY/SECRET KEY,如果没有请自行创建并记录下来。

输入下面的命令导入密钥(CloudXNS),注意不同的DNS,导入的参数不一样,具体您可以参考:dnsapi

export CX_Key="1234"export CX_Secret="sADDsdasdgdsf"
  • CX_Key:对应CloudXNS API KEY
  • CX_Secret:对应CloudXNS SECRET KEY

其它常用DNS API设置

CloudFlare

#导入密钥export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"export CF_Email="xxxx@sss.com"#申请证书acme.sh --issue --dns dns_cf -d example.com -d www.example.com

腾讯/DNSPod(国内版)

#导入密钥export DP_Id="1234"export DP_Key="sADDsdasdgdsf"#申请证书acme.sh --issue --dns dns_dp -d example.com -d www.example.com

阿里云

 #导入密钥

export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"

export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"

#申请证书

acme.sh --issue --dns dns_ali -d example.com -d www.example.com

 

更多DNS API设置请参考:https://github.com/Neilpang/acme.sh/tree/master/dnsapi 

签发泛域名证书

以CloudXNS DNS为例,我们为awk.sh签发一个泛域名证书。

acme.sh --issue --dns dns_cx -d awk.sh -d *.awk.sh
使用acme.sh脚本申请Let’s Encrypt 泛域名SSL证书-技术宅

申请成功后会提示证书绝对路径(如下截图),接下来就可以在WEB服务上部署SSL证书了。

一般来说我们只会用到fullchain.cerdomain.com.key这两个文件

总结

目前Let’s Encrypt已经支持多域名、泛域名,但缺点是有效期依然只有三个月,即使可以设置脚本自动续期,但是管理维护还是有点不便。推荐大家使用一键包,这样大家维护起来还是比较方便的。

其实在执行acme.sh的时候,会自动在服务器添加一个crontab,到三个月的时候会自动续签,所以,动手能力不强的推荐大家使用lnmp之类的一键包!

Nginx与安全有关的几个配置

$
0
0

安全无小事,安全防范从nginx配置做起

上一篇文章《Nginx的几个常用配置和技巧》收到了不错的反馈,这里再总结下nginx配置中与安全有关的一些配置

隐藏版本号

http {    server_tokens off;}

经常会有针对某个版本的nginx安全漏洞出现,隐藏nginx版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞

开启HTTPS

server {    listen 443;    server_name ops-coffee.cn;    ssl on;    ssl_certificate /etc/nginx/server.crt;    ssl_certificate_key /etc/nginx/server.key;    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;    ssl_ciphers         HIGH:!aNULL:!MD5;}

ssl on: 开启https

ssl_certificate: 配置nginx ssl证书的路径

ssl_certificate_key: 配置nginx ssl证书key的路径

ssl_protocols: 指定客户端建立连接时使用的ssl协议版本,如果不需要兼容TSLv1,直接去掉即可

ssl_ciphers: 指定客户端连接时所使用的加密算法,你可以再这里配置更高安全的算法

添加黑白名单

白名单配置

location /admin/ {    allow   192.168.1.0/24;    deny    all;}

上边表示只允许192.168.1.0/24网段的主机访问,拒绝其他所有

也可以写成黑名单的方式禁止某些地址访问,允许其他所有,例如

location /ops-coffee/ {    deny   192.168.1.0/24;    allow    all;}

更多的时候客户端请求会经过层层代理,我们需要通过$http_x_forwarded_for来进行限制,可以这样写

set $allow false;if ($http_x_forwarded_for = "211.144.204.2") { set $allow true; }if ($http_x_forwarded_for ~ "108.2.66.[89]") { set $allow true; }if ($allow = false) { return 404; }

添加账号认证

server {    location / {        auth_basic "please input user&passwd";        auth_basic_user_file key/auth.key;    }}

关于账号认证《Nginx的几个常用配置和技巧》文章中已有详细介绍,这里不赘述

限制请求方法

if ($request_method !~ ^(GET|POST)$ ) {    return 405;}

$request_method能够获取到请求nginx的method

配置只允许GET\POST方法访问,其他的method返回405

拒绝User-Agent

if ($http_user_agent ~* LWP::Simple|BBBike|wget|curl) {    return 444;}

可能有一些不法者会利用wget/curl等工具扫描我们的网站,我们可以通过禁止相应的user-agent来简单的防范

Nginx的444状态比较特殊,如果返回444那么客户端将不会收到服务端返回的信息,就像是网站无法连接一样

图片防盗链

location /images/ {    valid_referers none blocked www.ops-coffee.cn ops-coffee.cn;    if ($invalid_referer) {        return  403;    }}

valid_referers: 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为www.ops-coffee.cn或ops-coffee.cn时访问images下的图片资源,否则返回403

当然你也可以给不符合referer规则的请求重定向到一个默认的图片,比如下边这样

location /images/ {    valid_referers blocked www.ops-coffee.cn ops-coffee.cn    if ($invalid_referer) {        rewrite ^/images/.*\.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last;    }}

控制并发连接数

可以通过ngx_http_limit_conn_module模块限制一个IP的并发连接数

http {    limit_conn_zone $binary_remote_addr zone=ops:10m;    server {        listen       80;        server_name  ops-coffee.cn;        root /home/project/webapp;        index index.html;        location / {            limit_conn ops 10;        }        access_log  /tmp/nginx_access.log  main;    }}

limit_conn_zone: 设定保存各个键(例如$binary_remote_addr)状态的共享内存空间的参数,zone=空间名字:大小

大小的计算与变量有关,例如$binary_remote_addr变量的大小对于记录IPV4地址是固定的4 bytes,而记录IPV6地址时固定的16 bytes,存储状态在32位平台中占用32或者64 bytes,在64位平台中占用64 bytes。1m的共享内存空间可以保存大约3.2万个32位的状态,1.6万个64位的状态

limit_conn: 指定一块已经设定的共享内存空间(例如name为ops的空间),以及每个给定键值的最大连接数

上边的例子表示同一IP同一时间只允许10个连接

当有多个limit_conn指令被配置时,所有的连接数限制都会生效

http {    limit_conn_zone $binary_remote_addr zone=ops:10m;    limit_conn_zone $server_name zone=coffee:10m;    server {        listen       80;        server_name  ops-coffee.cn;        root /home/project/webapp;        index index.html;        location / {            limit_conn ops 10;            limit_conn coffee 2000;        }    }}

上边的配置不仅会限制单一IP来源的连接数为10,同时也会限制单一虚拟服务器的总连接数为2000

缓冲区溢出攻击

缓冲区溢出攻击 是通过将数据写入缓冲区并超出缓冲区边界和重写内存片段来实现的,限制缓冲区大小可有效防止

client_body_buffer_size  1K;client_header_buffer_size 1k;client_max_body_size 1k;large_client_header_buffers 2 1k;

client_body_buffer_size: 默认8k或16k,表示客户端请求body占用缓冲区大小。如果连接请求超过缓存区指定的值,那么这些请求实体的整体或部分将尝试写入一个临时文件。

client_header_buffer_size: 表示客户端请求头部的缓冲区大小。绝大多数情况下一个请求头不会大于1k,不过如果有来自于wap客户端的较大的cookie它可能会大于 1k,Nginx将分配给它一个更大的缓冲区,这个值可以在large_client_header_buffers里面设置

client_max_body_size: 表示客户端请求的最大可接受body大小,它出现在请求头部的Content-Length字段, 如果请求大于指定的值,客户端将收到一个”Request Entity Too Large” (413)错误,通常在上传文件到服务器时会受到限制

large_client_header_buffers 表示一些比较大的请求头使用的缓冲区数量和大小,默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,请求字段不能大于一个缓冲区大小,如果客户端发送一个比较大的头,nginx将返回”Request URI too large” (414),请求的头部最长字段不能大于一个缓冲区,否则服务器将返回”Bad request” (400)

同时需要修改几个超时时间的配置

client_body_timeout   10;client_header_timeout 10;keepalive_timeout     5 5;send_timeout          10;

client_body_timeout: 表示读取请求body的超时时间,如果连接超过这个时间而客户端没有任何响应,Nginx将返回”Request time out” (408)错误

client_header_timeout: 表示读取客户端请求头的超时时间,如果连接超过这个时间而客户端没有任何响应,Nginx将返回”Request time out” (408)错误

keepalive_timeout: 参数的第一个值表示客户端与服务器长连接的超时时间,超过这个时间,服务器将关闭连接,可选的第二个参数参数表示Response头中Keep-Alive: timeout=time的time值,这个值可以使一些浏览器知道什么时候关闭连接,以便服务器不用重复关闭,如果不指定这个参数,nginx不会在应Response头中发送Keep-Alive信息

send_timeout: 表示发送给客户端应答后的超时时间,Timeout是指没有进入完整established状态,只完成了两次握手,如果超过这个时间客户端没有任何响应,nginx将关闭连接

Header头设置

通过以下设置可有效防止XSS攻击

add_header X-Frame-Options "SAMEORIGIN";add_header X-XSS-Protection "1; mode=block";add_header X-Content-Type-Options "nosniff";

X-Frame-Options: 响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套

X-XSS-Protection: 表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面

X-Content-Type-Options: 响应头用来指定浏览器对未指定或错误指定Content-Type资源真正类型的猜测行为,nosniff 表示不允许任何猜测

在通常的请求响应中,浏览器会根据Content-Type来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用MIME-sniffing来猜测资源的响应类型,这是非常危险的

例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果

另外还有几个关于请求头的安全配置需要注意

Content-Security-Policy: 定义页面可以加载哪些资源,

add_header Content-Security-Policy "default-src 'self'";

上边的配置会限制所有的外部资源,都只能从当前域名加载,其中default-src定义针对所有类型资源的默认加载策略,self允许来自相同来源的内容

Strict-Transport-Security: 会告诉浏览器用HTTPS协议代替HTTP来访问目标站点

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

上边的配置表示当用户第一次访问后,会返回一个包含了Strict-Transport-Security响应头的字段,这个字段会告诉浏览器,在接下来的31536000秒内,当前网站的所有请求都使用https协议访问,参数includeSubDomains是可选的,表示所有子域名也将采用同样的规则

nginx 自定义 Server Name 隐藏软件名 自定义版本

$
0
0

How To Customize Your Nginx Server Name

  • src/core/nginx.h
    #define NGINX_VER "MYWS/“ NGINX_VERSION
  • http/ngx_http_special_response.c
    "<hr><center>MYWS</center>” CRLF
  • http/ngx_http_header_filter_module.c
    static u_char ngx_http_server_string[] = "Server: MYWS" CRLF;
  • src/http/v2/ngx_http_v2_filter_module.c
    static const u_char nginx[5] = "\x84\xd1\xcf\x96\xef";

第4点是为http2 做的修改.
字节码生成:

package main

import (
    "fmt"
    "golang.org/x/net/http2/hpack"
)

func main() {
    fmt.Println("nginx", "→", Encode("MYWS"))
    fmt.Println("nginx", "→", Encode("nginx"))
    fmt.Println("apache", "→", Encode("apache"))
    fmt.Println("-----")
    fmt.Println("\\x84\\xaa\\x63\\x55\\xe7", "→", Decode("\x84\xaa\x63\x55\xe7"))
    fmt.Println("\\x84\\x1d\\x63\\x24\\xe5", "→", Decode("\x84\x1d\x63\x24\xe5"))
}

func Encode(s string) string {
    var result string

    hd := hpack.AppendHuffmanString(nil, s)
    hl := hpack.HuffmanEncodeLength(s) | 0x80

    result += RenderByte(byte(hl))

    for _, b := range hd {
        result += RenderByte(b)
    }

    return result
}

func Decode(s string) string {
    data := []byte(s)
    result, _ := hpack.HuffmanDecodeToString(data[1:])
    return result
}

func RenderByte(b byte) string {
    return fmt.Sprintf("\\x%x", b)
}

参考 https://stackoverflow.com/questions/35655448/how-does-this-code-result-in-the-string-nginx0人点赞nginx“小礼物走一走,来简书

作者:未兆谋
链接:https://www.jianshu.com/p/5167cca96837
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

GO设置代理

$
0
0

在 Linux 或 macOS 上面,需要运行下面命令:

Bash (Linux or macOS)

# 启用 Go Modules 功能
export GO111MODULE=on
# 配置 GOPROXY 环境变量
export GOPROXY=https://goproxy.io

或者,可以把上面的命令写到.bashrc.bash_profile文件当中。

在 Windows 上,需要运行下面命令:

PowerShell (Windows)

# 启用 Go Modules 功能
$env:GO111MODULE="on"
# 配置 GOPROXY 环境变量
$env:GOPROXY="https://goproxy.io"

现在,当你构建或运行你的应用时,Go 将会通过 goproxy.io 获取依赖。更多信息请查看 goproxy 仓库。

如果你使用的 Go 版本>=1.13, 你可以通过设置 GOPRIVATE 环境变量来控制哪些私有仓库和依赖(公司内部仓库)不通过 proxy 来拉取,直接走本地,设置如下:

Go version >= 1.13

go env -w GOPROXY=https://goproxy.io,direct
# 设置不走 proxy 的私有仓库,多个用逗号相隔
go env -w GOPRIVATE=*.corp.example.com
Viewing all 222 articles
Browse latest View live