十一、codis

一、简介

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 , 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.

组成部分

编辑

Codis Proxy (codis-proxy)

Codis Manager (codis-config)

Codis Redis (codis-server)

ZooKeeper

codis-proxy 是客户端连接的 Redis 代理服务, codis-proxy 本身实现了 Redis 协议, 表现得和一个原生的 Redis 没什么区别 (就像 Twemproxy), 对于一个业务来说, 可以部署多个 codis-proxy, codis-proxy 本身是无状态的.

codis-config 是 Codis 的管理工具, 支持包括, 添加/删除 Redis 节点, 添加/删除 Proxy 节点, 发起数据迁移等操作. codis-config 本身还自带了一个 http server, 会启动一个 dashboard, 用户可以直接在浏览器上观察 Codis 集群的运行状态.

codis-server 是 Codis 项目维护的一个 Redis 分支, 基于 2.8.13 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行.

Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.

Codis 支持按照 Namespace 区分不同的产品, 拥有不同的 product name 的产品, 各项配置都不会冲突

特性

编辑

自动平衡

使用非常简单

图形化的面板和管理工具

支持绝大多数 Redis 命令,完全兼容twemproxy

支持 Redis 原生客户端

安全而且透明的数据移植,可根据需要轻松添加和删除节点

提供命令行接口

RESTful APIs

优点:实现高并发读写,数据一致性高.

缺点:性能有较大损耗,故障切换无法保证不丢key,无法进行读写分离.


逻辑架构如下:

访问层:访问方式可以是vip或者是通过java代码调用jodis,然后连接调用不同的codis-proxy地址来实现高可用的LVS和HA功能.

代理层:然后中间层由codis-proxy和zookeeper处理数据走向和分配,通过crc32算法,把key平均分配在不同redis的某一个slot中.实现类似raid0的条带化,在旧版本的codis中,slot需要手工分配,在codis3.2之后,slot会自动分配,相当方便.

数据层:最后codis-proxy把数据存进真实的redis-server主服务器上,由于codis的作者黄东旭相当注重数据一致性,不允许有数据延时造成的数据不一致,所以架构从一开始就没考虑主从读写分离.从服务器仅仅是作为故障切换的冗余架构,由zookeeper调用redis-sentinel实现故障切换功能.


因为机器有限,部署的架构如下:

序号 IP 主机名 部署程序
01 172.16.1.150 codis-porxy codis-proxy:19000 codis-dashborad:18080、codis-fe:18090
02 172.16.1.151 codis-redis1 codis-server:(6379&6380) redis-sentinel:26379
03 172.16.1.152 codis-redis2 codis-server:(6379&6380) redis-sentinel:26379
04 172.16.1.153 codis-redis3 codis-server:(6379&6380) redis-sentinel:26379

1.安装go

cd /application/tools/
wget https://dl.google.com/go/go1.10.2.linux-amd64.tar.gz
tar -zxf go1.10.2.linux-amd64.tar.gz -C /usr/local/
cat << EOF  >>/etc/profile
export PATH=$PATH:/usr/local/go/bin
export GOROOT=/usr/local/go
export GOPATH=/usr/local/go/work
path=$PATH:$HOME/bin:$GOROOT/bin:$GOPATH/bin
EOF
source /etc/profile

2.获取codis

wget https://github.com/CodisLabs/codis/archive/release3.2.zip
mkdir -p $GOPATH/src/github.com/CodisLabs
cd /usr/local/go/work/src/github.com/CodisLabs
unzip /application/tools/release3.2
mv codis-release3.2/ codis
cd codis/
make
#执行全部指令后,会在 bin 文件夹内生成 codis-proxy、codis-server三个可执行文件。另外, bin/assets 文件夹是 dashboard http 服务需要的前端资源)
[[email protected] application]# ll /usr/local/go/work/src/github.com/CodisLabs/codis/bin
total 107560
drwxr-xr-x 4 root root     4096 Jun  2 03:57 assets
-rwxr-xr-x 1 root root 16237048 Jun  2 03:57 codis-admin
-rwxr-xr-x 1 root root 17222240 Jun  2 03:56 codis-dashboard
-rwxr-xr-x 1 root root 15512405 Jun  2 03:57 codis-fe
-rwxr-xr-x 1 root root 14457471 Jun  2 03:57 codis-ha
-rwxr-xr-x 1 root root 19425814 Jun  2 03:57 codis-proxy
-rwxr-xr-x 1 root root  7983449 Jun  2 03:56 codis-server
-rwxr-xr-x 1 root root  5578703 Jun  2 03:56 redis-benchmark
-rwxr-xr-x 1 root root  5710507 Jun  2 03:56 redis-cli
-rwxr-xr-x 1 root root  7983449 Jun  2 03:56 redis-sentinel
-rw-r--r-- 1 root root       97 Jun  2 03:59 version
[[email protected] application]#

