nginx install

Base library

1
2
3
4
[root@localhost ~]# yum -y install epel-release
[root@localhost ~]# yum makecache
[root@localhost ~]# yum -y install gcc gcc-c++ make cmake bison libtool autoconf automake zip unzip bzip2 zlib zlib-devel openssl openssl-devel pcre pcre-devel bison-devel ncurses-devel tcl tcl-devel perl-Digest-SHA1 GeoIP GeoIP-devel gperftools gperftools-devel libatomic_ops-devel gtest gtest-devel glibc-devel unixODBC-devel fop libperl libpython readline readline-devel python2-pip libxml2 libxml2-devel libxslt-devel gd gd-devel jemalloc jemalloc-devel
[root@localhost ~]# yum -y install git lftp ntpdate vim wget telnet dstat tree lrzsz net-tools nmap-ncat

nginx install

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
[root@localhost app]# useradd -s /sbin/nologin nginx

[root@localhost app]# tar xzf nginx-1.10.2.tar.gz
[root@localhost app]# cd nginx-1.10.2
[root@localhost nginx-1.10.2]# ./configure \
> --prefix=/mnt/app/nginx \
> --user=nginx \
> --group=nginx \
> --with-select_module \
> --with-poll_module \
> --with-threads \
> --with-file-aio \
> --with-stream \
> --with-stream_ssl_module \
> --with-http_ssl_module \
> --with-http_stub_status_module \
> --with-http_v2_module \
> --with-http_realip_module \
> --with-http_addition_module \
> --with-http_geoip_module \
> --with-http_gunzip_module \
> --with-http_gzip_static_module \
> --with-http_auth_request_module \
> --with-http_degradation_module \
> --with-google_perftools_module \
> --with-pcre \
> --with-libatomic
[root@localhost nginx-1.10.2]# make
[root@localhost nginx-1.10.2]# make install

[root@localhost app]# mkdir -p /mnt/log/nginx
[root@localhost app]# chown -R nginx.nginx /mnt/log/nginx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
./configure \
--prefix=/mnt/app/nginx \
--user=nginx \
--group=nginx \
--with-select_module \
--with-poll_module \
--with-threads \
--with-file-aio \
--with-stream \
--with-stream_ssl_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_geoip_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_auth_request_module \
--with-http_degradation_module \
--with-google_perftools_module \
--with-pcre \
--with-libatomic

tengine install

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
[root@192 app]# useradd -s /sbin/nologin nginx
[root@192 app]# tar xzf tengine-2.2.0.tar.gz
[root@192 app]# cd tengine-2.2.0
[root@192 tengine-2.2.0]# ./configure \
> --prefix=/mnt/app/nginx \
> --user=nginx \
> --group=nginx \
> --with-rtsig_module \
> --with-select_module \
> --with-poll_module \
> --with-threads \
> --with-file-aio \
> --with-ipv6 \
> --with-force-exit \
> --with-http_v2_module \
> --with-http_realip_module \
> --with-http_addition_module \
> --with-http_xslt_module \
> --with-http_image_filter_module \
> --with-http_geoip_module \
> --with-http_sub_module \
> --with-http_dav_module \
> --with-http_flv_module \
> --with-http_slice_module \
> --with-http_mp4_module \
> --with-http_gunzip_module \
> --with-http_gzip_static_module \
> --with-http_auth_request_module \
> --with-http_concat_module \
> --with-http_random_index_module \
> --with-http_secure_link_module \
> --with-http_degradation_module \
> --with-http_sysguard_module \
> --with-http_addition_module=shared \
> --with-http_xslt_module=shared \
> --with-http_image_filter_module=shared \
> --with-http_geoip_module=shared \
> --with-http_sub_module=shared \
> --with-http_flv_module=shared \
> --with-http_slice_module=shared \
> --with-http_mp4_module=shared \
> --with-http_concat_module=shared \
> --with-http_random_index_module=shared \
> --with-http_secure_link_module=shared \
> --with-http_sysguard_module=shared \
> --with-http_charset_filter_module=shared \
> --with-http_userid_filter_module=shared \
> --with-http_footer_filter_module=shared \
> --with-http_trim_filter_module=shared \
> --with-http_access_module=shared \
> --with-http_autoindex_module=shared \
> --with-http_map_module=shared \
> --with-http_split_clients_module=shared \
> --with-http_referer_module=shared \
> --with-http_rewrite_module=shared \
> --with-http_fastcgi_module=shared \
> --with-http_uwsgi_module=shared \
> --with-http_scgi_module=shared \
> --with-http_memcached_module=shared \
> --with-http_limit_conn_module=shared \
> --with-http_limit_req_module=shared \
> --with-http_empty_gif_module=shared \
> --with-http_browser_module=shared \
> --with-http_user_agent_module=shared \
> --with-http_upstream_hash_module=shared \
> --with-http_upstream_ip_hash_module=shared \
> --with-http_upstream_least_conn_module=shared \
> --with-http_upstream_session_sticky_module=shared \
> --with-http_reqstat_module=shared \
> --with-http_dyups_module \
> --with-mail \
> --with-mail_ssl_module \
> --with-google_perftools_module \
> --with-cpp_test_module \
> --with-backtrace_module \
> --with-pcre \
> --with-pcre-jit \
> --with-libatomic \
> --with-jemalloc
[root@192 tengine-2.2.0]# make -j 2
[root@192 tengine-2.2.0]# make -j 2 install
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
./configure \
--prefix=/mnt/app/nginx \
--user=nginx \
--group=nginx \
--with-rtsig_module \
--with-select_module \
--with-poll_module \
--with-threads \
--with-file-aio \
--with-ipv6 \
--with-force-exit \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_xslt_module \
--with-http_image_filter_module \
--with-http_geoip_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_slice_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_auth_request_module \
--with-http_concat_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_degradation_module \
--with-http_sysguard_module \
--with-http_addition_module=shared \
--with-http_xslt_module=shared \
--with-http_image_filter_module=shared \
--with-http_geoip_module=shared \
--with-http_sub_module=shared \
--with-http_flv_module=shared \
--with-http_slice_module=shared \
--with-http_mp4_module=shared \
--with-http_concat_module=shared \
--with-http_random_index_module=shared \
--with-http_secure_link_module=shared \
--with-http_sysguard_module=shared \
--with-http_charset_filter_module=shared \
--with-http_userid_filter_module=shared \
--with-http_footer_filter_module=shared \
--with-http_trim_filter_module=shared \
--with-http_access_module=shared \
--with-http_autoindex_module=shared \
--with-http_map_module=shared \
--with-http_split_clients_module=shared \
--with-http_referer_module=shared \
--with-http_rewrite_module=shared \
--with-http_fastcgi_module=shared \
--with-http_uwsgi_module=shared \
--with-http_scgi_module=shared \
--with-http_memcached_module=shared \
--with-http_limit_conn_module=shared \
--with-http_limit_req_module=shared \
--with-http_empty_gif_module=shared \
--with-http_browser_module=shared \
--with-http_user_agent_module=shared \
--with-http_upstream_hash_module=shared \
--with-http_upstream_ip_hash_module=shared \
--with-http_upstream_least_conn_module=shared \
--with-http_upstream_session_sticky_module=shared \
--with-http_reqstat_module=shared \
--with-http_dyups_module \
--with-mail \
--with-mail_ssl_module \
--with-google_perftools_module \
--with-cpp_test_module \
--with-backtrace_module \
--with-pcre \
--with-pcre-jit \
--with-libatomic \
--with-jemalloc
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
--prefix=指向安装目录
--sbin-path=指向(执行)程序文件(nginx)
--conf-path=指向配置文件(nginx.conf)
--error-log-path=指向错误日志目录
--pid-path=指向pid文件(nginx.pid)
--lock-path=指向lock文件(nginx.lock)(安装文件锁定,防止安装文件被别人利用,或自己误操作)
--user=指定程序运行时的非特权用户
--group=指定程序运行时的非特权用户组
--builddir=指向编译目录

--with-rtsig_module
启用rtsig模块支持(实时信号)

--with-select_module
启用select模块支持(一种轮询模式,不推荐在高载环境下使用)
--without-select_module
禁用select模块支持(一种轮询模式,不推荐在高载环境下使用)

--with-poll_module
启用poll模块支持(功能与select相同,与select特性相同,为一种轮询模式,不推荐在高载环境下使用)

--with-file-aio
启用file aio支持(一种APL文件传输格式)

--with-ipv6
启用ipv6支持

--with-http_ssl_module
启用ngx_http_ssl_module支持(使支持https请求,需已安装openssl)

--with-http_realip_module
启用ngx_http_realip_module支持(这个模块允许从请求标头更改客户端的IP地址值,默认为关)

--with-http_addition_module
启用ngx_http_addition_module支持(作为一个输出过滤器,支持不完全缓冲,分部分响应请求)

--with-http_xslt_module
启用ngx_http_xslt_module支持(过滤转换XML请求)

--with-http_image_filter_module
启用ngx_http_image_filter_module支持(传输JPEG/GIF/PNG 图片的一个过滤器)
默认为不启用,要用到gd库

--with-http_geoip_module
启用ngx_http_geoip_module支持(该模块创建基于与MaxMind GeoIP二进制文件相配的客户端IP地址的ngx_http_geoip_module变量)

--with-http_sub_module
启用ngx_http_sub_module支持(允许用一些其他文本替换nginx响应中的一些文本)

--with-http_dav_module
启用ngx_http_dav_module支持(增加PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法)
默认情况下为关闭,需编译开启

--with-http_flv_module
启用ngx_http_flv_module支持(提供寻求内存使用基于时间的偏移量文件)

--with-http_gzip_static_module
启用ngx_http_gzip_static_module支持(在线实时压缩输出数据流)

--with-http_random_index_module
启用ngx_http_random_index_module支持(从目录中随机挑选一个目录索引)

--with-http_secure_link_module
启用ngx_http_secure_link_module支持(计算和检查要求所需的安全链接网址)

--with-http_degradation_module
启用ngx_http_degradation_module支持(允许在内存不足的情况下返回204或444码)

--with-http_stub_status_module
启用ngx_http_stub_status_module支持(获取nginx自上次启动以来的工作状态)

--without-http_charset_module
禁用ngx_http_charset_module支持(重新编码web页面,但只能是一个方向--服务器端到客户端,并且只有一个字节的编码可以被重新编码)

--without-http_gzip_module
禁用ngx_http_gzip_module支持(该模块同-with-http_gzip_static_module功能一样)

--without-http_ssi_module
禁用ngx_http_ssi_module支持(该模块提供了一个在输入端处理处理服务器包含文件(SSI)的过滤器,目前支持SSI命令的列表是不完整的)

--without-http_userid_module
禁用ngx_http_userid_module支持(该模块用来处理用来确定客户端后续请求的cookies)

