阿里云redis数据迁移
一般来讲,如果我们要从自建的redia迁移到阿里的redis,可以采用aof文件的办法,通过:
1 |
CONFIG SET appendonly yes |
创建一个aof文件,也可能你的配置下本来就有这个文件,然后通过:
1 |
tail -n $big_number -f appendonly.aof |redis-cli target_host target_port |
其中 $big_number 是一个足够大的数,保证tail是从文件的第一行开始的,如此,则可以保证源redis和目标redis的数据是一致的,代码上修改完配置后,源redis不再有写入,即可废掉源redis
由于阿里云的redis没有一个可以供我们tail的aof文件,所以,没法通过上述办法将阿里云redis数据平滑迁移到本地(抑或是阿里云其他)redis实例,不过也可以有不太平滑的办法的。
阿里云redis的备份其实就是一个rdb文件,只需要:
方案一:
- 停掉redis
- 创建redis备份 (这个在阿里云控制台是支持的)
- 下载备份
- 根据备份启动redis实例
- 生成一个aof文件
- cat aof | redis-cli target_host target_port 即可
- 如果需要在迁移的同时修改db号,即: 将db 1 中的数据迁移到db 2中,可参考: https://phpor.net/blog/post/5614
- 该方案需要暂停服务的
方案二:
- 使用工具 https://github.com/vipshop/redis-migrate-tool https://q.cnblogs.com/q/93181/
- 该方案没法将源db修改成目标的其他db
方案三:
bash 之echo vs printf
没有发现如何仅仅通过echo 直接输出 ‘-e’ 的方法, printf则可以 — 使得不再继续解析更多选项。
If you want to literally print the string “-e”, you will have difficulties doing it with echo. I faced such a problem recently while writing a script.
I had to use prinf to be able to print the literal string “-e”.
bash 之 echo -e
示例:
1 2 3 |
#echo -e "a\nb" a b |
如果我仅仅想输出 ‘-e’ 呢?如何echo 呢?
1 |
#echo -e |
这个是不会有任何输出的,当然,你可能马上就发现问题了; 不过,有些情况下,你想echo的东西是预先不知道的,实在程序运行时生成的,万一生成了 ‘-e’ ,你将看不到 ‘-e’ ,而且还影响了程序的行为,如何避免呢?
gnocchi-api 访问慢的问题
gnocchi-api 访问基本在10s +, why ?
gnocchi-api 使用了 wsgiref , wsgiref 使用了 :
/usr/bin/gnocchi-api:
1 |
server = wss.make_server(args.host, args.port, build_wsgi_app()) |
/usr/lib64/python2.7/wsgiref/simple_server.py :
(这里提到了个REMOTE_HOST的环境变量,含义就是“REMOTE_ADDR 对应的域名”, 而 address_string() 的命名也是ip地址对应的域名的意思,因为绝大部分的ip地址是反解不到域名的,所以,这个逻辑基本可以注释掉,不过,直接修改人家的代码不大好)
然而上面的 WSGIRequestHandler 基本上会执行到get_environ() , 进而执行到 BaseHTTPServer.py 中的 self.address_string() ,如下:
address_string() 函数又调用了 /usr/lib64/python2.7/socket.py 中的 getfqdn(), 如下:
然后就肯定会执行到gethostbtaddr() 了,该函数的具体实现又是什么逻辑呢? socket.py import了 _socket 模块中的所有函数,而gethostbyaddr()正是_socket 模块实现的,_socket 模块的实现见: /usr/lib64/python2.7/lib-dynload/_socketmodule.so , 可见,这是一个c实现的so文件,稍后再看:
测试发现,该函数当遇到IP地址时,肯定会做一次反向地址解析,反向地址解析不是所有dns都能支持的很好的,有些能快速返回,有些却不能(具体原因,稍后再查),比如: 公网地址的反向地址解析可以很快返回,私网地址的反向地址解析就很慢
解决办法:
办法一: 在 dns 上给自己的IP地址添加反向地址解析,这样反向地址解析就可以很快; 给每个IP地址都添加反向地址解析的话,比较麻烦,最好能有一个更好的办法,让某一类IP地址能直接返回错误,或返回一个自定义的域名; 这个办法的优点是: 不需要修改程序 ; 如果搞不定dns,那就修改程序吧
办法二: 修改/usr/lib64/python2.7/BaseHTTPServer.py ,在 address_string() 中直接返回host,而不进行socket.getfqdn(host) 的调用
办法三: 修改 /usr/lib64/python2.7/socket.py 中的 getfqdn() 函数,对于ip地址的情况,不再调用 gethostbyaddr()
办法四: 其实,不是特别有信心的话,不要修改的太底层,没准儿影响到别的程序的; 更好的办法是:
在 /usr/bin/gnocchi-api 中wss.make_server(…) 时,提供了三个参数,还有两个参数是可以定制的,我们可以自己在 /usr/bin/gnocchi-api 中实现一个 MyWSGIRequestHandler ,继承自./simple_server.py 中的WSGIRequestHandler , 然后覆盖其中的address_string() 方法即可
按照办法四 修改后的 /usr/bin/gnocchi-api 如下:
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 |
#!/usr/bin/python2 #PBR Generated from u'wsgi_scripts' import threading from gnocchi.rest.app import build_wsgi_app from wsgiref.simple_server import WSGIRequestHandler class GnocchiWSGIRequestHandler(WSGIRequestHandler): def address_string(self): return self.client_address[0] if __name__ == "__main__": import argparse import socket import sys import wsgiref.simple_server as wss my_ip = socket.gethostbyname(socket.gethostname()) parser = argparse.ArgumentParser( description=build_wsgi_app.__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter, usage='%(prog)s [-h] [--port PORT] [--host IP] -- [passed options]') parser.add_argument('--port', '-p', type=int, default=8041, help='TCP port to listen on') parser.add_argument('--host', '-b', default='', help='IP to bind the server to') parser.add_argument('args', nargs=argparse.REMAINDER, metavar='-- [passed options]', help="'--' is the separator of the arguments used " "to start the WSGI server and the arguments passed " "to the WSGI application.") args = parser.parse_args() if args.args: if args.args[0] == '--': args.args.pop(0) else: parser.error("unrecognized arguments: %s" % ' '.join(args.args)) sys.argv[1:] = args.args server = wss.make_server(args.host, args.port, build_wsgi_app(), handler_class = GnocchiWSGIRequestHandler) print("*" * 80) print("STARTING test server gnocchi.rest.app.build_wsgi_app") url = "http://%s:%d/" % (server.server_name, server.server_port) print("Available at %s" % url) print("DANGER! For testing only, do not use in production") print("*" * 80) sys.stdout.flush() server.serve_forever() else: application = None app_lock = threading.Lock() with app_lock: if application is None: application = build_wsgi_app() |
测试发现,访问确实快多了,不再感觉到延迟了
docker-init in bash
把下面脚本当做容器的init进程:
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 |
#!/bin/bash # kill all process except pid=1 export TZ=UTC-8 trap "quit; exit " 1 2 3 15 function log() { echo $(date +"%F %T") "$@" } function quit() { while :; do local pid_info=$(ps -axo pid,ppid,comm --no-headers|awk '$1 != 1 {print $0}') [[ $pid_info == "" ]] && break local succ=0 while read pid ppid comm; do if kill $pid &>/dev/null; then ((succ++)) log "$(printf '%-64s[%s]' "killing pid $pid(ppid: $ppid, comm: $comm)" succ)" else log "$(printf '%-64s[%s]' "killing pid $pid(ppid: $ppid, comm: $comm)" fail)" fi done < <(echo "$pid_info") [[ $succ == 0 ]] && break sleep 1 done } while read line; do log "$line" done |
知识点:
- while循环中修改外部的环境变量,则 不能使用管道的方式给while提供数据,这样的话,while 就是在新的子shell中执行的,不会影响到当前shell,所以:
- 使用了标准输入的重定向
- 使用了 <($cmd) 的方式
- 为了让字符串中连续的空格被保留,参数传递时多要通过双引号引上,即使是 $(cmd) 产生的字符串也要整个用双引号引上,当然,此时的双引号比较特殊,因为此时的双引号可以套双引号而不需要转义,示例: (注意下面几种双引号中嵌套单引号的的区别)
注意:
- 这个init进程是bash做的,如果docker attach的话,不管是ctrl-d退出还是ctrl-c退出,都会导致init进程终止,容器退出
- 脚本中的while循环最初想到的是通过sleep实现暂停的,但是考虑到sleep会产生一个额外的进程,不好看,于是选择了read;
注: 后来发现,使用read有一定好处,bash处理信号需要注意的是,在执行外部命令(如: sleep)时不能实时处理信号,只有在外部命令结束后才能处理信号; 而read虽然也是阻塞的,但是能实时处理信号
linux文件系统评估之inode – it_arch_notes – 博客园
https://www.cnblogs.com/wuhuiyuan/p/linux-filesystem-inodes.html
ext*文件系统的inode数量是预先定义好的,但是xfs的不是,xfs文件系统比较能很好地平衡inode和磁盘空间的使用
时延与带宽之间的关系
带宽计算公式为:带宽=时钟频率*总线位数/8
对于网线来讲,总线位数等于1,而且公式里的带宽单位显然是byte/s
时延 包括好多方面
仅从链路上的传输时延来讲,仅仅和信号在介质上的传播速度有关系,和带宽没有关心
为什么给人的感觉是带宽越大,延迟越小呢?我觉得,更大的带宽可以在大数据量时降低排队时延,进而降低总体时延;如果设备没有任何负载,从结点A发送到结点B一个数据包的时延应该和A、B之间的带宽没有一毛钱关系。
又是什么影响带宽的呢?
我觉得带宽是由频率决定的,单位时间内,产生的波峰和波谷越多,就意味着信息量越大,也就是带宽越大
带宽和延迟之间的关系:
当数据量很小时,延迟基本会稳定在某个值左右。随着数据量的变大,延迟也会变大;就好比从北京开车去广州,高速上车越多,花费的时间也就越多,尽管还没达到最大吞吐量,延迟已经很厉害了。 当然,如果你走土路,可能和车多少关系也不大,这个就是介质问题。
所以,高带宽和低延迟需求要分开考虑,尽量使用不同的网络。
参考: http://m.blog.csdn.net/u013830021/article/details/73648091
文件系统 之 inode篇
缘起:
20T的1亿个小文件存放在xfs的文件系统中会存在inode被用光(但是存储空间还有很大空闲)的问题吗?
测试:
df -i 可以看到可用、已用inode数量,一般来讲,mkfs的时候,会划分 x% 的空间存放inode的,可用inode数量是按照文件个数计算的,不是按照占用空间计算的,如:
500GB的磁盘,格式化为xfs后,可以使用的inode数量约 2.6亿; 那么1GB的磁盘格式化为xfs后,可用inode数量为 2.6亿/500 ~= 50万吗?测试如下:
确实,1GB默认可以存放约52万个文件,注意: 目录也是占用inode的,而且也不可能把所有文件都放在一个目录的,所以真正计算inode的话,还需要把目录的数量算上; 按照每个目录100个文件计算的话,50万个文件就需要5k个目录(可以忽略不计了);其实不全对,5k个目录放在一个父目录下也不科学,为了保证每个目录最多100个的话,还要分到50个父目录里面,额.. 也没有多少目录
按照上面的公式计算: 20T/1G*50w ~= 1000亿 个文件, 不少了
当然,如果还不够的话,格式化的时候可以指定更大的inode数量
计算:
10亿个文件,打散到N个目录中,每个目录的子目录(文件)数量不超过100个,需要多少级子目录?
100x > 10亿 ,x最少值为 x>=5 ,就是说 5层目录就够了
其实,xfs是个比较只能的文件系统,没有固定大小的inode区域,随着磁盘的使用,inode的总数量也在变化,基本不会出现inode已用光,但是存储空间很空闲很多的情况
FCSAN与IPSAN详细技术比较 – 豆丁网
http://m.docin.com/touch_new/preview_new.do?id=1551793152
ipsan 需要把传输的数据封到IP数据包中, fcsan 不需要封包,直接将scsi扔给光模块即可;话说封包是消耗client的CPU的(但是你真的在乎这点儿CPU吗?你真的很在意这点儿计算增加的延迟吗?访问磁盘的延迟远比这个大的多)
ipsan和fcsan只有在大访问量时才能明显感觉到差异
IP网络和fc网络的传输延迟不一样,能有多大差异?