3.codis-server配置

作用:基于 redis-3.2.8 分支开发。增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。具体的修改可以参考文档 redis 的修改。
#拷贝codis程序
mkdir -p /application/codis/bin
mkdir /application/codis/conf
mkdir /application/codis/log
mkdir /application/codis/proc
mkdir /application/codis/data/redis_data_6380 -p
mkdir /application/codis/data/redis_data_6379 -p
cp -fr /usr/local/go/work/src/github.com/CodisLabs/codis/bin/* /application/codis/bin/
cp -fr /usr/local/go/work/src/github.com/CodisLabs/codis/config/* /application/codis/conf/
#修改主配置
cd /application/codis/conf/
#主配置
cp redis.conf redis-6379.conf
vim redis-6379.conf
bind 172.16.1.150
daemonize yes 
#进程ID文件路径 
pidfile /application/codis/proc/redis-6379.pid 
#绑定端口 
port 6379
timeout 86400 
tcp-keepalive 60 
loglevel notice 
#日志文件路径
logfile "/application/codis/log/redis-6379.log"
databases 16 
save “” 
save 900 1 
save 300 10 
save 60 10000 
stop-writes-on-bgsave-error no 
rdbcompression yes 
#dump文件 
dbfilename dump-6379.rdb 
#dump路径 
dir /application/codis/data/redis_data_6379
#Master密码(从主同步密码)
masterauth "123456"  
slave-serve-stale-data yes 
repl-disable-tcp-nodelay no 
slave-priority 100 
#鉴权密码(客户端连接密码)
requirepass "123456" 
maxmemory 10gb 
maxmemory-policy allkeys-lru 
appendonly no 
appendfsync everysec 
no-appendfsync-on-rewrite yes 
auto-aof-rewrite-percentage 100 
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000 
slowlog-log-slower-than 10000 
slowlog-max-len 128 
hash-max-ziplist-entries 512 
hash-max-ziplist-value 64 
list-max-ziplist-entries 512 
list-max-ziplist-value 64 
set-max-intset-entries 512 
zset-max-ziplist-entries 128 
zset-max-ziplist-value 64 
client-output-buffer-limit normal 0 0 0 
client-output-buffer-limit slave 0 0 0 
client-output-buffer-limit pubsub 0 0 0 
hz 10 
aof-rewrite-incremental-fsync yes 
repl-backlog-size 33554432

#修改从配置
cp redis-6379.conf redis-example.conf 
egrep -v "#|^$" redis-example.conf > redis-6380.conf
sed -i "[email protected]@[email protected]" redis-6380.conf
vim redis-6380.conf
bind 172.16.1.150
protected-mode yes
port 6380
tcp-backlog 511
timeout 86400
tcp-keepalive 60
daemonize yes
supervised no
pidfile /application/codis/proc/redis-6380.pid
loglevel notice
logfile "/application/codis/log/redis-6380.log"
databases 16
#save ""
#save 900 1
#save 300 10
#save 60 10000
stop-writes-on-bgsave-error no
rdbcompression yes
rdbchecksum yes
dbfilename dump-6380.rdb
dir /application/codis/data/redis_data_6380
masterauth 123456
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
repl-backlog-size 33554432
slave-priority 100
requirepass 123456
maxmemory 10gb
maxmemory-policy allkeys-lru
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 0 0 0
client-output-buffer-limit pubsub 0 0 0
hz 10
aof-rewrite-incremental-fsync yes

#拷贝codis-server程序到其他节点
scp -r codis [email protected]:/application/
scp -r codis [email protected]:/application/

#启动脚本
vim /server/scripts/codis-server.sh
if [ $# -eq 0 ]
then
echo "useage:sh $0 {start|stop}"
exit 0
fi
case $1 in
start)
/application/codis/bin/codis-server /application/codis/conf/redis-6379.conf
/application/codis/bin/codis-server /application/codis/conf/redis-6380.conf
;;
stop) 
ps -ef|grep codis-server|grep -v grep|awk '{print $2}'|xargs kill
;;
esac

#拷贝脚本到其他节点
scp /server/scripts/codis-server.sh [email protected]:/server/scripts/
scp /server/scripts/codis-server.sh [email protected]:/server/scripts/

#所有节点启动
sh /server/scripts/codis-server.sh start

4.Codis-dashboard

作用:集群管理工具,支持 codis-proxy、codis-server 的添加、删除,以及据迁移等操作。在集群状态发生改变时,codis-dashboard 维护集群下所有 codis-proxy 的状态的一致性。
1)对于同一个业务集群而言,同一个时刻 codis-dashboard 只能有 0个或者1个; 
2)所有对集群的修改都必须通过 codis-dashboard 完成。

cd /application/codis/bin/
#生成配置
./codis-dashboard --default-config | tee ../conf/dashboard.conf
vim ../conf/dashboard.conf
#外部存储类型 
coordinator_name = "zookeeper" 
#外部存储IP列表
coordinator_addr = "172.16.1.111:2181" 
#项目名称 
product_name = "my-codis" 
#集群密码(注意:需要与redis配置中的requirepass保持一致)
product_auth = "123456"
#RESTful API 端口
admin_addr = "0.0.0.0:18080" 
#为了防止出现dashboard监控页面中OPS始终为0的现象,需要将proxy的IP和主机名写到hosts文件中.
172.16.1.150    codis-porxy

#启动程序
nohup ./codis-dashboard --ncpu=24 --config=/application/codis/conf/dashboard.conf --log=/application/codis/log/dashboard.log --log-level=WARN &

#关闭
./codis-admin --dashboard=172.16.1.150:18080 –auth=123456 --shutdown

5.Codis-proxy

作用:客户端连接的 Redis 代理服务, 实现了 Redis 协议。 除部分命令不支持以外(不支持的命令列表),表现的和原生的 Redis 没有区别(就像 Twemproxy)。
1)对于同一个业务集群而言,可以同时部署多个 codis-proxy 实例; 
2)不同 codis-proxy 之间由 codis-dashboard 保证状态同步

#修改配置
cd /application/codis/bin/
#生成配置
./codis-proxy --default-config | tee ../conf/proxy.conf 
#修改配置
vim ../conf/proxy.conf 
#设置项目名 
product_name = "my-codis" 
#设置登录dashboard的密码(注意:与redis中requirepass一致)
product_auth = "123456" 
#Redis客户端的登录密码(注意:与redis中requirepass不一致)
session_auth = "56789" 
# Set bind address for admin(rpc), tcp only. 
admin_addr = "0.0.0.0:11080" 
proto_type = "tcp4"
#绑定端口(Redis客户端连接此端口)
proxy_addr = "0.0.0.0:19000" 
#外部存储类型 
jodis_name = "zookeeper"
#外部存储列表 
jodis_addr = "172.16.1.111:2181" 
jodis_timeout = "20s"
#会话设置 如果不为0可能导致应用程序出现”write: broken pipe”的问题
session_recv_timeout = "0s" 

#启动程序
nohup ./codis-proxy --ncpu=24 --config=/application/codis/conf/proxy.conf --log=/application/codis/log/proxy.log  &

6.Redis-sentinel

作用:Redis官方推荐的高可用性(HA)解决方案。它可以实现对Redis的监控、通知、自动故障转移。如果Master不能工作,则会自动启动故障转移进程,将其中的一个Slave提升为Master,其他的Slave重新设置新的Master服务
#修改配置 其余节点配置相同
vim /application/codis/conf/sentinel.conf
bind 0.0.0.0 
protected-mode no 
port 26379 
dir /application/codis/data/
scp /application/codis/conf/sentinel.conf [email protected]:/application/codis/conf/
scp /application/codis/conf/sentinel.conf [email protected]:/application/codis/conf/

#启动程序
nohup /application/codis/bin/redis-sentinel /application/codis/conf/sentinel.conf &

7.Codis-fe

作用:集群管理界面。
1)多个集群实例共享可以共享同一个前端展示页面; 
2)通过配置文件管理后端codis-dashboard列表,配置文件可自动更新

#生成配置
cd /application/codis/bin/
./codis-admin --dashboard-list --zookeeper=172.16.1.111:2181 | tee ../conf/codis.json
[
    {
        "name": "my-codis",
        "dashboard": "codis-porxy:18080"
    },
    {
        "name": "codis-chinasoft",
        "dashboard": "172.16.1.150:18080"
    }
]

#启动程序
nohup ./codis-fe --ncpu=1 --log=/application/codis/log/fe.log --log-level=WARN --zookeeper=172.16.1.111:2181 --listen=172.16.1.150:8090 &

#访问172.16.1.150:8090设置

添加proxy

添加codis-server


添加redis-sentinels


配置slots

8.开机自启相关设置

#codis-server+Redis-sentinel
vim /server/scripts/sentinel.sh
if [ $# -eq 0 ]
then
echo "useage:sh $0 {start|stop}"
exit 0
fi
case $1 in
start)
nohup /application/codis/bin/redis-sentinel /application/codis/conf/sentinel.conf &
;;
stop) 
ps -ef|grep redis-sentinel|grep -v grep|awk '{print $2}'|xargs kill
;;
esac
vim /server/scripts/auto_start_codis.sh
 sh /server/scripts/codis-server.sh start
 sh /server/scripts/sentinel.sh start
chmod +x /server/scripts/auto_start_codis.sh
vim /etc/rc.local
 /server/scripts/auto_start_codis.sh
 
#Codis-fe + Codis-proxy + Codis-dashboard
vim /server/scripts/codis.sh
export GO_HOME=/usr/local/go/bin/
if [ $# -eq 0 ]
then
echo "useage:sh $0 {start|stop}"
exit 0
fi
case $1 in
start)
nohup /application/codis/bin/codis-dashboard --ncpu=24 --config=/application/codis/conf/dashboard.conf --log=/application/codis/log/dashboard.log --log-level=WARN &
nohup /application/codis/bin/codis-proxy --ncpu=24 --config=/application/codis/conf/proxy.conf --log=/application/codis/log/proxy.log &
nohup /application/codis/bin/codis-fe --ncpu=1 --log=/application/codis/log/fe.log --log-level=WARN --zookeeper=172.16.1.111:2181 --listen=172.16.1.150:8090 &
;;
stop)
ps -ef|grep codis-proxy|grep -v grep|awk '{print $2}'|xargs kill
ps -ef|grep codis-fe|grep -v grep|awk '{print $2}'|xargs kill
ps -ef|grep codis-dashboar|grep -v grep|awk '{print $2}'|xargs kill
chmod +x /server/scripts/codis.sh
vim /etc/rc.local
 /server/scripts/codis.sh start
 
#由于是测试环境,我经常强制关机,导致codis-dashboard没有正常关闭.直接造成zookeeper里面的状态没有更新,最终新启动的codis-dashboard不能注册进zookeeper,一直提示已存在而被强制关闭. 解决方法如下 删除product
/application/codis/bin/codis-admin --remove-lock --product=my-codis --zookeeper=172.16.1.111:2181
#再次启动
nohup /application/codis/bin/codis-dashboard --ncpu=24 --config=/application/codis/conf/dashboard.conf --log=/application/codis/log/dashboard.log --log-level=WARN &

9.性能测试

redis-benchmark参数解析:

-h    ip地址

-p    redis端口

-a    认证密码

-c    设定多少个并发连接

-n    总共多少个请求

-q    显示模式:简要模式

#集群测试
/application/codis/bin/redis-benchmark -h 172.16.1.150 -p 19000 -a 56789 -c 500 -n 1000000 -q

#单节点测试
/application/codis/bin/redis-benchmark -h 172.16.1.151 -p 6739 -a 56789 -c 500 -n 1000000 -q

10.读写分布测试

vim /server/scripts/test_codis.sh
#!/bin/bash
hos="172.16.1.150"
pot="19000"
pawd="56789"
cli="/application/codis/bin/redis-cli"
keyset="keytest2"
valueset="jlasdnfnsdfsdf;sdfhlkjahsdjlkfadfjkasdbbcjhdgasfyuefkbadjkhflk"
dbname=2
a=0
for i in `seq 1 5000`
do
        $cli -h $hos -p $pot -a $pawd -n $dbname 'set' ${keyset}${a} "${valueset}${a}" >/dev/null
        #echo $a
        let a++
done

sh /server/scripts/test_codis.sh

key基本平均分布在3个组内

11.故障切换测试

#修改一下脚本
vim 
#!/bin/bash
hos="172.16.1.150"
pot="19000"
pawd="56789"
cli="/application/codis/bin/redis-cli"
keyset="test2"
valueset="asdklalksjdklajsdlkajs"
dbname=2
a=0
for i in `seq 1 6000`
do
        $cli -h $hos -p $pot -a $pawd -n $dbname 'set' ${keyset}${a} "${valueset}${a}" >/dev/null
        #echo $a
        let a++
done

sh /server/scripts/test_codis.sh
#查找主库进程ss -ntplu | grep codis-server(172.16.1.152)
tcp    LISTEN     0      128         172.16.1.152:6379         *:*      users:(("codis-server",1068,4))
tcp    LISTEN     0      128         172.16.1.152:6380         *:*      users:(("codis-server",1073,4))
#杀掉主库进程
kill -9 1068

共计5100个KEY 

丢KEY的问题是由于redis-sentinel故障切换期间,整个codis集群并不会关闭对此故障redis-server的连接,所以codis-proxy依然会发送数据给当前故障的redis-server,而显然此时的redis-server是无法存储数据的,这就造成了丢key现象了.如果整个主从挂了,就会丢掉所有发送到此redis-server的key了,除非手工剔除故障节点.

虽然codis还自带有一种故障切换程序codis-ha,他属于一个守护进程,会连接codis-dashboard查看各节点状态,


1

2


#执行一下命令启动codis-ha,端口是codis-dashboard的端口

/usr/local/codis/codis-ha --dashboard=172.16.1.150:18080 --log=/application/codis/log/ha.log --log-level=WARN &

--dashboard    指定dashboard的地址和端口

--log         指定日志文件

--log-level    指定日志等级,有INFO,WARN,DEBUG,ERROR

但是这个软件也是有缺陷,他会自动连接上dashboard检测各主从结构的健康信息,检测间隔很快(默认3秒,可修改参数--interval),检测到故障后,会将故障主库或者从库强制下线并删除在dashboard登记的信息.

虽然切换速度非常快,只会有很少的丢key现象(3秒还是会丢一些),但是后面会把故障旧主库强制下线,需要手动修改配置并重新启动redis-server(codis-server),还要再在codis-fe界面添加配置才行.

显然这是做不到全自动管理,有点麻烦了,而且也会让redis-sentinel变得没有意义了,所以只能两个方式选其一.

虽然看上去丢key现象是少了,但是依然还是有丢key的情况,只能说是50步笑100步,而且该组内其他 slave 实例是不会自动改变状态的,这些 slave 仍将试图从旧的 master 上同步数据,因而会导致组内新的 master 和其他 slave 之间的数据不一致。因此当出现主从切换时,需要管理员手动创建新的 sync action 来完成新 master 与 slave 之间的数据同步,这样反而增加了手动操作的工作量,各位对于codis-ha和redis-sentinel的集群的选择还是需要多考虑一些实际情况.

所以,说到底就是codis的故障切换没有做好,如果对丢key可以容忍的,就开redis-sentinel就足够了,对于数据一致性要求高的,就开codis-ha加脚本来实现比较好,各取所需.


原文地址:http://blog.51cto.com/13712476/2130070

时间: 2024-10-12 22:29:56

十一、codis的相关文章

第十一课——codis-server的高可用,对比codis和redis cluster的优缺点

[作业描述] 1.配置codis-ha 2.总结对比codis的集群方式和redis的cluster集群的优缺点 ================================================================================= 一.codis-ha的部署配置 ##codis-ha要独立于codis集群,单独配置,也是基于go环境的 1.go方式下载codis-ha: go get github.com/ngaut/codis-ha 2.进入cod

android产品研发(二十一)--&gt;UI优化

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android产品研发过程中的代码Review.通过代码Review能够提高产品质量,增强团队成员之间的沟通,提高开发效率,所以良好的产品开发迭代过程中,代码Review是一个必不可少的步骤.那么如何进行代码Review呢?我们主要讲解了团队成员之间的代码Review,代码lint检查,开发规范等方面的知识点,更多关于代码Review相关的知识可参考我的:android产品研发(二十)–>代码Review 本文我们将讲解一下android U

Codis 是一个分布式 Redis 解决方案

Codis源码地址:https://github.com/wandoulabs/codis 关于Codis组件可以参考:https://github.com/wandoulabs/codis/blob/master/doc/tutorial_zh.md 今天分享的这篇文章纯属个人的一些理解和使用的一些心得体会,如果错误也请朋友指出. 更重要的是为了认识一些正在使用或将要使用Codis的朋友有或多或少的帮助. 关于Codis的整体架构和功能介绍官方文档给的在详细不过了,所以我也不想在画蛇添足. 由

荣耀的双十一:为冠军而来

前些日子,第三方数据机构发布报告指出华为手机在出货量方面已经赶超小米,之后又有知名自媒体指出,荣耀仅2014年第一年的销量就达到2000万部,而2015年更是只用半年时间就达到2000万部销量.该自媒体指出,华为在2015年的销量将会铁定超越1亿部,而按照目前发展速度来看,未来荣耀或将实现单品牌赶超小米的速度. 这种磅礴而凶猛的发展势头,使得荣耀对双十一也信心满满. 10月30日,荣耀官方微博发布消息,内容和配图均以"为冠军而来"为口号,力图抢夺双十一手机销量冠军的意图可见一斑.除此之

我的编程之路(二十一) 规范

不知不觉一周就过去了,这周细想真的没有做成什么,因为几乎都是做了改,改了做··· 1.代码规范 以前自认为自己很注重代码规范,但是没有想到自己项目组的开发会将代码规范审查的那么严谨,这突然让我想到之前说到程序员都喜欢追求完美,都喜欢自己和自己的风格一致,否则就会觉得别扭,不过与此不同,这是团队开发,代码规范是为了统一风格,便于别人的阅读与后人的修改与维护,虽然因为这我前前后后改了三次dao层的代码,一是要用公司封装的借口,二是要把异常处理都放在这一层或者service层,三是要用公司自己写的工具

QT开发(二十一)——QT布局管理器

QT开发(二十一)--QT布局管理器 一.布局管理器简介 QT中使用绝对定位的布局方式无法自适应窗口的变化. QT中提供了对界面组件进行布局管理的类,用于对界面组件进行管理,能够自动排列窗口中的界面组件,窗口大小变化后自动更新界面组件的大小. QLayout是QT中布局管理器的抽象基类,通过对QLayout的继承,实现了功能各异且互补的布局管理器. 布局管理器不是界面组件,而是界面组件的定位策略. 任意容器类型的组件都可以指定布局管理器. 同一个布局管理器管理中的组件拥有相同的父组件,在设置布局

struts2官方 中文教程 系列十一:使用XML进行表单验证

在本教程中,我们将讨论如何使用Struts 2的XML验证方法来验证表单字段中用户的输入.在前面的教程中,我们讨论了在Action类中使用validate方法验证用户的输入.使用单独的XML验证文件让您可以内置到Struts 2框架的验证器. 贴个本帖的地址,以免被爬:struts2官方 中文教程 系列十一:使用XML进行表单验证  即 http://www.cnblogs.com/linghaoxinpian/p/6938720.html 下载本章节代码 为了使用户能够编辑存储在Person对

《构建之法》第十一、十二章学习总结

第十一章的内容是软件设计与实现. 在第一节中,讲的是关于分析和设计方法,向我们介绍在"需求分析"."设计与实现"阶段."测试""发布"阶段该搞清楚的问题. 在第二节中,讲的是关于图形建模和分析方法.在表达实体和实体之间的关系时,可以用到思维导图(Mind Map).实体关系图(ERD).UCD ;在表达数据的流动时,可以用到DFD工具:在表达控制流的时候可以用到FSM工具:前面提到的这些图形建模方法各有特点,UML却可以有一个

安装codis 以及遇到的一些问题

redis集群安装用的是codis ,由豌豆荚开源,相比较twemproxy的好处有很多,参考http://blog.csdn.net/hunci/article/details/51799468 不废话,搞起 下面的安装文档抄袭了小炒肉的,连接如下 https://www.kissni.com/2017/04/06/codis-redis/ 但是部署中也遇到了一些问题 1,在codis make 的时候出现错误 go build -i -o bin/codis-dashboard ./cmd/