--without-http_access_module
禁用ngx_http_access_module支持(该模块提供了一个简单的基于主机的访问控制.允许/拒绝基于ip地址)

--without-http_auth_basic_module
禁用ngx_http_auth_basic_module(该模块是可以使用用户名和密码基于http基本认证方法来保护你的站点或其部分内容)

--without-http_autoindex_module
禁用disable ngx_http_autoindex_module支持(该模块用于自动生成目录列表,只在ngx_http_index_module模块未找到索引文件时发出请求.)

--without-http_geo_module
禁用ngx_http_geo_module支持(创建一些变量,其值依赖于客户端的IP地址)

--without-http_map_module
禁用ngx_http_map_module支持(使用任意的键/值对设置配置变量)

--without-http_split_clients_module
禁用ngx_http_split_clients_module支持(该模块用来基于某些条件划分用户.条件如:ip地址,报头,cookies等等)

--without-http_referer_module
禁用disable ngx_http_referer_module支持(该模块用来过滤请求,拒绝报头中Referer值不正确的请求)

--without-http_rewrite_module
禁用ngx_http_rewrite_module支持(该模块允许使用正则表达式改变URI,并且根据变量来转向以及选择配置.如果在server级别设置该选项,那么他们将在 location之前生效.如果在location还有更进一步的重写规则,location部分的规则依然会被执行.如果这个URI重写是因为location部分的规则造成的,那么location部分会再次被执行作为新的URI.这个循环会执行10次,然后Nginx会返回一个500错误.)

--without-http_proxy_module
禁用ngx_http_proxy_module支持(有关代理服务器)

--without-http_fastcgi_module
禁用ngx_http_fastcgi_module支持(该模块允许Nginx与FastCGI进程交互,并通过传递参数来控制FastCGI 进程工作.).FastCGI一个常驻型的公共网关接口

--without-http_uwsgi_module
禁用ngx_http_uwsgi_module支持(该模块用来禁用uwsgi协议,uWSGI服务器相关)

--without-http_scgi_module
禁用ngx_http_scgi_module支持(该模块用来启用SCGI协议支持,SCGI协议是CGI协议的替代.它是一种应用程序与HTTP服务接口标准.它有些像FastCGI但他的设计更容易实现)

--without-http_memcached_module
禁用ngx_http_memcached_module支持(该模块用来提供简单的缓存,以提高系统效率)

--without-http_limit_zone_module
禁用ngx_http_limit_zone_module支持(该模块可以针对条件,进行会话的并发连接数控制)

--without-http_limit_req_module
禁用ngx_http_limit_req_module支持(该模块允许你对于一个地址进行请求数量的限制用一个给定的session或一个特定的事件)

--without-http_empty_gif_module
禁用ngx_http_empty_gif_module支持(该模块在内存中常驻了一个1*1的透明GIF图像,可以被非常快速的调用)

--without-http_browser_module
禁用ngx_http_browser_module支持(该模块用来创建依赖于请求报头的值.如果浏览器为modern,则$modern_browser等于modern_browser_value指令分配的值,如果浏览器为old,则$ancient_browser等于 ancient_browser_value指令分配的值;如果浏览器为 MSIE中的任意版本,则 $msie等于1)

--without-http_upstream_ip_hash_module
禁用ngx_http_upstream_ip_hash_module支持(该模块用于简单的负载均衡)

--with-http_perl_module 启用ngx_http_perl_module支持(该模块使nginx可以直接使用perl或通过ssi调用perl)
--with-perl_modules_path= 设定perl模块路径
--with-perl= 设定perl库文件路径

--http-log-path= 设定access log路径
--http-client-body-temp-path= 设定http客户端请求临时文件路径
--http-proxy-temp-path= 设定http代理临时文件路径
--http-fastcgi-temp-path= 设定http fastcgi临时文件路径
--http-uwsgi-temp-path= 设定http uwsgi临时文件路径
--http-scgi-temp-path= 设定http scgi临时文件路径
-without-http 禁用http server功能
--without-http-cache 禁用http cache功能
--with-mail 启用POP3/IMAP4/SMTP代理模块支持
--with-mail_ssl_module 启用ngx_mail_ssl_module支持
--without-mail_pop3_module 禁用pop3协议(POP3即邮局协议的第3个版本,它是规定个人计算机如何连接到互联网上的邮件服务器进行收发邮件的协议。是因特网电子邮件的第一个离线协议标 准,POP3协议允许用户从服务器上把邮件存储到本地主机上,同时根据客户端的操作删除或保存在邮件服务器上的邮件。POP3协议是TCP/IP协议族中的一员,主要用于 支持使用客户端远程管理在服务器上的电子邮件)
--without-mail_imap_module 禁用imap协议(一种邮件获取协议。它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。IMAP协议运行在TCP/IP协议之上, 使用的端口是143。它与POP3协议的主要区别是用户可以不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。)
--without-mail_smtp_module 禁用smtp协议(SMTP即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地。)
--with-google_perftools_module
启用ngx_google_perftools_module支持(调试用,剖析程序性能瓶颈)
--with-cpp_test_module 启用ngx_cpp_test_module支持
--add-module= 启用外部模块支持
--with-cc= 指向C编译器路径
--with-cpp= 指向C预处理路径
--with-cc-opt= 设置C编译器参数(PCRE库,需要指定–with-cc-opt=”-I /usr/local/include”,如果使用select()函数则需要同时增加文件描述符数量,可以通过–with-cc- opt=”-D FD_SETSIZE=2048”指定。)
--with-ld-opt= 设置连接文件参数。(PCRE库,需要指定–with-ld-opt=”-L /usr/local/lib”。)
--with-cpu-opt= 指定编译的CPU,可用的值为: pentium, pentiumpro, pentium3, pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64
--without-pcre 禁用pcre库
--with-pcre 启用pcre库
--with-pcre= 指向pcre库文件目录
--with-pcre-opt= 在编译时为pcre库设置附加参数
--with-md5= 指向md5库文件目录(消息摘要算法第五版,用以提供消息的完整性保护)
--with-md5-opt= 在编译时为md5库设置附加参数
--with-md5-asm 使用md5汇编源
--with-sha1= 指向sha1库目录(数字签名算法,主要用于数字签名)
--with-sha1-opt= 在编译时为sha1库设置附加参数
--with-sha1-asm 使用sha1汇编源
--with-zlib= 指向zlib库目录
--with-zlib-opt= 在编译时为zlib设置附加参数
--with-zlib-asm= 为指定的CPU使用zlib汇编源进行优化,CPU类型为pentium, pentiumpro
--with-libatomic 为原子内存的更新操作的实现提供一个架构
--with-libatomic= 指向libatomic_ops安装目录
--with-openssl= 指向openssl安装目录
--with-openssl-opt 在编译时为openssl设置附加参数
--with-debug 启用debug日志

./configure \
–prefix=/mnt/app/nginx \
–user=nginx \
–group=nginx \
–with-select_module \
–with-poll_module \
–with-file-aio \
–with-http_ssl_module \
–with-http_stub_status_module \
–with-http_v2_module \
–with-http_realip_module \
–with-http_addition_module \
–with-http_geoip_module \
–with-http_gunzip_module \
–with-http_gzip_static_module \
–with-http_auth_request_module \
–with-http_degradation_module \
–with-google_perftools_module \
–with-pcre \
–with-libatomic

make -j 2 && make -j 2 install
kill -USR2 $(cat /mnt/app/nginx/logs/nginx.pid)
kill -QUIT $(cat /mnt/app/nginx/logs/nginx.pid.oldbin)

libxml2 libxml2-devel libxslt-devel gd gd-devel perl-ExtUtils-MakeMaker perl-ExtUtils-Embed lua lua-devel yajl yajl-devel jemalloc jemalloc-devel

nginx status

nginx 开启监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
第一步: 编译Nginx的时候添加参数:--with-http_stub_status_module

第二步: 启用nginx status配置
[root@10 ~]# vim /mnt/app/nginx/conf/nginx.conf
在server{}中添加配置:
server {
... ...
location /nginx_status {
stub_status on;
access_log off;
}
... ...
}

第三步: 重新加载nginx配置文件
[root@10 ~]# /mnt/app/nginx/sbin/nginx -c /mnt/app/nginx/conf/nginx.conf -t
[root@10 ~]# /mnt/app/nginx/sbin/nginx -c /mnt/app/nginx/conf/nginx.conf -s reload

第四步: 打开浏览器访问
http://IP/nginx_status

第五步: 在服务器上操作
curl -s http://IP/nginx_status

nginx 状态参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@10 zabbix_agentd.d]# curl -s http://127.0.0.1/nginx_status
Active connections: 37
server accepts handled requests
2777347 2777347 52733269
Reading: 0 Writing: 4 Waiting: 33

说明:
active connections 表示对后端发起的连接数(活跃)

server accepts handled requests 2777347 2777347 52733269
表示总共处理了2777347个连接,成功创建了2777347次握手,总共处理了52733269请求

Reading: 0 Writing: 4 Waiting: 33
Reading 表示读取客户端的Header信息数.这个操作只是读取头部信息,读取完后马上进入writing状态,因此时间很短.
Writing 表示响应数据到客户端的Header信息数.这个操作不仅读取头部,还要等待服务响应,因此时间比较长
Waiting 表示开启keep-alive后等候下一次请求指令的驻留连接(这个值等于(active – (reading+writing)))

注意:正常情况下waiting数量是比较多的,并不能说明性能差.反而如果reading+writing数量比较多说明服务并发有问题

redis status

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
[root@10 zabbix_agentd.d]# redis-cli -h 10.0.3.35 -p 6379
10.0.3.35:6379> info //查看状态信息命令
# Server
redis_version:3.2.6 //redis版本
redis_git_sha1:00000000 //Git SHA1
redis_git_dirty:0 //Git dirty flag
redis_build_id:c12acbf494828ff2 //redis 版本ID
redis_mode:standalone //redis 单机/集群
os:Linux 3.10.0-123.9.3.el7.x86_64 x86_64 //系统版本
arch_bits:64 //架构
multiplexing_api:epoll //Redis 所使用的事件处理机制
gcc_version:4.8.5 //GCC版本
process_id:19961 //进程ID
run_id:4f988936df5471d496e894057de080150fa2d8d1 //进程运行ID
tcp_port:6379 //监听端口
uptime_in_seconds:4097321 //自 Redis 服务器启动以来,经过的秒数
uptime_in_days:47 //自 Redis 服务器启动以来,经过的天数
hz:10
lru_clock:12372574 //以分钟为单位进行自增的时钟,用于 LRU 管理
executable:/mnt/app/redis/bin/redis-server //执行脚本
config_file:/mnt/app/redis/conf/6379.M.conf //执行配置文件

# Clients
connected_clients:32 //客户端连接数
client_longest_output_list:0 //当前连接的客户端当中,最长的输出列表
client_biggest_input_buf:0 //当前连接的客户端当中,最大输入缓存
blocked_clients:0 //正在等待阻塞命令(BLPOP,BRPOP,BRPOPLPUSH)的客户端的数量

