├── README ├── twine-backup.sh ├── twine-install-centos-deprecated.sh ├── twine-install.sh ├── twine-restore.sh ├── twine-setup.sh ├── twine-start.sh ├── twine-stop.sh ├── twine.conf └── twine.sh /README: -------------------------------------------------------------------------------- 1 | ======================================== 2 | Twine 3 | 4 | "a bundle of redis threads" 5 | 6 | Utilities maintaining and querying a replicated 7 | partitioned (shard) Redis cluster 8 | 9 | Formerly named 'Roma' 10 | ======================================== 11 | 12 | 13 | ======================================== 14 | Contents 15 | ======================================== 16 | 17 | * Quick Start 18 | * Poetic License 19 | * Introduction 20 | * Note on Partitions (Sharding) 21 | * Configuration 22 | o twine.conf 23 | o redis.conf 24 | o monitrc 25 | * Core utilities 26 | o twine-install 27 | o twine-setup 28 | o twine-start 29 | o twine-stop 30 | * Monit control 31 | * Append only file 32 | * Twine Name 33 | 34 | 35 | ======================================== 36 | Quick Start 37 | ======================================== 38 | 39 | $ git clone git://github.com/alexgenaud/twine.git 40 | $ cd twine 41 | $ bash twine-install.sh 42 | $ bash twine-setup.sh localhost 43 | 44 | $ bash twine-start.sh 45 | $ monit -c partitions/localhost/monit/monitrc 46 | 47 | $ monit -c partitions/localhost/monit/monitrc stop all 48 | $ bash twine-stop.sh 49 | $ monit -c partitions/localhost/monit/monitrc quit 50 | 51 | 52 | ======================================== 53 | Poetic License 54 | ======================================== 55 | 56 | (c) 2010 Alexander E Genaud 57 | 58 | This work ‘as-is’ we provide. 59 | No warranty express or implied. 60 | We’ve done our best, 61 | to debug and test. 62 | Liability for damages denied. 63 | 64 | Permission is granted hereby, 65 | to copy, share, and modify. 66 | Use as is fit, 67 | free or for profit. 68 | On this notice, these rights rely. 69 | 70 | 71 | ======================================== 72 | Introduction 73 | ======================================== 74 | 75 | Twine is a set of utilities that should help you get a partitioned 76 | redis cluster up and running quickly. It handles failover using monit. 77 | 78 | Twine does not yet promote slaves to masters. However, with enough 79 | partitions, it is often faster and infinitely easier to bring failed 80 | masters back online than to reconfigure slaves, masters, and clients. 81 | 82 | Monit can be configured to monitor the cluster every second. Again, 83 | with enough partitions, each node can be very small and thus come back 84 | up to speed in seconds or less. 85 | 86 | A backup is simply a matter of copying (or zipping) the partition 87 | directory on each host. And restoration is the reverse. 88 | 89 | 90 | ======================================== 91 | Note on Partitions (Sharding) 92 | ======================================== 93 | 94 | Querying a partitioned cluster is the responsibility of the client 95 | (perhaps I can share some Java code shortly). Basically, a client 96 | should use the same twine.conf with the client and redis cluster. 97 | After all, it defines the various redis nodes and their partition 98 | number. For every key-value query, the client must first hash the 99 | key and apply a modulo to obtain the partition to query. 100 | 101 | For example, we could set and get from 64 partitions (shards), each 102 | in its own redis data node on ports 4200 to 4263 on localhost: 103 | 104 | redis-cli -p (hash(key) % 64) set key value 105 | redis-cli -p (hash(key) % 64) get key 106 | 107 | 108 | ======================================== 109 | Configuration 110 | ======================================== 111 | 112 | Twine consists of three configuration file types. There is a single 113 | twine.conf file which specifies the redis nodes, partitions, and 114 | network location. Each redis node has its own redis.conf, though these 115 | are quite similar to each other. Finally, each host will have its 116 | own monitrc file. 117 | 118 | twine.conf 119 | a simple config file which consists of redis node names, types 120 | (data or status), partition number, host, port, and database 121 | number. For example, the last line of a 64 part cluster might 122 | look like this: 123 | 124 | b4263=data 63 127.0.0.1 4263 0 125 | 126 | redis.conf 127 | This is standard redis configuration file minus all the 128 | comments. By default, the redis data nodes of a twine cluster 129 | will write data asynchronously at least once per minute. All 130 | of this can be changed either in the various redis.conf or in 131 | twine-setup that generates them. 132 | 133 | monitrc 134 | monitrc is used by monit - a unix service monitor. One monitrc 135 | is generated by twine-setup for each host. The first line tells 136 | monit how often it should check the cluster. By default, it is 137 | set to five seconds. Httpd is required for some basic queries 138 | like status and summary. 139 | 140 | 141 | ======================================== 142 | Core utilities 143 | ======================================== 144 | 145 | twine (not yet available) 146 | wraps redis-cli, but hashes the key 147 | and executes the command on the 148 | appropriate partition (shard) 149 | 150 | twined (not yet available) 151 | daemon (of which there may be many) 152 | which monitors the cluster. It 153 | competes with any other twined for 154 | alpha position. The alpha sets the 155 | cluster status and handles fail-over. 156 | It can be configured to send an email 157 | if the status is HALT or any Redis 158 | node is down for more than x seconds. 159 | 160 | twine-setup [host] 161 | creates the entire cluster plumbing by default 162 | including all partitions and redis.conf 163 | according to the twine.conf. Optionally takes 164 | a host name as arguement. This is convenient for 165 | setting up each machine using the same twine.conf 166 | file. The host name must be listed in the twine.conf 167 | file. 168 | 169 | twine-start [host] 170 | starts the entire cluster according 171 | to the twine.conf configuration file 172 | (must be run separately per machine) 173 | 174 | twine-stop [host] 175 | stops the entire cluster according 176 | to the twine.conf configuration file 177 | 178 | twine-status (not yet available) 179 | returns the cluster status in various 180 | formats: summary, list, xml, html 181 | 182 | twine-hash (not yet available) 183 | A plug-able hash function wrapper 184 | which accepts two arguments: 185 | a single 7-bit ASCII string (key) 186 | and a modulus (number of partitions). 187 | It returns the partition number. 188 | 189 | twine-backup (not yet available) 190 | backs up the entire cluster to 191 | directory(ies) according to twine.conf 192 | 193 | twine-restore (not yet available) 194 | overwrites all cluster data from a 195 | previous backup. 196 | 197 | 198 | ======================================== 199 | Monit control 200 | ======================================== 201 | 202 | Twine-setup configures a monitrc control file for 203 | each host, found in partitions/HOSTNAME/monit. 204 | 205 | It is worth editing the monitrc file (or twine-setup) 206 | to configure how often (in seconds) monit checks the status 207 | of the cluster (first line set daemon x). Also, mail 208 | alerts are worth configuring, or removing so as not to 209 | clutter the log files. 210 | 211 | To start monit: 212 | 213 | monit -c partitions/HOSTNAME/monit/monitrc 214 | 215 | Try to kill some or all of the redis nodes (not in production, of 216 | course) with the following commands and see how quickly monit 217 | brings them back to life: 218 | 219 | partitions/HOSTNAME/NODENAME/stop.sh 220 | or 221 | kill -9 222 | or 223 | sh twine-stop.sh 224 | 225 | If find the following alias helpful, which displays monit and 226 | redis processes: 227 | 228 | alias psef='ps -ef | grep -v volume-monitor | grep "[rm][eo][dn]i[st]"' 229 | 230 | When the monitrc file is to your liking, you will probably want to 231 | move it to '/etc/monit/monitrc' and/or run it automatically on startup, 232 | from init.d. 233 | 234 | http://mmonit.com/wiki/Monit/FAQ#init 235 | 236 | 237 | ======================================== 238 | Append only file 239 | ======================================== 240 | 241 | Twine-setup contains a variable at the top APPENDONLY=yes|no 242 | which sets each redis not in the cluster to save using 243 | either the original asynchronous database dump (no) or the 244 | new append only journalling (yes). 245 | 246 | Setting APPENDONLY to 'yes' will create a script in 247 | partitions/HOSTNAME/appendonly/appendonly.sh which can be 248 | invoked by crontab. This script will compact the journal 249 | file asynchronously. 250 | 251 | http://code.google.com/p/redis/wiki/BgrewriteaofCommand 252 | 253 | 254 | ======================================== 255 | Twine Name 256 | ======================================== 257 | 258 | Why Twine? Twine is a strong chord consisting of multiple threads. 259 | Twine is used to bind things together. Likewise Twine, the utility, 260 | helps bind a cluster of Redis threads. 261 | 262 | What about Roma? Well, within two hours of creating the public github 263 | repo, I was informed by two people that there was a distributed key- 264 | value store named Roma and the names might confuse people. I agreed. 265 | -------------------------------------------------------------------------------- /twine-backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p backup 3 | DATE=`date -u +%Y%m%d.%H%M%S` 4 | echo backup/partitions.$DATE.zip 5 | zip -9ryq backup/partitions.$DATE.zip partitions 6 | -------------------------------------------------------------------------------- /twine-install-centos-deprecated.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # redisversion=redis-1.1.91-beta 4 | redisversion=redis-1.2.2 5 | 6 | # 7 | # Check whether this version of redis is already installed 8 | # 9 | if [ -d $redisversion ]; then 10 | echo ============================= 11 | echo FAILURE: $redisversion is already installed. 12 | echo If you really want to reinstall, 13 | echo you will have to remove it yourself 14 | echo ============================= 15 | exit -1 16 | fi 17 | 18 | # 19 | # Check whether any redis-server* is running 20 | # 21 | if [ `ps ax | grep redis-server | grep -v grep | wc -l` -gt 0 ]; then 22 | echo ============================= 23 | echo FAILED redis-server or partition is already running 24 | echo You must manually \"kill -9 PID\" 25 | echo perhaps: `ps ax | grep redis-server | grep -v grep | sed "s: .*::" | sed "s:^:kill -9 :"` 26 | echo ============================= 27 | ps ax | grep redis-server | grep -v grep 28 | echo ============================= 29 | exit -1 30 | fi 31 | 32 | # 33 | # Set the 'skip' command line argument 34 | # (undocumented feature) 35 | # if set, skip installing gcc, make test, and benchmark 36 | # 37 | if [ "$1" = "skip" ]; then 38 | skip=skip 39 | fi 40 | 41 | if [ ! $skip ]; then 42 | 43 | echo ============================= 44 | echo Installing gcc 45 | echo ============================= 46 | 47 | yum install gcc 48 | 49 | fi 50 | 51 | echo ============================= 52 | echo Extracting $redisversion 53 | echo ============================= 54 | 55 | tar xf ${redisversion}.tar.gz 56 | 57 | # 58 | # Change to newly extracted directory 59 | # 60 | cd $redisversion 61 | 62 | echo ============================= 63 | echo Compiling $redisversion 64 | echo ============================= 65 | 66 | make 67 | 68 | echo ============================= 69 | echo Starting server 70 | echo in the background 71 | echo ============================= 72 | 73 | ./redis-server > test-server.log & 74 | 75 | if [ ! $skip ]; then 76 | 77 | echo ============================= 78 | echo Running test 79 | echo ============================= 80 | 81 | make test 82 | 83 | echo ============================= 84 | echo Running benchmark 85 | echo ============================= 86 | 87 | ./redis-benchmark 88 | 89 | fi 90 | 91 | # echo ============================= 92 | # echo Cleanup source, etc 93 | # echo ============================= 94 | # 95 | # mkdir src 96 | # mv -f 00* *.c *.h *.o *txt BUGS Changelog client-libraries COPYING design-documents doc Makefile README redis.conf redis-benchmark TODO utils redis.tcl test-redis.tcl src 97 | 98 | # 99 | # Kill the redis-server process 100 | # 101 | echo ============================= 102 | echo Killing redis-server used in tests 103 | ps ax | grep redis-server | grep -v grep | sed "s: .*::" | sed "s:^:kill -9 :" | sh 104 | if [ `ps ax | grep [0-9]../redis-server | wc -l` -gt 0 ]; then 105 | echo FAILED to kill process 106 | echo You must manually \"kill -9 PID\" 107 | echo perhaps: `ps ax | grep redis-server | grep -v grep | sed "s: .*::" | sed "s:^:kill -9 :"` 108 | fi 109 | echo ============================= 110 | rm -f dump.rdb 111 | cd .. 112 | 113 | echo ============================= 114 | echo Done 115 | echo ============================= 116 | -------------------------------------------------------------------------------- /twine-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | redisversion=redis-1.2.6 4 | 5 | # 6 | # Check whether any redis-server* is running 7 | # 8 | if [ `ps ax | grep redis-server | grep -v grep | wc -l` -gt 0 ]; then 9 | echo ============================= 10 | echo FAILED redis-server or partition is already running 11 | echo You must manually \"kill -9 PID\" 12 | echo perhaps: `ps ax | grep redis-server | grep -v grep | sed "s: .*::" | sed "s:^:kill -9 :"` 13 | echo or run twine-stop.sh 14 | echo ============================= 15 | ps ax | grep redis-server | grep -v grep 16 | echo ============================= 17 | exit -1 18 | fi 19 | 20 | echo ============================= 21 | echo Installing gcc and monit 22 | echo ============================= 23 | 24 | if [ `uname -v | grep Ubuntu | wc -c` -gt 6 ]; then 25 | sudo apt-get install gcc monit 26 | else # gross assumption yum, redhat, centos 27 | yum install gcc monit 28 | fi 29 | 30 | if ! [ -e ${redisversion}.tar.gz ]; then 31 | echo ============================= 32 | echo Downloading $redisversion 33 | echo ============================= 34 | 35 | wget http://redis.googlecode.com/files/${redisversion}.tar.gz 36 | fi 37 | 38 | 39 | # 40 | # Check whether this version of redis is already extracted 41 | # 42 | if [ -d $redisversion ]; then 43 | echo ============================= 44 | echo Already extracted $redisversion 45 | echo ============================= 46 | else 47 | echo ============================= 48 | echo Extracting $redisversion 49 | echo ============================= 50 | 51 | tar xf ${redisversion}.tar.gz 52 | fi 53 | 54 | # 55 | # Change to newly extracted directory 56 | # 57 | cd $redisversion 58 | 59 | if [ -e redis-server ]; then 60 | echo ============================= 61 | echo Already compiled $redisversion 62 | echo ============================= 63 | else 64 | echo ============================= 65 | echo Compiling $redisversion 66 | echo ============================= 67 | 68 | make 69 | fi 70 | 71 | if [ -r test-server.log ]; then 72 | echo ============================= 73 | echo Skipping test and benchmark 74 | echo ============================= 75 | else 76 | ./redis-server > test-server.log & 77 | 78 | echo ============================= 79 | echo Running test 80 | echo ============================= 81 | 82 | make test 83 | 84 | echo ============================= 85 | echo Running benchmark 86 | echo ============================= 87 | 88 | ./redis-benchmark 89 | 90 | # echo ============================= 91 | # echo Cleanup source, etc 92 | # echo ============================= 93 | # 94 | # mkdir src 95 | # mv -f 00* *.c *.h *.o *txt BUGS Changelog client-libraries COPYING design-documents doc Makefile README redis.conf redis-benchmark TODO utils redis.tcl test-redis.tcl src 96 | 97 | # 98 | # Kill the redis-server process 99 | # 100 | echo ============================= 101 | echo Killing redis-server used in tests 102 | ps ax | grep redis-server | grep -v grep | sed "s: [a-z].*::" | sed "s:^:kill -9 :" | sh 103 | if [ `ps ax | grep -v grep | grep [0-9]../redis-server | wc -l` -gt 0 ]; then 104 | echo FAILED to kill process 105 | echo You must manually \"kill -9 PID\" 106 | echo perhaps: `ps ax | grep redis-server | grep -v grep | sed "s: [a-z].*::" | sed "s:^:kill -9 :"` 107 | echo or run twine-stop.sh 108 | fi 109 | echo ============================= 110 | rm -f dump.rdb 111 | fi 112 | 113 | # 114 | # leave the redis directory 115 | # 116 | cd .. 117 | 118 | echo ============================= 119 | echo Done 120 | echo ============================= 121 | -------------------------------------------------------------------------------- /twine-restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -lt 1 ]; then 4 | echo FAILURE: usage twine-restore archive.zip 5 | exit 1 6 | elif [ `unzip -t $1|grep "No errors detected"|wc -l` -ne 1 ]; then 7 | echo FAILURE: usage twine-restore archive.zip 8 | exit 1 9 | elif [ -r partitions ]; then 10 | mkdir -p backup 11 | DATE=`date -u +%Y%m%d.%H%M%S` 12 | echo backup/partitions.mv.$DATE.zip 13 | zip -9ryq backup/partitions.mv.$DATE.zip partitions 14 | rm -rf partitions 15 | fi 16 | unzip -q $1 17 | exit 0 18 | -------------------------------------------------------------------------------- /twine-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | REDISVERSION=redis-1.2.6 4 | SERVERSUFFIX=redis-server-1.2.6 5 | MONIT_DAEMON_SEC=1 6 | REDIS_SAVE_SEC=10 7 | USE_HOST=$1 8 | APPENDONLY=no 9 | 10 | if [ $# -lt 1 ] ; then 11 | echo twine-setup all partitions for all hosts 12 | else 13 | echo twine-setup only partitions for host: $1 14 | fi 15 | 16 | # check that the twine.conf file exists and is readable 17 | if ! [ -r twine.conf ]; then 18 | echo ============================= 19 | echo Error: Unable to read twine.conf 20 | echo ============================= 21 | exit 1 22 | fi 23 | 24 | # check that every line of twine.conf is valid 25 | cat twine.conf | while read -r LINE; do 26 | if [ `echo $LINE | grep -E \ 27 | "^[a-zA-Z0-9\._-]+=(data [0-9]+|status) [a-zA-Z0-9\._-]+ [0-9]+ [0-9]+$"\ 28 | | wc -c` -gt 20 ]; then 29 | continue; 30 | elif [ `echo $LINE | grep "^#" | wc -l` = 1 ]; then 31 | continue; 32 | elif [ `echo $LINE | grep "^[\w]*$" | wc -l` = 1 ]; then 33 | continue; 34 | else 35 | echo ============================= 36 | echo Error in twine.conf 37 | echo INVALID: $LINE 38 | echo ============================= 39 | exit 1 40 | fi 41 | done 42 | 43 | # check that partitions directory does not exist 44 | if [ -e partitions ]; then 45 | echo ============================= 46 | echo Error: partitions directory already exists 47 | echo ============================= 48 | exit 1 49 | fi 50 | 51 | echo ============================= 52 | echo Creating partitions directory 53 | echo ============================= 54 | mkdir partitions 55 | 56 | 57 | cat twine.conf | while read -r LINE; do 58 | if [ `echo $LINE | grep -E \ 59 | "^[a-zA-Z0-9\._-]+=(data [0-9]+|status) [a-zA-Z0-9\._-]+ [0-9]+ [0-9]+$"\ 60 | | wc -c` -gt 20 ]; then 61 | if [ `echo $LINE | grep "^.*data" | wc -c` -gt 20 ]; then 62 | LINETYPE=data 63 | NAME=`echo $LINE |sed s:=.*::` 64 | PART=`echo $LINE |awk '{ print $2 }'` 65 | HOST=`echo $LINE |awk '{ print $3 }'` 66 | PORT=`echo $LINE |awk '{ print $4 }'` 67 | DB=`echo $LINE |awk '{ print $5 }'` 68 | elif [ `echo $LINE | grep "^.*=status" | wc -c` -gt 20 ]; then 69 | LINETYPE=status 70 | NAME=`echo $LINE |sed s:=.*::` 71 | HOST=`echo $LINE |awk '{ print $2 }'` 72 | PORT=`echo $LINE |awk '{ print $3 }'` 73 | DB=`echo $LINE |awk '{ print $4 }'` 74 | else 75 | echo NONESENSE 76 | fi # data or status line 77 | 78 | if [ "_${USE_HOST}" != "_" -a "_${USE_HOST}" != "_${HOST}" ]; then 79 | continue 80 | fi 81 | 82 | PART_PATH=partitions/$HOST/$NAME 83 | echo Creating $HOST/${NAME}-${SERVERSUFFIX} 84 | if [ -e $PART_PATH ]; then 85 | echo ============================= 86 | echo Error: $PART_PATH already exists 87 | echo ============================= 88 | exit 1 89 | fi 90 | mkdir -p $PART_PATH 91 | 92 | # create redis.conf file 93 | CONFIG=${PART_PATH}/redis.conf 94 | ln -s $PWD/$REDISVERSION/redis-server \ 95 | ${PART_PATH}/${NAME}-${SERVERSUFFIX} 96 | echo daemonize yes > $CONFIG 97 | echo pidfile ${PWD}/${PART_PATH}/redis.pid >> $CONFIG 98 | echo port $PORT >> $CONFIG 99 | echo timeout 300 >> $CONFIG 100 | echo loglevel notice >> $CONFIG 101 | echo logfile redis.log >> $CONFIG 102 | echo databases 1 >> $CONFIG 103 | if [ "_${APPENDONLY}" = "_yes" ]; then 104 | # Journalled Save 105 | echo appendonly yes >> $CONFIG 106 | echo appendfsync everysec >> $CONFIG 107 | else 108 | # Async Save 109 | # after 5 seconds if at least one key changed 110 | # echo save $REDIS_SAVE_SEC 1 >> $CONFIG 111 | echo save 1 1 >> $CONFIG 112 | echo appendonly no >> $CONFIG 113 | echo rdbcompression yes >> $CONFIG 114 | echo dbfilename dump.rdb >> $CONFIG 115 | fi 116 | echo dir ./ >> $CONFIG 117 | echo glueoutputbuf yes >> $CONFIG 118 | echo shareobjects no >> $CONFIG 119 | 120 | # create start.sh file 121 | echo cd \"${PWD}/${PART_PATH}\" > ${PART_PATH}/start.sh 122 | echo echo -n Starting ${NAME}-${SERVERSUFFIX}\" \" >> ${PART_PATH}/start.sh 123 | echo ./${NAME}-${SERVERSUFFIX} redis.conf 1\> access.log 2\> error.log \& >> ${PART_PATH}/start.sh 124 | # echo ps -ef\|grep \$\$\|grep ${NAME}-${SERVERSUFFIX}\|grep -v \$0\|awk \'{ print \$2 }\' \> redis.pid >> ${PART_PATH}/start.sh 125 | # echo if ! [ -r redis.pid ]\; then sleep 1 >> ${PART_PATH}/start.sh 126 | # echo elif ! [ -r redis.pid ]\; then sleep 3 >> ${PART_PATH}/start.sh 127 | # echo elif ! [ -r redis.pid ]\; then sleep 10 >> ${PART_PATH}/start.sh 128 | # echo fi >> ${PART_PATH}/start.sh 129 | echo echo pid: \`cat redis.pid\` >> ${PART_PATH}/start.sh 130 | 131 | 132 | # create stop.sh file 133 | echo cd \"${PWD}/${PART_PATH}\" > ${PART_PATH}/stop.sh 134 | echo echo Stopping ${NAME}-${SERVERSUFFIX} pid: \`cat redis.pid\` >> ${PART_PATH}/stop.sh 135 | echo echo SHUTDOWN \| nc $HOST $PORT >> ${PART_PATH}/stop.sh 136 | echo rm -f redis.pid >> ${PART_PATH}/stop.sh 137 | 138 | # create appendonly bg rewrite script 139 | if [ "_$APPENDONLY" = "_yes" ]; then 140 | # create appendonly save 141 | AOFRC=partitions/$HOST/appendonly/appendonly.sh 142 | if ! [ -r $AOFRC ]; then 143 | mkdir -p partitions/$HOST/appendonly 144 | echo \#!`which dash` > $AOFRC 145 | echo echo \$\$ \> ${PWD}/partitions/$HOST/appendonly/appendonly.pid >> $AOFRC 146 | fi 147 | echo sleep $REDIS_SAVE_SEC >> $AOFRC 148 | echo ${PWD}/${REDISVERSION}/redis-cli -p $PORT Bgrewriteaof >> $AOFRC 149 | fi 150 | 151 | # create monitrc 152 | MONITRC=partitions/$HOST/monit/monitrc 153 | if ! [ -r $MONITRC ]; then 154 | mkdir -p partitions/$HOST/monit 155 | echo set daemon $MONIT_DAEMON_SEC > $MONITRC 156 | echo set httpd port 4280 >> $MONITRC 157 | echo allow localhost >> $MONITRC 158 | echo set logfile ${PWD}/partitions/${HOST}/monit/logfile >> $MONITRC 159 | #echo set mailserver localhost >> $MONITRC 160 | #echo set alert foo@bar.baz >> $MONITRC 161 | echo >> $MONITRC 162 | echo check system localhost >> $MONITRC 163 | echo if loadavg \(1min\) \> 4 then alert >> $MONITRC 164 | echo if loadavg \(5min\) \> 2 then alert >> $MONITRC 165 | echo if memory usage \> 50% then alert >> $MONITRC 166 | echo if cpu usage \(user\) \> 90% then alert >> $MONITRC 167 | echo if cpu usage \(system\) \> 70% then alert >> $MONITRC 168 | echo >> $MONITRC 169 | 170 | chmod 700 $MONITRC 171 | fi 172 | 173 | echo check process ${NAME} >> $MONITRC 174 | echo with pidfile \"${PWD}/${PART_PATH}/redis.pid\" >> $MONITRC 175 | echo start program = \"`which bash` ${PWD}/${PART_PATH}/start.sh\" >> $MONITRC 176 | echo stop program = \"`which bash` ${PWD}/${PART_PATH}/stop.sh\" >> $MONITRC 177 | echo if failed host localhost port $PORT then restart >> $MONITRC 178 | echo if 5 restarts within 5 cycles then timeout >> $MONITRC 179 | echo >> $MONITRC 180 | 181 | fi # data|status 182 | done 183 | 184 | exit 185 | -------------------------------------------------------------------------------- /twine-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SERVERSUFFIX=redis-server-1.2.6 4 | USE_HOST=$1 5 | 6 | # if no arguments, then we must be sure 7 | # there is only one host in the partitions directory 8 | if [ $# -eq 0 ]; then 9 | USE_HOST=_BOGUS_DIRECTORY_ 10 | if [ `ls partitions|wc -l` -eq 1 ]; then 11 | if [ -r partitions/`ls partitions` ]; then 12 | USE_HOST=`ls partitions` 13 | fi 14 | fi 15 | fi 16 | 17 | if ! [ -r partitions/$USE_HOST ]; then 18 | echo usage: twine-start HOST 19 | ls partitions 20 | exit 1 21 | fi 22 | 23 | cd partitions/${USE_HOST} 24 | for server in `find -mindepth 1 -maxdepth 1 -type d`; do 25 | if [ -r ${server}/start.sh ]; then 26 | cd $server 27 | sh start.sh 28 | cd .. 29 | fi 30 | done; 31 | cd ../.. 32 | 33 | exit 0 34 | -------------------------------------------------------------------------------- /twine-stop.sh: -------------------------------------------------------------------------------- 1 | if [ -r partitions ]; then 2 | find partitions -name redis.pid|\ 3 | sed s:redis.pid:stop.sh:|sed s:^:sh\ :|sh 4 | fi 5 | ps ax | grep redis-server | grep -v grep |\ 6 | sed "s: [a-z].*::" | sed "s:^:kill -9 :" | sh 7 | 8 | -------------------------------------------------------------------------------- /twine.conf: -------------------------------------------------------------------------------- 1 | # 2 | # one shard cluster (perhaps on one machine) 3 | # 4 | a4200=data 0 localhost 4200 0 5 | a4201=data 1 localhost 4201 0 6 | a4202=data 2 localhost 4202 0 7 | a4203=data 3 localhost 4203 0 8 | a4204=data 4 localhost 4204 0 9 | a4205=data 5 localhost 4205 0 10 | a4206=data 6 localhost 4206 0 11 | a4207=data 7 localhost 4207 0 12 | a4208=data 8 localhost 4208 0 13 | a4209=data 9 localhost 4209 0 14 | a4210=data 10 localhost 4210 0 15 | a4211=data 11 localhost 4211 0 16 | a4212=data 12 localhost 4212 0 17 | a4213=data 13 localhost 4213 0 18 | a4214=data 14 localhost 4214 0 19 | a4215=data 15 localhost 4215 0 20 | a4216=data 16 localhost 4216 0 21 | a4217=data 17 localhost 4217 0 22 | a4218=data 18 localhost 4218 0 23 | a4219=data 19 localhost 4219 0 24 | a4220=data 20 localhost 4220 0 25 | a4221=data 21 localhost 4221 0 26 | a4222=data 22 localhost 4222 0 27 | a4223=data 23 localhost 4223 0 28 | a4224=data 24 localhost 4224 0 29 | a4225=data 25 localhost 4225 0 30 | a4226=data 26 localhost 4226 0 31 | a4227=data 27 localhost 4227 0 32 | a4228=data 28 localhost 4228 0 33 | a4229=data 29 localhost 4229 0 34 | a4230=data 30 localhost 4230 0 35 | a4231=data 31 localhost 4231 0 36 | 37 | # 38 | # another shard cluster (perhaps on another machine) 39 | # 40 | b4232=data 32 127.0.0.1 4232 0 41 | b4233=data 33 127.0.0.1 4233 0 42 | b4234=data 34 127.0.0.1 4234 0 43 | b4235=data 35 127.0.0.1 4235 0 44 | b4236=data 36 127.0.0.1 4236 0 45 | b4237=data 37 127.0.0.1 4237 0 46 | b4238=data 38 127.0.0.1 4238 0 47 | b4239=data 39 127.0.0.1 4239 0 48 | b4240=data 40 127.0.0.1 4240 0 49 | b4241=data 41 127.0.0.1 4241 0 50 | b4242=data 42 127.0.0.1 4242 0 51 | b4243=data 43 127.0.0.1 4243 0 52 | b4244=data 44 127.0.0.1 4244 0 53 | b4245=data 45 127.0.0.1 4245 0 54 | b4246=data 46 127.0.0.1 4246 0 55 | b4247=data 47 127.0.0.1 4247 0 56 | b4248=data 48 127.0.0.1 4248 0 57 | b4249=data 49 127.0.0.1 4249 0 58 | b4250=data 50 127.0.0.1 4250 0 59 | b4251=data 51 127.0.0.1 4251 0 60 | b4252=data 52 127.0.0.1 4252 0 61 | b4253=data 53 127.0.0.1 4253 0 62 | b4254=data 54 127.0.0.1 4254 0 63 | b4255=data 55 127.0.0.1 4255 0 64 | b4256=data 56 127.0.0.1 4256 0 65 | b4257=data 57 127.0.0.1 4257 0 66 | b4258=data 58 127.0.0.1 4258 0 67 | b4259=data 59 127.0.0.1 4259 0 68 | b4260=data 60 127.0.0.1 4260 0 69 | b4261=data 61 127.0.0.1 4261 0 70 | b4262=data 62 127.0.0.1 4262 0 71 | b4263=data 63 127.0.0.1 4263 0 72 | 73 | -------------------------------------------------------------------------------- /twine.sh: -------------------------------------------------------------------------------- 1 | #~/bin/bash 2 | 3 | REDISVERSION=redis-1.2.6 4 | CMD= 5 | KEY= 6 | VAL= 7 | 8 | if [ `echo $1 | grep -Ei "^(randomkey)$" | wc -l` = 1 ]; then 9 | CMD=$1 10 | elif [ `echo $1 | grep -Ei \ 11 | "^(exists|dlel|type|get|expire|ttl|getset|incr|decr|llen)$"\ 12 | | wc -l` = 1 ]; then 13 | CMD=$1 14 | KEY=$2 15 | elif [ `echo $1 | grep -Ei \ 16 | "(set|incrby|decrby|rpush|lpush)"\ 17 | | wc -l` = 1 ]; then 18 | CMD=$1 19 | KEY=$2 20 | VAL=$3 21 | else 22 | echo unsupported command 23 | exit 1 24 | fi 25 | 26 | 27 | HASH=`sh twine-hash.sh $KEY 1234568` 28 | 29 | 30 | # lookup the hash mod number in status node 31 | # to get the host/ip, port, and database of 32 | # the appropriate master for this hash val 33 | HOST=localhost 34 | PORT=4200 35 | DB=0 36 | 37 | $REDISVERSION/redis-cli -h $HOST -p $PORT -n $DB $CMD $KEY $VAL 38 | 39 | --------------------------------------------------------------------------------