# Memory
used_memory:940850496 //由Redis分配器分配的内存总量,以字节(byte)为单位
used_memory_human:897.26M //以人类可读的格式返回 Redis 分配的内存总量
used_memory_rss:1066475520 //从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致
used_memory_rss_human:1017.07M //以人类可读的格式返回从操作系统的角度分配的内存总量
used_memory_peak:941091472 //Redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human:897.49M //以人类可读的格式返回Redis 的内存消耗峰值
total_system_memory:8204222464 //系统内存大小(字节)
total_system_memory_human:7.64G //以人类可读格式返回系统内存大小
used_memory_lua:37888 //Lua 引擎所使用的内存大小(以字节为单位)
used_memory_lua_human:37.00K //以人类可读格式返回Lua 引擎所使用的内存大小
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:1.13 //used_memory_rss 和 used_memory 之间的比率
mem_allocator:libc //在编译时指定的,Redis所使用的内存分配器:libc,jemalloc,tcmalloc

//补充:
//在理想情况下,used_memory_rss的值应该只比 used_memory 稍微高一点儿
//当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片.内存碎片的比率可以通过 mem_fragmentation_ratio 的值看出
//当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟
//当 Redis 释放内存时,分配器可能会,也可能不会,将内存返还给操作系统
//如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 used_memory 的值可能和操作系统显示的 Redis 内存占用并不一致
//查看 used_memory_peak 的值可以验证这种情况是否发生


# Persistence
loading:0 //是否正在 load of a dump file 的标记
rdb_changes_since_last_save:6590 //自从上次save后rdb change的数量
rdb_bgsave_in_progress:0 //是否正常进行bgsave
rdb_last_save_time:1488767519 //上次save的unix时间戳
rdb_last_bgsave_status:ok //rdb上次bgsave的状态
rdb_last_bgsave_time_sec:6 //上次bgsave的持续时间(s)
rdb_current_bgsave_time_sec:-1 //正在bgsave的持续时间(s)
aof_enabled:1 //aof_enabled:启用AOF
aof_rewrite_in_progress:0 //AOF rewrite operation是否正在进行
aof_rewrite_scheduled:0 //Flag indicating an AOF rewrite operation will be scheduled once the on-going RDB save is complete.
aof_last_rewrite_time_sec:10 //上次AOF rewrite持续时间
aof_current_rewrite_time_sec:-1 //正在进行的AOF rewrite持续时间
aof_last_bgrewrite_status:ok //上次AOF rewrite状态
aof_last_write_status:ok //上次AOF write状态
aof_current_size:2263046107 //AOF当前大小
aof_base_size:523261598 //AOF file size on latest startup or rewrite
aof_pending_rewrite:0 //Flag indicating an AOF rewrite operation will be scheduled once the on-going RDB save is complete.
aof_buffer_length:0 //Size of the AOF buffer
aof_rewrite_buffer_length:0 //Size of the AOF rewrite buffer
aof_pending_bio_fsync:0 //Number of fsync pending jobs in background I/O queue
aof_delayed_fsync:35 //Delayed fsync counter

# Stats
total_connections_received:343061 //服务器已接受的连接请求数量
total_commands_processed:3461425275 //服务器已执行的命令数量
instantaneous_ops_per_sec:937 //服务器每秒钟执行的命令数量
total_net_input_bytes:296078629521 //
total_net_output_bytes:2953563739584
instantaneous_input_kbps:174.82
instantaneous_output_kbps:3536.63
rejected_connections:0 //因为最大客户端数量限制而被拒绝的连接请求数量
sync_full:1
sync_partial_ok:0
sync_partial_err:0
expired_keys:13400113 //因为过期而被自动删除的数据库键数量
evicted_keys:0 //因为最大内存容量限制而被驱逐(evict)的键数量
keyspace_hits:1184692014 //查找数据库键成功的次数
keyspace_misses:17573169 //查找数据库键失败的次数
pubsub_channels:0 //目前被订阅的频道数量
pubsub_patterns:0 //目前被订阅的模式数量
latest_fork_usec:22503 //最近一次 fork() 操作耗费的毫秒数
migrate_cached_sockets:0

# Replication
role:master
connected_slaves:1 //已连接的从服务器数量
slave0:ip=10.0.3.36,port=6379,state=online,offset=217761475716,lag=0 //ID、IP 地址、端口号、连接状态
master_repl_offset:217761633717
repl_backlog_active:1
repl_backlog_size:209715200
repl_backlog_first_byte_offset:217551918518
repl_backlog_histlen:209715200

# CPU
used_cpu_sys:86536.52 //System CPU consumed by the Redis server
used_cpu_user:57295.42 //User CPU consumed by the Redis server(Redis主进程消耗)
used_cpu_sys_children:13930.27 //System CPU consumed by the background processes
used_cpu_user_children:107078.70 //User CPU consumed by the background processes(后台进程消耗(后台包括RDB文件的消耗,master,slave同步产生的消耗等等))

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=224638,expires=92157,avg_ttl=22856280
10.0.3.35:6379> exit

maven install

java install

1
2
3
4
5
6
7
8
[root@localhost app]# tar xzf jdk-8u111-linux-x64.tar.gz
[root@localhost app]# mv jdk1.8.0_111 /mnt/app/java
[root@localhost app]# echo 'JAVA_HOME=/mnt/app/java' | tee /etc/profile.d/java.sh
[root@localhost app]# echo 'JRE_HOME=${JAVA_HOME}/jre' | tee -a /etc/profile.d/java.sh
[root@localhost app]# echo 'CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib' | tee -a /etc/profile.d/java.sh
[root@localhost app]# echo 'export PATH=${JAVA_HOME}/bin:$PATH' | tee -a /etc/profile.d/java.sh
[root@localhost app]# source /etc/profile
[root@localhost app]# java -version

maven install

1
2
3
4
5
[root@localhost app]# tar xzf apache-maven-3.3.9-bin.tar.gz
[root@localhost app]# mv apache-maven-3.3.9 /mnt/app/maven
[root@localhost app]# echo 'MAVEN_HOME=/mnt/app/maven' | tee -a /etc/profile.d/maven.sh
[root@localhost app]# echo 'export PATH=${PATH}:${MAVEN_HOME}/bin' | tee -a /etc/profile.d/maven.sh
[root@localhost app]# source /etc/profile

nexus install

java install

1
2
3
4
5
6
7
8
[root@localhost app]# tar xzf jdk-8u111-linux-x64.tar.gz
[root@localhost app]# mv jdk1.8.0_111 /mnt/app/java
[root@localhost app]# echo 'JAVA_HOME=/mnt/app/java' | tee /etc/profile.d/java.sh
[root@localhost app]# echo 'JRE_HOME=${JAVA_HOME}/jre' | tee -a /etc/profile.d/java.sh
[root@localhost app]# echo 'CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib' | tee -a /etc/profile.d/java.sh
[root@localhost app]# echo 'export PATH=${JAVA_HOME}/bin:$PATH' | tee -a /etc/profile.d/java.sh
[root@localhost app]# source /etc/profile
[root@localhost app]# java -version

maven install

1
2
3
4
5
[root@localhost app]# tar xzf apache-maven-3.3.9-bin.tar.gz
[root@localhost app]# mv apache-maven-3.3.9 /mnt/app/maven
[root@localhost app]# echo 'MAVEN_HOME=/mnt/app/maven' | tee -a /etc/profile.d/maven.sh
[root@localhost app]# echo 'export PATH=${PATH}:${MAVEN_HOME}/bin' | tee -a /etc/profile.d/maven.sh
[root@localhost app]# source /etc/profile

nexus install

  1. 创建用户

    1
    2
    [root@localhost ~]# useradd nexus
    [root@localhost ~]# echo 'cMaxj(^s7:do! | passwd --stdin nexus
  2. nexus 安装

    1
    2
    3
    4
    5
    6
    [root@localhost ~]# tar xzf nexus-3.1.0-04-unix.tar.gz
    [root@localhost ~]# mv nexus-3.1.0-04 /mnt/app/nexus
    [root@localhost ~]# echo 'export NEXUS_HOME=/mnt/app/nexus' | tee /etc/profile.d/nexus.sh
    [root@localhost ~]# echo 'export NEXUS_BIN=${NEXUS_HOME}/bin' | tee -a /etc/profile.d/nexus.sh
    [root@localhost ~]# echo 'export PATH=${NEXUS_BIN}:$PATH' | tee -a /etc/profile.d/nexus.sh
    [root@localhost ~]# source /etc/profile
  3. nexus 修改配置文件

    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
    [root@localhost ~]# vim /mnt/app/nexus/etc/nexus-default.properties
    # Jetty section
    application-port=8081
    application-host=0.0.0.0
    nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml
    nexus-context-path=/
    # Nexus section
    nexus-edition=nexus-pro-edition
    nexus-features=\
    nexus-pro-feature

    [root@localhost ~]# vim /mnt/app/nexus/bin/nexus.rc
    run_as_user="nexus"

    [root@localhost ~]# vim /mnt/app/nexus/bin/nexus.vmoptions
    -Xms1200M
    -Xmx1200M
    -XX:MaxDirectMemorySize=2G
    -XX:+HeapDumpOnOutOfMemoryError
    -XX:+UnlockDiagnosticVMOptions
    -XX:+UnsyncloadClass
    -XX:+LogVMOutput
    -XX:LogFile=/mnt/log/nexus/nexus.log
    -Djava.net.preferIPv4Stack=true
    -Dkaraf.home=.
    -Dkaraf.base=.
    -Dkaraf.etc=etc/karaf
    -Djava.util.logging.config.file=etc/karaf/java.util.logging.properties
    -Dkaraf.data=/mnt/data/nexus
    -Djava.io.tmpdir=/mnt/data/nexus/tmp
    -Dkaraf.startLocalConsole=false
  4. nexus 创建日志和数据目录,并修改文件属性

    1
    2
    3
    [root@localhost ~]# mkdir -p /mnt/{data,log}/nexus
    [root@localhost ~]# mkdir -p /mnt/data/nexus/tmp
    [root@localhost ~]# chown -R nexus.nexus /mnt/{app,data,log}/nexus
  5. nexus 启动

    1
    2
    3
    4
    [root@localhost ~]# su - nexus
    [nexus@localhost ~]$ /mnt/app/nexus/bin/nexus start
    [nexus@localhost ~]$ /mnt/app/nexus/bin/nexus stop
    [nexus@localhost ~]$ /mnt/app/nexus/bin/nexus status
  6. nexus 加入开机启动项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    方式一:
    [root@localhost ~]# vim /etc/rc.local
    su nexus -c "/mnt/app/nexus/bin/nexus start"

    方式二:
    [root@localhost ~]# vim /usr/lib/systemd/system/nexus.service
    [Unit]
    Description=nexus service
    After=network.target

    [Service]
    Type=forking
    ExecStart=/mnt/app/nexus/bin/nexus start
    ExecStop=/mnt/app/nexus/bin/nexus stop
    User=nexus
    Restart=on-abort

    [Install]
    WantedBy=multi-user.target

    [root@localhost ~]# systemctl daemon-reload
    [root@localhost ~]# systemctl enable nexus
    [root@localhost ~]# systemctl start nexus
  7. 通过浏览器打开

    1
    2
    3
    http://192.168.10.75:8081

    默认密码: admin/admin123

datax info

datax[https://github.com/alibaba/DataX/wiki/DataX-Introduction]

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
DataX 是一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等),HDFS,Hive,MaxCompute(原ODPS),HBase,FTP等各种异构数据源之间稳定高效的数据同步功能

设计理念:
为了解决异构数据源同步问题,DataX将复杂的网状的同步链路变成了星型数据链路,DataX作为中间传输载体负责连接各种数据源.当需要接入一个新的数据源的时候,只需要将此数据源对接到DataX,便能跟已有的数据源做到无缝数据同步

datax框架设计:
例如:
Mysql => | ReadPlugin => FrameWork => HDFSWriter | => HDFS

DataX本身作为离线数据同步框架,采用"Framework + plugin"架构构建.
将数据源读取和写入抽象成为Reader/Writer插件,纳入到整个同步框架中:
1.Reader:
Reader为数据采集模块,负责采集数据源的数据,将数据发送给Framework
2.Writer:
Writer为数据写入模块,负责不断向Framework取数据,并将数据写入到目的端
3.Framework:
Framework用于连接reader和writer,作为两者的数据传输通道,并处理缓冲,流控,并发,数据转换等核心技术问题


DataX 3.0 开源版本支持单机多线程模式完成同步作业运行:
1.DataX完成单个数据同步的作业,我们称之为Job,DataX接受到一个Job之后,将启动一个进程来完成整个作业同步过程.DataX Job模块是单个作业的中枢管理节点,承担了数据清理,子任务切分(将单一作业计算转化为多个子Task),TaskGroup管理等功能

2.DataXJob启动后,会根据不同的源端切分策略,将Job切分成多个小的Task(子任务),以便于并发执行.Task便是DataX作业的最小单元,每一个Task都会负责一部分数据的同步工作.

3.切分多个Task之后,DataX Job会调用Scheduler模块,根据配置的并发数据量,将拆分成的Task重新组合,组装成TaskGroup(任务组).每一个TaskGroup负责以一定的并发运行完毕分配好的所有Task,默认单个任务组的并发数量为5

4.每一个Task都由TaskGroup负责启动,Task启动后,会固定启动Reader—>Channel—>Writer的线程来完成任务同步工作

5.DataX作业运行起来之后,Job监控并等待多个TaskGroup模块任务完成,等待所有TaskGroup任务完成后Job成功退出.否则,异常退出,进程退出值非0

例如:
用户提交了一个DataX作业,并且配置了20个并发,目的是将一个100张分表的mysql数据同步到odps里面.
DataX的调度决策思路是:
1.DataXJob根据分库分表切分成了100个Task。
2.根据20个并发,DataX计算共需要分配4个TaskGroup
3.4个TaskGroup平分切分好的100个Task,每一个TaskGroup负责以5个并发共计运行25个Task。

datax windows乱码解决问题[https://github.com/alibaba/DataX/wiki/windows-error-encoding]

datax job

从数据库读取数据写入到hdfs(mysql)

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
{
"job": {
"setting": {
"speed": {
"channel": 1,
"byte": 2048576000
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "$username",
"password": "$password",
"connection": [
{
"querySql": [
"select column1,column2,column3 from tablename;"
],
"jdbcUrl": [
"jdbc:mysql://$IP_addr:$port/$dbname?characterEncoding=utf-8"
]
}
]
}
},
"writer": {
"name": "hdfswriter",
"parameter": {
"defaultFS": "hdfs://IP_addr:9000",
"fileType": "text",
"fileName": "${dbname}_${time}",
"path": "/p/test/tablename/${time}",
"column": [
{
"name": "xx",
"type": "yy"
},
{
"name": "xx",
"type": "yy"
},
{
"name": "xx",
"type": "yy"
},
... ...
],
"writeMode": "append",
"fieldDelimiter": "\t",
"encoding": "utf-8",
"compress": " "
}
}
}
]
}
}

从数据库读取数据写入到数据库(mysql)

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
50
51
52
53
54
55
56
57
58
59
60
61
62
{
"job": {
"setting": {
"speed": {
"channel": 1,
"byte": 2048576000
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "$username",
"password": "$password",
"connection": [
{
"querySql": [
"SELECT colume1,colume2,colume3 FROM tablename;"
],
"jdbcUrl": [
"jdbc:mysql://$IP_addr:$port/$dbname?characterEncoding=utf-8"
]
}
]
}
},
"writer": {
"name": "mysqlwriter",
"parameter": {
"writeMode": "insert",
"username": "$username",
"password": "$password",
"column": [
"colume1",
"colume2",
"colume3"
],
"session": [
"set session sql_mode='ANSI'"
],
"preSql": [
"delete from tabename;"
],
"connection": [
{
"jdbcUrl": "jdbc:mysql://$IP_addr:$port/$dbname?characterEncoding=utf-8",
"table": [
"tablename"
]
}
]
}
}
}
]
}
}

从数据库读取数据写入到文本文件(mysql)

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
{
"job": {
"setting": {
"speed": {
"channel": 1,
"byte": 2048576000
},
"errorLimit": {
"record": 0,
"percentage": 0.02
}
},
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "$username",
"password": "$password",
"connection": [
{
"querySql": [
"SELECT colume1,colume2,colume3 FROM tablename;"
],
"jdbcUrl": [
"jdbc:mysql://$IP_addr:$port/$dbname?characterEncoding=utf-8"
]
}
]
}
},
"writer": {
"name": "txtfilewriter",
"parameter": {
"path": "/path/to/tablename",
"fileName": "${dbname}_$time",
"writeMode": "append"
}
}
}
]
}
}

datax install

java install

1
2
3
4
5
6
7
8
[root@localhost app]# tar xzf jdk-8u111-linux-x64.tar.gz
[root@localhost app]# mv jdk1.8.0_111 /mnt/app/java
[root@localhost app]# echo 'JAVA_HOME=/mnt/app/java' | tee /etc/profile.d/java.sh
[root@localhost app]# echo 'JRE_HOME=${JAVA_HOME}/jre' | tee -a /etc/profile.d/java.sh
[root@localhost app]# echo 'CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib' | tee -a /etc/profile.d/java.sh
[root@localhost app]# echo 'export PATH=${JAVA_HOME}/bin:$PATH' | tee -a /etc/profile.d/java.sh
[root@localhost app]# source /etc/profile
[root@localhost app]# java -version

maven install

1
2
3
4
5
[root@localhost app]# tar xzf apache-maven-3.3.9-bin.tar.gz
[root@localhost app]# mv apache-maven-3.3.9 /mnt/app/maven
[root@localhost app]# echo 'MAVEN_HOME=/mnt/app/maven' | tee -a /etc/profile.d/maven.sh
[root@localhost app]# echo 'export PATH=${PATH}:${MAVEN_HOME}/bin' | tee -a /etc/profile.d/maven.sh
[root@localhost app]# source /etc/profile

python install

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# git clone https://github.com/yyuu/pyenv.git ~/.pyenv
[root@localhost ~]# echo 'export PYENV_ROOT="$HOME/.pyenv"' | tee /etc/profile.d/pyenv.sh
[root@localhost ~]# echo 'export PATH="$PYENV_ROOT/bin:$PATH"' | tee -a /etc/profile.d/pyenv.sh
[root@localhost ~]# echo 'eval "$(pyenv init -)"' | tee -a /etc/profile.d/pyenv.sh
[root@localhost ~]# echo 'eval "$(pyenv virtualenv-init -)"' | tee -a /etc/profile.d/pyenv.sh
[root@localhost ~]# source /etc/profile
[root@localhost ~]# exec $SHELL

[root@localhost ~]# pyenv install 2.7.13
[root@localhost ~]# pyenv rehash

[root@localhost ~]# pyenv global 2.7.13
[root@localhost ~]# pyenv versions

datax install

1
2
3
4
5
6
[root@localhost app]# tar xzf datax.tar.gz
[root@localhost app]# mv datax /mnt/app/datax
[root@localhost app]# echo 'export DATAX_HOME=/mnt/app/datax' | tee /etc/profile.d/datax.sh
[root@localhost app]# echo 'export DATAX_BIN=${DATAX_HOME}/bin' | tee -a /etc/profile.d/datax.sh
[root@localhost app]# echo 'export PATH=${DATAX_BIN}:$PATH' | tee -a /etc/profile.d/datax.sh
[root@localhost app]# source /etc/profile

datax use[https://github.com/alibaba/DataX]

1
2
3
4
5
6
[root@localhost app]# touch /mnt/app/datax/job/test.json
[root@localhost app]# cd /mnt/app/datax && python ./bin/datax.py ./job/test.json -p "-Dtime=${DAY} -Ddays=${num}"

说明:
-p 表示传参
-D 表示定义的变量,在job中引用变量

ntpd install

时间同步

  1. 设置时区和时间

    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
    [root@[ALL] ~]# [ -f /etc/localtime ] && cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    [root@[ALL] ~]# [ -f /etc/sysconfig/clock ] && echo 'ZONE="Asia/Shanghai"' | tee /etc/sysconfig/clock
    [root@[ALL] ~]# [ -f /etc/timezone ] && echo 'Asia/Shanghai' | tee /etc/timezone
    [root@[ALL] ~]# [ -f /etc/sysconfig/ntpd ] && echo 'SYNC_HWCLOCK=yes' | tee -a /etc/sysconfig/ntpd
    [root@[ALL] ~]# ntpdate cn.pool.ntp.org
    [root@[ALL] ~]# cp -f /etc/{ntp.conf,ntp.conf.bak}
    [root@[ALL] ~]# cat > /etc/ntp.conf <<EOF
    > driftfile /var/lib/ntp/drift
    > restrict default nomodify notrap nopeer noquery
    > restrict 127.0.0.1
    > restrict ::1
    > server cn.pool.ntp.org prefer
    > server 0.centos.pool.ntp.org iburst
    > server 1.centos.pool.ntp.org iburst
    > server 2.centos.pool.ntp.org iburst
    > server 3.centos.pool.ntp.org iburst
    > includefile /etc/ntp/crypto/pw
    > keys /etc/ntp/keys
    > disable monitor
    > EOF
    [root@[ALL] ~]# cp -f /etc/ntp/{step-tickers,step-tickers.bak}
    [root@[ALL] ~]# cat > /etc/ntp/step-tickers <<EOF
    > cn.pool.ntp.org
    > 0.centos.pool.ntp.org
    > 1.centos.pool.ntp.org
    > 2.centos.pool.ntp.org
    > 3.centos.pool.ntp.org
    > EOF
    [root@[ALL] ~]# systemctl start ntpd && systemctl enable ntpd
    1
    2
    3
    4
    //不在推荐使用
    [root@[ALL] ~]# systemctl stop ntpd
    [root@[ALL] ~]# systemctl disable ntpd
    [root@[ALL] ~]# echo '1 1 * * * /usr/sbin/ntpdate -s cn.pool.ntp.org' | tee /var/spool/cron/root

  1. ntpd 和 ntpdate 简介

    1
    2
    3
    4
    5
    在Windwos中,系统时间的设置很简单,界面操作,通俗易懂.而且设置后,重启,关机都没关系.系统时间会自动保存在Bios的时钟里面,启动计算机的时候,系统会自动在Bios里面取硬件时间,以保证时间的不间断.

    在Linux下,默认情况下,系统时间和硬件时间,并不会自动同步.在Linux运行过程中,系统时间和硬件时间以异步的方式运行,互不干扰.硬件时间的运行,是靠Bios电池来维持,而系统时间,是用CPU tick来维持的

    在系统开机的时候,会自动从Bios中取得硬件时间,设置为系统时间.
  2. Linux系统时间的设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //查看时间
    [root@localhost ~]# date
    2008年 12月 12日 星期五 14:44:12 CST

    //修改时间
    [root@localhost ~]# date --set "1/1/09 00:01" ==>月/日/年时:分:秒
    2009年 01月 01日 星期四 00:01:00 CST

    //date 有几种时间格式可接受,这样也可以设置时间:
    [root@localhost ~]# date 012501012009.30 ==>月日时分年.秒
    2009年 01月 25日 星期日 01:01:30 CST
  3. Linux硬件时间的设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    硬件时间的设置,可以用hwclock或者clock命令.其中,clock和hwclock用法相近,只用一个就行,只不过clock命令除了支持x86硬件体系外,还支持Alpha硬件体系

    //查看硬件时间 可以是用 hwclock ,hwclock --show 或者 hwclock -r
    [root@localhost ~]# hwclock --show
    2008年12月12日 星期五 06时52分07秒 -0.376932 seconds

    //设置硬件时间
    [root@localhost ~]# hwclock --set --date="1/25/09 00:00" <== 月/日/年时:分:秒
    [root@localhost ~]# hwclock
    2009年01月25日 星期日 00时00分06秒 -0.870868 seconds
  4. Linux系统时间和硬件时间的同步

    1
    2
    3
    4
    5
    6
    7
    8
    9
    同步系统时间和硬件时间,可以使用hwclock命令:

    //以系统时间为基准,修改硬件时间
    [root@localhost ~]# hwclock --systohc ==> sys(系统时间)to(写到)hc(Hard Clock)
    [root@localhost ~]# hwclock -w

    //以硬件时间为基准,修改系统时间
    [root@localhost ~]# hwclock --hctosys
    [root@localhost ~]# hwclock -s
  5. 不同机器之间的时间同步

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    为了避免主机时间因为长期运作下所导致的时间偏差,进行时间同步(synchronize)的工作是非常必要的.
    Linux系统下,一般使用ntp服务器来同步不同机器的时间.一台机器,可以同时是ntp服务器和ntp客户机.在网络中,推荐使用像DNS服务器一样分层的时间服务器来同步时间.
    同步时间,可以使用ntpdate命令,也可以使用ntpd服务

    //使用ntpdate比较简单,格式如下:
    [root@linux ~]# ntpdate [-nv] [NTP IP/hostname]
    [root@linux ~]# ntpdate 192.168.0.1
    [root@linux ~]# ntpdate time.ntp.org

    但这样的同步,只是强制性的将系统时间设置为ntp服务器时间.如果cpu tick有问题,只是治标不治本.所以,一般配合cron命令,来进行定期同步设置.比如,在crontab中添加:
    0 12 * * * * /usr/sbin/ntpdate time.ntp.org

    //使用ntpd服务,要好于ntpdate加cron的组合
    因为,ntpdate同步时间,会造成时间的跳跃,对一些依赖时间的程序和服务会造成影响.比如: sleep,timer等.而且,ntpd服务可以在修正时间的同时,修正cpu tick.理想的做法为,在开机的时候,使用ntpdate强制同步时间,在其他时候使用ntpd服务来同步时间.
    要注意的是,ntpd有一个自我保护设置: 如果本机与上源时间相差太大,ntpd不运行.所以新设置的时间服务器一定要先 ntpdate从上源取得时间初值,然后启动ntpd服务.ntpd服务运行后,先是每64秒与上源服务器同步一次,根据每次同步时测得的误差值经复杂计算逐步调整自己的时间,随着误差减小,逐步增加同步的间隔.每次跳动,都会重复这个调整的过程.
  6. ntpd服务的设置

    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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    //ntpd服务的相关设置文件
    * /etc/ntp.conf
    这个是NTP daemon的主要设文件,也是 NTP 唯一的设定文件
    * /usr/share/zoneinfo/
    在这个目录下的文件其实是规定了各主要时区的时间设定文件(例如:北京地区的时区设定文件在/usr/share/zoneinfo/Asia/Beijing).
    这个目录里面的文件与下面要谈的两个文件(clock与localtime)是有关系的
    * /etc/sysconfig/clock
    这个文件其实也不包含在NTP的daemon当中,因为这个是linux的主要时区设定文件.
    每次开机后,Linux会自动的读取这个文件来设定自己系统所默认要显示的时间
    * /etc/localtime
    这个文件就是"本地端的时间配置文件".
    刚刚那个clock文件里面规定了使用的时间设置文件(ZONE)为"/usr/share/zoneinfo/Asia/Beijing",所以说,这就是本地端的时间了.此时,Linux系统就会将Beijing那个文件另存为一份/etc/localtime文件,所以未来我们的时间显示就会以Beijing那个时间设定文件为准
    * /etc/timezone
    系统时区文件


    下面重点说说"/etc/ntp.conf"文件的设置: 在NTP Server的设定上面,其实最好不要对Internet无限制的开放,尽量仅提供您自己内部的Client端联机进行网络校时就好.此外,NTP Server也是需要网络上面较为准确的主机来自行更新自己的时间,所以在我们的NTP Server上面也要找一部最靠近自己的Time Server来进行自我校正.事实上,NTP这个服务也是C/S的一种模式

    [root@linux ~]# vi /etc/ntp.conf
    # 1.关于权限设定部分
    # 权限设定主要以"restrict"这个参数来设定,主要语法为:
    #  restrict {IP_addr} mask {net_mast} parameter
    #  * IP 可以是软件地址,也可以是"default","default"类似"0.0.0.0"
    #  * paramter则有:
    #   * ignore: 关闭所有的NTP联机服务
    #   * nomodify: 表示Client端不能更改Server端的时间参数.不过,Client端仍然可以透过Server端来进行网络校时
    #   * notrust: 该Client除非通过认证,否则该Client来源将被视为不信任网域
    #   * noquery: 不提供Client端的时间查询
    #   * notrap: 不提供trap这个远程事件登入
    #   * Kod: kod技术可以阻止"Kiss of Death"包对服务器的破坏
    #   * Nopeer: 不与其他同一层的NTP服务器进行时间同步
    #   如果paramter完全没有设定,那就表示该IP(或网域)没有任何限制

    restrict default nomodify notrap noquery  #关闭所有的NTP要求封包
    restrict 127.0.0.1    #这是允许本地查询
    restrict 192.168.0.1 mask 255.255.255.0 nomodify
    # 在192.168.0.1/24网段内的服务器就可以通过这台NTPServer进行时间同步了

    # 2.上层主机的设定
    # 要设定上层主机主要以server这个参数来设定,语法为:
    #  server [IP|HOST Name] [prefer]
    #  * Server后面接的就是我们上层"Time Server",如果Server参数后面加上"perfer"的话,那表示我们的NTP主机主要以该部主机来作为时间校正的对应.另外,为了解决更新时间封包的传送延迟动作,所以可以使用"driftfile"来规定我们的主机在与Time Server"沟通时所花费的时间,可以记录在"driftfile"后面接的文件内.
    # * prefer 表示优先级最高
    # * burst 当一个运程NTP服务器可用时,向它发送一系列的并发包进行检测
    # * iburst 当一个运程NTP服务器不可用时,向它发送一系列的并发包进行检测
    # 默认情况小15分钟后才会与上层NTP服务器进行时间校对
    # 例如:我们的NTP server与cn.pool.ntp.org联机时所花费的时间会记录在"/etc/ntp/drift"文件内
    server 0.pool.ntp.org
    server 1.pool.ntp.org
    server 2.pool.ntp.org
    server cn.pool.ntp.org prefer

    # 3.其他设置值,以系统默认值即可
    server 127.127.1.0 # local clock
    fudge 127.127.1.0 stratum 10
    driftfile /var/lib/ntp/drift
    broadcastdelay 0.008
    keys /etc/ntp/keys

    综上,restrict用来设置访问权限,server用来设置上层时间服务器,driftfile用来设置保存漂移时间的文件
  7. ntp服务的启动与观察

    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
    在启动NTP服务前,先对提供服务的这台主机手动的校正一次时间.()因为启动服务器,端口会被服务端占用,就不能手动同步时间了)
    [root@linux ~] # ntpdate cn.pool.ntp.org

    然后,启动ntpd服务:
    [root@linux ~] # /etc/init.d/ntpd start

    查看端口:
    [root@linux ~] # netstat -ln|grep 123
    udp 0 0 192.168.228.153:123 0.0.0.0:*
    udp 0 0 127.0.0.1:123 0.0.0.0:*
    udp 0 0 0.0.0.0:123 0.0.0.0:*
    udp 0 0 :::123 :::*

    确认我们的NTP服务器已经更新了自己的时间:
    [root@linux ~] # ntpstat
    synchronized to NTP server(127.127.1.0) at stratum 11
    time correct to within 950ms
    polling server every 64 s

    常见错误:
    25 Apr 15:30:17 ntpdate[11520]: no server suitable for synchronization found
    其实,这不是一个错误.而是由于每次重启NTP服务器之后大约要3-5分钟客户端才能与server建立正常的通讯连接.当此时用客户端连接服务端就会报这样的信息.一般等待几分钟就可以了.

    [root@linux ~] # ntptrace –n 127.0.0.1
    127.0.0.1:stratum 11, offset 0.000000,synch distance 0.950951
    222.73.214.125:stratum 2,offset –0.000787,synch distance 0.108575
    209.81.9.7:stratum 1,offset 0.000028,synch distance 0.00436,refid ‘GPS’
    #这个指令可以列出目前NTP服务器(第一层)与上层NTP服务器(第二层)彼此之间的关系


    指令"ntpq -p"可以列出目前我们的NTP与相关的上层NTP的状态,以上的几个字段的意义如下:
    * remote
    即NTP主机的IP或主机名称
    注意最左边的符号,如果由"+"则代表目前正在作用中的上层NTP,如果是"*"则表示也有连上线,不过是作为次要联机的NTP主机
    * refid 参考的上一层NTP主机的地址
    * st 即stratum阶层
    * when 几秒前曾做过时间同步更新的操作
    * poll 下次更新在几秒之后
    * reach 已经向上层NTP服务器要求更新的次数
    * delay 网络传输过程钟延迟的时间
    * offset 时间补偿的结果
    * jitter Linux系统时间与BIOS硬件时间的差异时间

    最后提及一点,ntp服务,默认只会同步系统时间!!!
    如果想要让ntp同时同步硬件时间,可以设置/etc/sysconfig/ntpd文件
    在/etc/sysconfig/ntpd文件中,添加"SYNC_HWCLOCK=yes".这样,就可以让硬件时间与系统时间一起同步
  8. 快速部署

    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
    // 私有ntp服务器,同步公网的ntp服务器
    * 编辑配置
    /etc/ntp.conf:
    # 定义服务器
    server pool.ntp.org
    restrict default nomodify notrap noquery

    #从192.168.0.1-192.168.0.254的服务器都可以使用我们的NTP服务器来同步时间
    restrict 192.168.0.0 mask 255.255.255.0 notrust nomodify notrap

    server 127.127.1.0
    fudge 127.127.1.0 stratum 8 当NTP服务不可用时,使用NTP服务器当前时间同步给客户机

    #注释掉
    #restrict default ignore

    * 启动:
    /etc/init.d/ntpd start
    chkconfig ntpd on

    默认情况下,我们配置的NTP服务器不会去时间源那里同步时间,所以必须修改"/etc/ntp/step-tickers"文件,加入我们的时间源,这样每次通过"/etc/init.d/ntpd"来启动服务的时候就会自动更新时间了

    //配置LINUX客户端
    在linux客户端上执行"ntpdate ntp_server_ip"就可以根据时间服务器统一局域网的时间了,将上面的命令放到cron里每天早上3点定期执行,crontab –e 然后输入:
    0 3 * * * /usr/sbin/ntpdate 192.168.0.179


    //防火墙
    iptables -I INPUT -p udp -m udp --sport 123 -j ACCEPT

  1. 安装

    1
    yum -y install ntp ntpdate
  2. 配置参数

    1
    2
    3
    4
    5
    6
    7
    ignore  :关闭所有的 NTP 联机服务
    nomodify:客户端不能更改服务端的时间参数,但是客户端可以通过服务端进行网络校时
    notrust :客户端除非通过认证,否则该客户端来源将被视为不信任子网
    noquery :不提供客户端的时间查询:用户端不能使用ntpq,ntpc等命令来查询ntp服务器
    notrap :不提供trap远端登陆:拒绝为匹配的主机提供模式 6 控制消息陷阱服务。陷阱服务是 ntpdq 控制消息协议的子系统,用于远程事件日志记录程序。
    nopeer :用于阻止主机尝试与服务器对等,并允许欺诈性服务器控制时钟
    kod : 访问违规时发送 KoD 包。
  3. 通用配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /etc/ntp.conf:
    driftfile /var/lib/ntp/drift
    restrict default nomodify notrap nopeer noquery
    restrict 127.0.0.1
    restrict ::1
    server 0.centos.pool.ntp.org iburst
    server 1.centos.pool.ntp.org iburst
    server 2.centos.pool.ntp.org iburst
    server 3.centos.pool.ntp.org iburst
    includefile /etc/ntp/crypto/pw
    keys /etc/ntp/keys
    disable monitor
  4. 限制网段访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /etc/ntp.conf:
    driftfile /var/lib/ntp/drift
    restrict default nomodify notrap
    restrict 127.0.0.1
    restrict ::1
    server 0.centos.pool.ntp.org iburst
    server 1.centos.pool.ntp.org iburst
    server 2.centos.pool.ntp.org iburst
    server 3.centos.pool.ntp.org iburst
    includefile /etc/ntp/crypto/pw
    keys /etc/ntp/keys
    disable monitor
  5. 启动ntp服务

    1
    2
    3
    4
    5
    6
    7
    8
    systemctl start ntpd
    systemctl enable ntpd

    iptables -A INPUT -p UDP -i eno16777736 -s 192.168.1.0/24 --dport 123 -j ACCEPT
    setsebool -P ntp_disable_trans

    vi /etc/sysconfig/ntpd #允许BIOS与系统时间同步,添加下面一行。
    SYNC_HWCLOCK=yes
  6. 检测ntp服务是否运行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //检测ntp服务是否运行
    netstat -tlunp | grep ntp

    //检测有无和上层ntp联通
    ntpstat

    //检测ntp和上层ntp的联通状态
    ntpq -p

    remote - 本机和上层ntp的ip或主机名,“+”表示优先,“*”表示次优先
    refid - 参考上一层ntp主机地址
    st - stratum阶层
    when - 多少秒前曾经同步过时间
    poll - 下次更新在多少秒后
    reach - 已经向上层ntp服务器要求更新的次数
    delay - 网络延迟
    offset - 时间补偿
    jitter - 系统时间与bios时间差
  7. 客户端配置时间同步

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //与ntp服务端同步
    ntpdate 192.168.1.101

    //写入到bios
    hclock -w

    //写入到计划任务
    /etc/crontab:
    01 0 * * * root /usr/sbin/ntpdate 192.168.1.101 2>&1 >/dev/null

    //重启crond计划任务
    /etc/init.d/crond restart

redis cluster redis-trib.rb

1
redis-trib.rb是redis官方推出的管理redis集群的工具,集成在redis的源码src目录下,是基于redis提供的集群命令封装成简单、便捷、实用的操作工具。redis-trib.rb是redis作者用ruby完成的.
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
$ruby redis-trib.rb help
Usage: redis-trib <command> <options> <arguments ...>
create host1:port1 ... hostN:portN
--replicas <arg>
check host:port
info host:port
fix host:port
--timeout <arg>
reshard host:port
--from <arg>
--to <arg>
--slots <arg>
--yes
--timeout <arg>
--pipeline <arg>
rebalance host:port
--weight <arg>
--auto-weights
--threshold <arg>
--use-empty-masters
--timeout <arg>
--simulate
--pipeline <arg>
add-node new_host:new_port existing_host:existing_port
--slave
--master-id <arg>
del-node host:port node_id
set-timeout host:port milliseconds
call host:port command arg arg .. arg
import host:port
--from <arg>
--copy
--replace
help (show this help)
For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
1
2
3
4
5
6
7
8
9
10
11
12
redis-trib.rb具有以下功能:
1、create:创建集群
2、check:检查集群
3、info:查看集群信息
4、fix:修复集群
5、reshard:在线迁移slot
6、rebalance:平衡集群节点slot数量
7、add-node:将新节点加入集群
8、del-node:从集群中删除节点
9、set-timeout:设置集群节点间心跳连接的超时时间
10、call:在集群全部节点上执行命令
11、import:将外部redis数据导入集群

create创建集群

create命令可选replicas参数,replicas表示需要有几个slave

1
2
3
4
5
最简单命令使用如下:
$ruby redis-trib.rb create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003

有一个slave的创建命令如下:
$ruby redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
创建流程如下:
1、首先为每个节点创建ClusterNode对象,包括连接每个节点。检查每个节点是否为独立且db为空的节点。执行load_info方法导入节点信息。
2、检查传入的master节点数量是否大于等于3个。只有大于3个节点才能组成集群。
3、计算每个master需要分配的slot数量,以及给master分配slave。分配的算法大致如下:
先把节点按照host分类,这样保证master节点能分配到更多的主机中。
不停遍历遍历host列表,从每个host列表中弹出一个节点,放入interleaved数组。直到所有的节点都弹出为止。
master节点列表就是interleaved前面的master数量的节点列表。保存在masters数组。
计算每个master节点负责的slot数量,保存在slots_per_node对象,用slot总数除以master数量取整即可。
遍历masters数组,每个master分配slots_per_node个slot,最后一个master,分配到16384个slot为止。
接下来为master分配slave,分配算法会尽量保证master和slave节点不在同一台主机上。对于分配完指定slave数量的节点,还有多余的节点,也会为这些节点寻找master。分配算法会遍历两次masters数组。
第一次遍历masters数组,在余下的节点列表找到replicas数量个slave。每个slave为第一个和master节点host不一样的节点,如果没有不一样的节点,则直接取出余下列表的第一个节点。
第二次遍历是在对于节点数除以replicas不为整数,则会多余一部分节点。遍历的方式跟第一次一样,只是第一次会一次性给master分配replicas数量个slave,而第二次遍历只分配一个,直到余下的节点被全部分配出去。
4、打印出分配信息,并提示用户输入“yes”确认是否按照打印出来的分配方式创建集群。
5、输入“yes”后,会执行flush_nodes_config操作,该操作执行前面的分配结果,给master分配slot,让slave复制master,对于还没有握手(cluster meet)的节点,slave复制操作无法完成,不过没关系,flush_nodes_config操作出现异常会很快返回,后续握手后会再次执行flush_nodes_config。
6、给每个节点分配epoch,遍历节点,每个节点分配的epoch比之前节点大1。
7、节点间开始相互握手,握手的方式为节点列表的其他节点跟第一个节点握手。
8、然后每隔1秒检查一次各个节点是否已经消息同步完成,使用ClusterNode的get_config_signature方法,检查的算法为获取每个节点cluster nodes信息,排序每个节点,组装成node_id1:slots|node_id2:slot2|...的字符串。如果每个节点获得字符串都相同,即认为握手成功。
9、此后会再执行一次flush_nodes_config,这次主要是为了完成slave复制操作。
10、最后再执行check_cluster,全面检查一次集群状态。包括和前面握手时检查一样的方式再检查一遍。确认没有迁移的节点。确认所有的slot都被分配出去了。
11、至此完成了整个创建流程,返回[OK] All 16384 slots covered.。

check检查集群

检查集群状态的命令,没有其他参数,只需要选择一个集群中的一个节点即可。

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
执行命令以及结果如下:
$ruby redis-trib.rb check 127.0.0.1:7001
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: b2506515b38e6bbd3034d540599f4cd2a5279ad1 127.0.0.1:7001
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: d376aaf80de0e01dde1f8cd4647d5ac3317a8641 127.0.0.1:7002
slots: (0 slots) slave
replicates e36c46dbe90960f30861af00786d4c2064e63df2
M: 15126fb33796c2c26ea89e553418946f7443d5a5 127.0.0.1:7003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 59fa6ee455f58a5076f6d6f83ddd74161fd7fb55 127.0.0.1:7004
slots: (0 slots) slave
replicates 15126fb33796c2c26ea89e553418946f7443d5a5
S: 460b3a11e296aafb2615043291b7dd98274bb351 127.0.0.1:7005
slots: (0 slots) slave
replicates b2506515b38e6bbd3034d540599f4cd2a5279ad1
M: e36c46dbe90960f30861af00786d4c2064e63df2 127.0.0.1:7006
slots:5461-10922 (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
1
检查前会先执行load_cluster_info_from_node方法,把所有节点数据load进来。load的方式为通过自己的cluster nodes发现其他节点,然后连接每个节点,并加入nodes数组。接着生成节点间的复制关系。load完数据后,开始检查数据,检查的方式也是调用创建时候使用的check_cluster。

info查看集群信息

info命令用来查看集群的信息。info命令也是先执行load_cluster_info_from_node获取完整的集群信息。然后显示ClusterNode的info_string结果

1
2
3
4
5
6
7
示例如下:
$ruby redis-trib.rb info 127.0.0.1:7001
127.0.0.1:7001 (b2506515...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7003 (15126fb3...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7005 (e36c46db...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.


fix修复集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fix命令的流程跟check的流程很像,显示加载集群信息,然后在check_cluster方法内传入fix为
true的变量,会在集群检查出现异常的时候执行修复流程。目前fix命令能修复两种异常,一种是集群有处于迁移中的slot的节点,一种是slot未完全分配的异常。
fix_open_slot方法是修复集群有处于迁移中的slot的节点异常。
1、先检查该slot是谁负责的,迁移的源节点如果没完成迁移,owner还是该节点。没有owner的slot无法完成修复功能。
2、遍历每个节点,获取哪些节点标记该slot为migrating状态,哪些节点标记该slot为importing状态。对于owner不是该节点,但是通过cluster countkeysinslot获取到该节点有数据的情况,也认为该节点为importing状态。
3、如果migrating和importing状态的节点均只有1个,这可能是迁移过程中redis-trib.rb被中断所致,直接执行move_slot继续完成迁移任务即可。传递dots和fix为true。
4、如果migrating为空,importing状态的节点大于0,那么这种情况执行回滚流程,将importing状态的节点数据通过move_slot方法导给slot的owner节点,传递dots、fix和cold为true。接着对importing的节点执行cluster stable命令恢复稳定。
5、如果importing状态的节点为空,有一个migrating状态的节点,而且该节点在当前slot没有数据,那么可以直接把这个slot设为stable。
6、如果migrating和importing状态不是上述情况,目前redis-trib.rb工具无法修复,上述的三种情况也已经覆盖了通过redis-trib.rb工具迁移出现异常的各个方面,人为的异常情形太多,很难考虑完全。

fix_slots_coverage方法能修复slot未完全分配的异常。未分配的slot有三种状态。
1、所有节点的该slot都没有数据。该状态redis-trib.rb工具直接采用随机分配的方式,并没有考虑节点的均衡。本人尝试对没有分配slot的集群通过fix修复集群,结果slot还是能比较平均的分配,但是没有了连续性,打印的slot信息非常离散。
2、有一个节点的该slot有数据。该状态下,直接把slot分配给该slot有数据的节点。
3、有多个节点的该slot有数据。此种情况目前还处于TODO状态,不过redis作者列出了修复的步骤,对这些节点,除第一个节点,执行cluster migrating命令,然后把这些节点的数据迁移到第一个节点上。清除migrating状态,然后把slot分配给第一个节点。

reshard在线迁移slot

reshard命令可以在线把集群的一些slot从集群原来slot负责节点迁移到新的节点,利用reshard可以完成集群的在线横向扩容和缩容。

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
reshard         host:port
--from <arg>
--to <arg>
--slots <arg>
--yes
--timeout <arg>
--pipeline <arg>

host:port:这个是必传参数,用来从一个节点获取整个集群信息,相当于获取集群信息的入口。
--from <arg>:需要从哪些源节点上迁移slot,可从多个源节点完成迁移,以逗号隔开,传递的是节点的node id,还可以直接传递--from all,这样源节点就是集群的所有节点,不传递该参数的话,则会在迁移过程中提示用户输入。
--to <arg>:slot需要迁移的目的节点的node id,目的节点只能填写一个,不传递该参数的话,则会在迁移过程中提示用户输入。
--slots <arg>:需要迁移的slot数量,不传递该参数的话,则会在迁移过程中提示用户输入。
--yes:设置该参数,可以在打印执行reshard计划的时候,提示用户输入yes确认后再执行reshard。
--timeout <arg>:设置migrate命令的超时时间。
--pipeline <arg>:定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10。

迁移的流程如下:
1、通过load_cluster_info_from_node方法装载集群信息。
2、执行check_cluster方法检查集群是否健康。只有健康的集群才能进行迁移。
3、获取需要迁移的slot数量,用户没传递--slots参数,则提示用户手动输入。
4、获取迁移的目的节点,用户没传递--to参数,则提示用户手动输入。此处会检查目的节点必须为master节点。
5、获取迁移的源节点,用户没传递--from参数,则提示用户手动输入。此处会检查源节点必须为master节点。--from all的话,源节点就是除了目的节点外的全部master节点。这里为了保证集群slot分配的平均,建议传递--from all。
6、执行compute_reshard_table方法,计算需要迁移的slot数量如何分配到源节点列表,采用的算法是按照节点负责slot数量由多到少排序,计算每个节点需要迁移的slot的方法为:迁移slot数量 * (该源节点负责的slot数量 / 源节点列表负责的slot总数)。这样算出的数量可能不为整数,这里代码用了下面的方式处理:

n = (numslots/source_tot_slots*s.slots.length)
if i == 0
n = n.ceil
else
n = n.floor
这样的处理方式会带来最终分配的slot与请求迁移的slot数量不一致,这个BUG已经在github上提给作者,https://github.com/antirez/redis/issues/2990。

7、打印出reshard计划,如果用户没传--yes,就提示用户确认计划。
8、根据reshard计划,一个个slot的迁移到新节点上,迁移使用move_slot方法,该方法被很多命令使用,具体可以参见下面的迁移流程。move_slot方法传递dots为true和pipeline数量。
9、至此,就完成了全部的迁移任务。
下面看下一次reshard的执行结果:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$ruby redis-trib.rb reshard --from all --to 80b661ecca260c89e3d8ea9b98f77edaeef43dcd --slots 11 10.180.157.199:6379
>>> Performing Cluster Check (using node 10.180.157.199:6379)
S: b2506515b38e6bbd3034d540599f4cd2a5279ad1 10.180.157.199:6379
slots: (0 slots) slave
replicates 460b3a11e296aafb2615043291b7dd98274bb351
S: d376aaf80de0e01dde1f8cd4647d5ac3317a8641 10.180.157.205:6379
slots: (0 slots) slave
replicates e36c46dbe90960f30861af00786d4c2064e63df2
M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 59fa6ee455f58a5076f6d6f83ddd74161fd7fb55 10.180.157.208:6379
slots: (0 slots) slave
replicates 15126fb33796c2c26ea89e553418946f7443d5a5
M: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 80b661ecca260c89e3d8ea9b98f77edaeef43dcd 10.180.157.200:6380
slots: (0 slots) master
0 additional replica(s)
M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379
slots:5461-10922 (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Ready to move 11 slots.
Source nodes:
M: 15126fb33796c2c26ea89e553418946f7443d5a5 10.180.157.201:6379
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: 460b3a11e296aafb2615043291b7dd98274bb351 10.180.157.202:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: e36c46dbe90960f30861af00786d4c2064e63df2 10.180.157.200:6379
slots:5461-10922 (5462 slots) master
1 additional replica(s)
Destination node:
M: 80b661ecca260c89e3d8ea9b98f77edaeef43dcd 10.180.157.200:6380
slots: (0 slots) master
0 additional replica(s)
Resharding plan:
Moving slot 5461 from e36c46dbe90960f30861af00786d4c2064e63df2
Moving slot 5462 from e36c46dbe90960f30861af00786d4c2064e63df2
Moving slot 5463 from e36c46dbe90960f30861af00786d4c2064e63df2
Moving slot 5464 from e36c46dbe90960f30861af00786d4c2064e63df2
Moving slot 0 from 460b3a11e296aafb2615043291b7dd98274bb351
Moving slot 1 from 460b3a11e296aafb2615043291b7dd98274bb351
Moving slot 2 from 460b3a11e296aafb2615043291b7dd98274bb351
Moving slot 10923 from 15126fb33796c2c26ea89e553418946f7443d5a5
Moving slot 10924 from 15126fb33796c2c26ea89e553418946f7443d5a5
Moving slot 10925 from 15126fb33796c2c26ea89e553418946f7443d5a5
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 5461 from 10.180.157.200:6379 to 10.180.157.200:6380:
Moving slot 5462 from 10.180.157.200:6379 to 10.180.157.200:6380:
Moving slot 5463 from 10.180.157.200:6379 to 10.180.157.200:6380:
Moving slot 5464 from 10.180.157.200:6379 to 10.180.157.200:6380:
Moving slot 0 from 10.180.157.202:6379 to 10.180.157.200:6380:
Moving slot 1 from 10.180.157.202:6379 to 10.180.157.200:6380:
Moving slot 2 from 10.180.157.202:6379 to 10.180.157.200:6380:
Moving slot 10923 from 10.180.157.201:6379 to 10.180.157.200:6380:
Moving slot 10924 from 10.180.157.201:6379 to 10.180.157.200:6380:
Moving slot 10925 from 10.180.157.201:6379 to 10.180.157.200:6380:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
move_slot方法可以在线将一个slot的全部数据从源节点迁移到目的节点,fix、reshard、rebalance都需要调用该方法迁移slot。
move_slot接受下面几个参数,
1、pipeline:设置一次从slot上获取多少个key。
2、quiet:迁移会打印相关信息,设置quiet参数,可以不用打印这些信息。
3、cold:设置cold,会忽略执行importing和migrating。
4、dots:设置dots,则会在迁移过程打印迁移key数量的进度。
5、update:设置update,则会更新内存信息,方便以后的操作。

move_slot流程如下:
1、如果没有设置cold,则对源节点执行cluster importing命令,对目的节点执行migrating命令。fix的时候有可能importing和migrating已经执行过来,所以此种场景会设置cold。
2、通过cluster getkeysinslot命令,一次性获取远节点迁移slot的pipeline个key的数量.
3、对这些key执行migrate命令,将数据从源节点迁移到目的节点。
4、如果migrate出现异常,在fix模式下,BUSYKEY的异常,会使用migrate的replace模式再执行一次,BUSYKEY表示目的节点已经有该key了,replace模式可以强制替换目的节点的key。不是fix模式就直接返回错误了。
5、循环执行cluster getkeysinslot命令,直到返回的key数量为0,就退出循环。
6、如果没有设置cold,对每个节点执行cluster setslot命令,把slot赋给目的节点。
7、如果设置update,则修改源节点和目的节点的slot信息。
8、至此完成了迁移slot的流程。

rebalance平衡集群节点slot数量

rebalance命令可以根据用户传入的参数平衡集群节点的slot数量,rebalance功能非常强大,可以传入的参数很多,以下是rebalance的参数列表和命令示例。

1
2
3
4
5
6
7
8
rebalance       host:port
--weight <arg>
--auto-weights
--threshold <arg>
--use-empty-masters
--timeout <arg>
--simulate
--pipeline <arg>

1
$ruby redis-trib.rb rebalance --threshold 1 --weight b31e3a2e=5 --weight 60b8e3a1=5 --use-empty-masters  --simulate 10.180.157.199:6379
1
2
3
4
5
6
7
8
9
下面也先一一解释下每个参数的用法:
host:port:这个是必传参数,用来从一个节点获取整个集群信息,相当于获取集群信息的入口。
--weight <arg>:节点的权重,格式为node_id=weight,如果需要为多个节点分配权重的话,需要添加多个--weight <arg>参数,即--weight b31e3a2e=5 --weight 60b8e3a1=5,node_id可为节点名称的前缀,只要保证前缀位数能唯一区分该节点即可。没有传递–weight的节点的权重默认为1。
--auto-weights:这个参数在rebalance流程中并未用到。
--threshold <arg>:只有节点需要迁移的slot阈值超过threshold,才会执行rebalance操作。具体计算方法可以参考下面的rebalance命令流程的第四步。
--use-empty-masters:rebalance是否考虑没有节点的master,默认没有分配slot节点的master是不参与rebalance的,设置--use-empty-masters可以让没有分配slot的节点参与rebalance。
--timeout <arg>:设置migrate命令的超时时间。
--simulate:设置该参数,可以模拟rebalance操作,提示用户会迁移哪些slots,而不会真正执行迁移操作。
--pipeline <arg>:与reshar的pipeline参数一样,定义cluster getkeysinslot命令一次取出的key数量,不传的话使用默认值为10。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
rebalance命令流程如下:
1、load_cluster_info_from_node方法先加载集群信息。
2、计算每个master的权重,根据参数--weight <arg>,为每个设置的节点分配权重,没有设置的节点,则权重默认为1。
3、根据每个master的权重,以及总的权重,计算自己期望被分配多少个slot。计算的方式为:总slot数量 * (自己的权重 / 总权重)。
4、计算每个master期望分配的slot是否超过设置的阈值,即--threshold <arg>设置的阈值或者默认的阈值。计算的方式为:先计算期望移动节点的阈值,算法为:(100-(100.0*expected/n.slots.length)).abs,如果计算出的阈值没有超出设置阈值,则不需要为该节点移动slot。只要有一个master的移动节点超过阈值,就会触发rebalance操作。
5、如果触发了rebalance操作。那么就开始执行rebalance操作,先将每个节点当前分配的slots数量减去期望分配的slot数量获得balance值。将每个节点的balance从小到大进行排序获得sn数组。
6、用dst_idx和src_idx游标分别从sn数组的头部和尾部开始遍历。目的是为了把尾部节点的slot分配给头部节点。

sn数组保存的balance列表排序后,负数在前面,正数在后面。负数表示需要有slot迁入,所以使用dst_idx游标,正数表示需要有slot迁出,所以使用src_idx游标。理论上sn数组各节点的balance值加起来应该为0,不过由于在计算期望分配的slot的时候只是使用直接取整的方式,所以可能出现balance值之和不为0的情况,balance值之和不为0即为节点不平衡的slot数量,由于slot总数有16384个,不平衡数量相对于总数,基数很小,所以对rebalance流程影响不大。

7、获取sn[dst_idx]和sn[src_idx]的balance值较小的那个值,该值即为需要从sn[src_idx]节点迁移到sn[dst_idx]节点的slot数量。
8、接着通过compute_reshard_table方法计算源节点的slot如何分配到源节点列表。这个方法在reshard流程中也有调用,具体步骤可以参考reshard流程的第六步。
9、如果是simulate模式,则只是打印出迁移列表。
10、如果没有设置simulate,则执行move_slot操作,迁移slot,传入的参数为:quiet=>true,:dots=>false,:update=>true。
11、迁移完成后更新sn[dst_idx]和sn[src_idx]的balance值。如果balance值为0后,游标向前进1。
12、直到dst_idx到达src_idx游标,完成整个rebalance操作。

add-node将新节点加入集群

add-node命令可以将新节点加入集群,节点可以为master,也可以为某个master节点的slave。

1
2
3
4
5
6
7
add-node    new_host:new_port existing_host:existing_port
--slave
--master-id <arg>

add-node有两个可选参数:
--slave:设置该参数,则新节点以slave的角色加入集群
--master-id:这个参数需要设置了--slave才能生效,--master-id用来指定新节点的master节点。如果不设置该参数,则会随机为节点选择master节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ruby redis-trib.rb add-node --slave --master-id dcb792b3e85726f012e83061bf237072dfc45f99 10.180.157.202:6379 10.180.157.199:6379
>>> Adding node 10.180.157.202:6379 to cluster 10.180.157.199:6379
>>> Performing Cluster Check (using node 10.180.157.199:6379)
M: dcb792b3e85726f012e83061bf237072dfc45f99 10.180.157.199:6379
slots:0-5460 (5461 slots) master
0 additional replica(s)
M: 464d740bf48953ebcf826f4113c86f9db3a9baf3 10.180.157.201:6379
slots:10923-16383 (5461 slots) master
0 additional replica(s)
M: befa7e17b4e5f239e519bc74bfef3264a40f96ae 10.180.157.200:6379
slots:5461-10922 (5462 slots) master
0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 10.180.157.202:6379 to make it join the cluster.
Waiting for the cluster to join.
>>> Configure node as replica of 10.180.157.199:6379.
[OK] New node added correctly.
1
2
3
4
5
6
add-node流程如下:
1、通过load_cluster_info_from_node方法转载集群信息,check_cluster方法检查集群是否健康。
2、如果设置了--slave,则需要为该节点寻找master节点。设置了--master-id,则以该节点作为新节点的master,如果没有设置--master-id,则调用get_master_with_least_replicas方法,寻找slave数量最少的master节点。如果slave数量一致,则选取load_cluster_info_from_node顺序发现的第一个节点。load_cluster_info_from_node顺序的第一个节点是add-node设置的existing_host:existing_port节点,后面的顺序根据在该节点执行cluster nodes返回的结果返回的节点顺序。
3、连接新的节点并与集群第一个节点握手。
4、如果没设置–slave就直接返回ok,设置了–slave,则需要等待确认新节点加入集群,然后执行cluster replicate命令复制master节点。
5、至此,完成了全部的增加节点的流程。

del-node从集群中删除节点

del-node可以把某个节点从集群中删除。del-node只能删除没有分配slot的节点。删除命令传递两个参数:

1
2
3
host:port:从该节点获取集群信息。
node_id:需要删除的节点id。
del-node执行结果示例如下:

1
2
3
4
$ruby redis-trib.rb del-node 10.180.157.199:6379 d5f6d1d17426bd564a6e309f32d0f5b96962fe53
>>> Removing node d5f6d1d17426bd564a6e309f32d0f5b96962fe53 from cluster 10.180.157.199:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
1
2
3
4
5
6
del-node流程如下:
1、通过load_cluster_info_from_node方法转载集群信息。
2、根据传入的node id获取节点,如果节点没找到,则直接提示错误并退出。
3、如果节点分配的slot不为空,则直接提示错误并退出。
4、遍历集群内的其他节点,执行cluster forget命令,从每个节点中去除该节点。如果删除的节点是master,而且它有slave的话,这些slave会去复制其他master,调用的方法是get_master_with_least_replicas,与add-node没设置--master-id寻找master的方法一样。
5、然后关闭该节点

set-timeout设置集群节点间心跳连接的超时时间

1
set-timeout用来设置集群节点间心跳连接的超时时间,单位是毫秒,不得小于100毫秒,因为100毫秒对于心跳时间来说太短了。该命令修改是节点配置参数cluster-node-timeout,默认是15000毫秒。通过该命令,可以给每个节点设置超时时间,设置的方式使用config set命令动态设置,然后执行config rewrite命令将配置持久化保存到硬盘。以下是示例:
1
2
3
4
5
6
7
8
ruby redis-trib.rb set-timeout 10.180.157.199:6379 30000
>>> Reconfiguring node timeout in every cluster node...
*** New timeout set for 10.180.157.199:6379
*** New timeout set for 10.180.157.205:6379
*** New timeout set for 10.180.157.201:6379
*** New timeout set for 10.180.157.200:6379
*** New timeout set for 10.180.157.208:6379
>>> New node timeout set. 5 OK, 0 ERR.

call在集群全部节点上执行命令

call命令可以用来在集群的全部节点执行相同的命令。call命令也是需要通过集群的一个节点地址,连上整个集群,然后在集群的每个节点执行该命令。

1
2
3
4
5
6
7
$ruby redis-trib.rb call 10.180.157.199:6379 get key
>>> Calling GET key
10.180.157.199:6379: MOVED 12539 10.180.157.201:6379
10.180.157.205:6379: MOVED 12539 10.180.157.201:6379
10.180.157.201:6379:
10.180.157.200:6379: MOVED 12539 10.180.157.201:6379
10.180.157.208:6379: MOVED 12539 10.180.157.201:6379


import将外部redis数据导入集群

1
2
3
4
5
6
7
8
9
10
11
import命令可以把外部的redis节点数据导入集群。导入的流程如下:
1、通过load_cluster_info_from_node方法转载集群信息,check_cluster方法检查集群是否健康。
2、连接外部redis节点,如果外部节点开启了cluster_enabled,则提示错误。
3、通过scan命令遍历外部节点,一次获取1000条数据。
4、遍历这些key,计算出key对应的slot。
5、执行migrate命令,源节点是外部节点,目的节点是集群slot对应的节点,如果设置了--copy参数,则传递copy参数,如果设置了--replace,则传递replace参数。
6、不停执行scan命令,直到遍历完全部的key。
7、至此完成整个迁移流程
这中间如果出现异常,程序就会停止。没使用--copy模式,则可以重新执行import命令,使用--copy的话,最好清空新的集群再导入一次。

import命令更适合离线的把外部Redis数据导入,在线导入的话最好使用更专业的导入工具,以slave的方式连接redis节点去同步节点数据应该是更好的方式。
1
2
./redis-trib.rb import --from 10.0.10.1:6379 10.10.10.1:7000
上面的命令是把 10.0.10.1:6379(redis 2.8)上的数据导入到 10.10.10.1:7000这个节点所在的集群