wget bind ip 失败

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 我们的程序需要从文件服务器拉去文件(跨机房), 程序运行的机器有电信、联通、移动3线,3个IP 假定为 01_DX_IP, 01_LT_IP, 01_YD_IP 文件服务器也是电信、联通、移动3线,3个IP 02_DX_IP, 02_LT_IP, 02_YD_IP 其域名为myfile.com 使用wget拉去文件,为了保证出口带宽用的尽量上,绑定出口IP wget --bind-address=01_YD_IP -t 3 -T 120 --limit-rate=3M -S -O 1407856770354_858932.mp4 http://myfile.com/data10/sony/303/2014-08/12/1407856770354_858932.mp4 按照预先的想法,绑定了移动IP,正常DNS服务器会返回一个文件服务器的移动IP,速度应该不会太慢,事情情况下,下载速度不到100k 1. 排查: 1.1 观察文件下载连接 观察wget打印的日志,显示实际建立连接访问的是联通的IP Resolving myfile.com... 02_LT_IP, ... Connecting to myfile.com|02_LT_IP|:80... connected. HTTP request sent, awaiting response... ^C 使用lsof观察进程的连接情况 [xxx@c3n~]$ sudo lsof -p 133396 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME wget 133396 root cwd DIR 8,2 4096 59640871425 /datapool/log/inject/xxx.log wget 133396 root 6w REG 0,17 164815000 59756490241 /datapool/injectBase/1408203875738_777462.mp4 wget 133396 root 7u IPv4 1479434406 0t0 TCP 01_YD_IP:29657->02_LT_IP:http (ESTABLISHED) 注意这一行 TCP 01_YD_IP:29657->02_LT_IP:http (ESTABLISHED) 本地的bind address确实已经生效,已经绑定了移动IP, 但是文件服务器的IP地址却是联通IP, 那只能是DNS解析有问题了 ...

January 1, 2018 · 2 min

rinetd 在生产环境要谨慎使用

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 购买了阿里云的redis节点,但是默认阿里云不提供公网IP,所以我在一台阿里云的机器启动了rinetd,做端口的转发服务,开始一切正常,一段时间以后,随着并发力度加大。我们发现redis连不上了,提示Connection reset by peer 排查 1. 排查Redis 为什么会这样,首先我怀疑,是否redis有问题 首先我查看了redis的负载情况,使用INFO 命令 # Clients connected_clients:192 client_longest_output_list:0 client_biggest_input_buf:0 blocked_clients:16 # Stats total_connections_received:1131 total_commands_processed:7225865 instantaneous_ops_per_sec:30 total_net_input_bytes:216949807 total_net_output_bytes:87315792 显然redis的负载并不高 instantaneous_ops_per_sec 要超过2w, 负载才算高 connected_clients还不到200, 默认的设置允许最大连接数是1w 2. 排查阿里云主机 首先这台的机器的连接数并不高 [root@xxx-xx-77 ~]# ss -s Total: 733 (kernel 751) TCP: 644 (estab 598, closed 1, orphaned 0, synrecv 0, timewait 1/0), ports 234 Transport Total IP IPv6 * 751 - - RAW 0 0 0 UDP 1 1 0 TCP 643 636 7 INET 644 637 7 FRAG 0 0 0 但是观察机器的CPU使用率 ...

January 1, 2018 · 3 min

优雅的终止docker容器

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 本文受到参考资料1的启发 我们线上的服务有不少都是部署在docker中,部署涉及的机器多大几十台, 服务发布时,要求前一个版本的容器必须优雅的退出。 docker容器中的进程是一个任务消费者。不断得从任务队列中取任务,然后进行执行(执行时间较长) 假定docker容器的name为test_v1 docker容器中的进程名为atm 也就是说不能简单的 docker rm -vf test_v1 docker run -d --name test_v1 test:v1 解决方案 1)方案1 首先,我想到的办法是在docker容器外部使用 ps -ef| grep atm |grep -v grep |awk '{print $2}'|xargs kill -15 容器中的进程捕获 SIGTERM 信号,优雅的退出,发现所有容器中的进程都退出后再执行发布逻辑 缺点: 这个方案肯定是没有问题的,但是如果进程同名,很有可能会导致误杀,而且从docker容器外部,传信号给容器内部的进程,感觉有点奇怪 2)方案2 幸运的看到了参考资料1 root@xxxx:~/test/docker/test_dk$ docker stop --help Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] Stop a running container by sending SIGTERM and then SIGKILL after a grace period --help=false Print usage -t, --time=10 Seconds to wait for stop before killing it 在docker stop命令执行的时候,会先向容器中PID为1的进程发送系统信号SIGTERM,然后等待容器中的应用程序终止执行,如果等待时间达到设定的超时时间,或者默认的10秒,会继续发送SIGKILL的系统信号强行kill掉进程。在容器中的应用程序,可以选择忽略和不处理SIGTERM信号,不过一旦达到超时时间,程序就会被系统强行kill掉,因为SIGKILL信号是直接发往系统内核的,应用程序没有机会去处理它。在使用docker stop命令的时候,我们唯一能控制的是超时时间,比如设置为20秒超时: ...

January 1, 2018 · 1 min

SSD 4k对齐问题

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 因为知识有限,如果文章中有错误,请指出,谢谢。 起因: 我们生产环境的一台机器,使用的是SSD硬盘,但是测试的结果,读写速度只能到200MB/s, 而按照网上提供给的数据,SSD至少能够达到500MB/s, 顺序读写 会不会我对SSD的设置有问题 1. 文件大小和文件占用空间 在操作系统中,文件大小和文件占用空间大小是2个不同的概念 文件大小可以理解为文件实际大小,比如字节数 文件占用空间大小是为了存储这个文件所分配的硬盘空间的大小 文件 xxx.log 文件的大小仅有7个字节,而实际占用了512 * 8 = 4k个字节 文件 xxx2.log [root@xxx tmp]#stat /tmp/xxx2.log File: `/tmp/xxx2.log' Size: 38890 Blocks: 80 IO Block: 4096 regular file Device: fc01h/64513d Inode: 814342 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-11-13 12:24:42.966209408 +0800 Modify: 2017-11-13 12:24:42.971209436 +0800 Change: 2017-11-13 12:24:42.971209436 +0800 细心的朋友会发现,文件空间总是大于文件大小,而且Blocks恰好为8的整数倍,这是因为操作系统为了和内存分页大小保持一致,便于数据从硬盘加载到内存中,以及便于从内存将文件回写到硬盘上,所以所做的妥协。 内存页大小 ...

January 1, 2018 · 4 min

saltstack 常用命令总结(持续更新)

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 工作中经常要用到,就列在这儿,方便查看。 1. file server 1.1 更新state文件(针对master) fileserver.update backend=roots,git 1.2 清除本地state文件(针对master) salt-run fileserver.clear_cache 1.3 列出fileserver目录(针对master) 列出文件夹 salt-run fileserver.dir_list 列出文件 salt-run fileserver.file_list 2. Pillar 2.1 更新pillar 如果你设定git作为external pillar salt-run git_pillar.update branch='branch'repo='https://foo.com/bar.git' 2.2 查看pillar 查看特定 salt "*" pillar.get disk_type 查看所有 salt "*" pillar.items 2.3 刷新目标机器的pillar salt '*' saltutil.refresh_pillar 3. grains 3.1 查看grains 查看特定 salt '*' grains.item os osrelease oscodename 查看所有 salt '*' grains.items 3.2 同步自定义的grains 脚本放在salt://_grains 目录中 Sync grains modules from salt://_grains to the minion ...

January 1, 2018 · 1 min

SaltStack 重要配置

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 当整个saltstack的负载比较高的时候需要修改如果配置参数 1. Minion By default, the Salt fileserver recurses fully into all defined environments to attempt to find files. To limit this behavior so that the fileserver only traverses directories with SLS files and special Salt directories like _modules, enable the option below. This might be useful for installations where a file root has a very large number of files and performance is negatively impacted. Default is False. ...

January 1, 2018 · 1 min

Redis 关于大量1级key的测试

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因:有文章提到Redis的1级key数量不应该超过100w 我十分怀疑这个结论是怎么得到的。我们知道在Redis中一个DB中的所有key维护在一个HashMap中,较多的key当然会导致,key的移动更加困难,当然由于HashMap的原因,在rehash时,可能消耗更多的时间;另外内存可能有少部分浪费。可是key的数量增大到100w以上,是否真的会带来其它问题吗 1. 测试验证 1.1 测试方法 使用string 类型,不断的插入新key,为了保证key仅可能不重复,且长度一致 使用自增变量 i 的md5值 每写入10w个key记录一下当前的内存值,已经插入这10w个key所消耗的时间 import json import redis import random import time import hashlib r = redis.Redis(host='localhost',port=6379,db=5) SIZE = 100000 fp = open('result.txt', 'w') counter = 0 for i in xrange(0, 100): t1 = time.time() for j in xrange(0, SIZE): counter += 1 print 'counter', counter m = hashlib.md5() m.update(str(i * SIZE + j)) key = m.hexdigest() r.set(key, 1) t2 = time.time() margin = t2 - t1 info = r.info() #print info ll = [] ll.append( str((i + 1) * SIZE) ) ll.append(str(margin)) ll.append(str(info['used_memory'])) fp.write(','.join(ll) + '\n') fp.flush() print (i + 1) * SIZE, margin, info['used_memory'] fp.close() 1.2 测试数据 测试总计写入1000w个key,耗时大概在半小时 图1 ...

January 1, 2018 · 1 min

golang中可变长参数的使用

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 使用的Redis的时候,需要使用LPUSH 往一个key中一次写入多个value 我使用的是garyburd/redigo 这个库 函数定义如下 // Do sends a command to the server and returns the received reply. func Do(commandName string, args ...interface{}) (reply interface{}, err error) 显然函数是可变长参数 解决方法 1. 列表 package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { dialOption1 := redis.DialDatabase(0) dialOption2 := redis.DialPassword("xxxx") rs, err := redis.Dial("tcp", "127.0.0.1:6379", dialOption1, dialOption2) if err != nil { fmt.Println(err) } // redis的key是 "mykey" args := []interface{}{"mykey"} args = append(args, 10, 20) args = append(args, 30) count, err := redis.Int(rs.Do("LPUSH", args ...)) fmt.Println("count:", count) } 2. 字典 package main import ( "fmt" "github.com/garyburd/redigo/redis" ) func main() { dialOption1 := redis.DialDatabase(0) dialOption2 := redis.DialPassword("xxxx") rs, err := redis.Dial("tcp", "127.0.0.1:6379", dialOption1, dialOption2) if err != nil { fmt.Println(err) } test_map := make(map[string]int) test_map["zhangsan"] = 1 test_map["lisi"] = 2 test_map["wangwu"] = 3 // redis的key是 "my_hash" args := []interface{}{"my_hash"} for f, v := range test_map { args = append(args, f, v) } str, err := redis.String(rs.Do("HMSET", args ...)) fmt.Println(str) } 参考资料 How do I call a command with a variable number of arguments Go实例学:可变长参数函数

December 31, 2017 · 1 min

业务日志收集方案

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: 我们线上的业务通常会部署到10几台或者几十台机器上,线上的日志如果用salt执行命令远程的grep已经是越来越不方便了,所以我们决定对日志进行统一收集,管理 1. 选择方案 我们业务日志不算特别的多,因此不想方案过于复杂,并且公司内部已经有ES和kafaka集群 因此可以选方案有 1) rsyslog + kafka + elasticsearch 2)fluentd + kafka + elasticsearch 我最终选择了方案1: a) 由于公司的服务器主要是centos, 默认已经安装了rsyslog b) Fluentd是JRuby开发的,而rsyslog是二进制程序 以前有过logstash的使用经历,当日志量较大时,logstash会把CPU打的很高 感受:rsyslog的功能其实非常强大, 它所有配置都是从某个input获取数据再发送到output(和logstask很像) 支持: 1) 文件 –> kafka 2) 文件 –> elasticsearch 3) tcp/udp –> 文件 4)文件 –> 其它主机(TCP/UDP) input 和 output 是可以任意组合的 如果你不想搭建Elasticsearch和Kafka,完全可以把所有日志收集到某个文件服务器 然后在这台文件服务器上再使用logrotate,完全可以满足日常的开销 kafka只是用来做缓冲的,如果日志没有明显的波峰,可以不使用kafka 2. 实施 2.1 统一日志字段 我们多个业务项目,并且有Golang、Python等多种语言,为了保证,入ES的数据格式一致,我们统一了日志的字段,如下 所有字段都是比选的,如果没有请留成空字符串* 字段 类型 是否必填 说明 备注 service string 是 业务标识 使用英文字符和下划线,中划线 name string 是 logger名称 level string 是 日志级别 ERROR/INFO/DEBUG/WARNING pathname string 是 文件全路径 lineno int 是 在文件中的行号 如果没有, 给默认值-1 msg string 是 消息体 task_id string 是 任务ID log_date string 是 日志时间 ES上的字段类型为datetime 2017-01-01T00:00:00+0800 不同的业务和项目之间通过service字段区分 ...

December 31, 2017 · 1 min

Elasticsearch经验总结(持续补充)

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因: ES在笔者所在的公司使用也有3年多了,集群的规模达到上百台,期间也有很多的经验,我这里总结出来分享给大家,技术水平有限,如有错误请指正。 事项: 这些事项,我把它们以问题的形式列出,并会持续补充 1. 关于shard大小的分配 ES的shard是在index创建好时,就已经分配了,所以shard数量的选择非常重要,根据经验shard的大小在10GB ~ 20GB 较为合适。选择这个大小的原因如下 1)ES是通过移动shard来实现负载均衡,如果shard过大移动会非常缓慢 2)另外每个shard相当于一个lucene实例,lucene实例也对应着一组Java线程,所以shard数也不应该过多 2. 关于index的命名设计 如果数据是随着时间增长的,可以选择按月,或者按天分库 index的命名可以是 index_201701、index_201702、index_201703 或 index_20170301、index_20170302、index_20170303 然后可以为他们指定别名index_2017,这样可以直接使用这个别名查询所有index库 另外ES的库是可以关闭的,关闭以后,不占内存空间,只消耗硬盘空间 3. SSD OR 机械硬盘? Elasticsearch的速度有赖于索引,大量的索引是以文件的形式存储在硬盘上的,如果你的数据量较大,且单次的查询或聚合量较大,那么应该使用SSD,据我们的测试表明,再查询的数据量较大的情况下, 使用SSD的ES速度是机械硬盘的ES速度的10倍, 官方说法在正确配置的情况下,SSD的写入速度是机械硬盘的500倍 给一个参考值 数据单条记录1kB 操作系统Centos 6.7 内存64G ES版本2.3 ,堆内存31GB 单个ES data node处理能力 机械硬盘 SSD 1w/min 10w/min 见参考资料[1] If you are using SSDs, make sure your OS I/O scheduler is configured correctly. When you write data to disk, the I/O scheduler decides when that data is actually sent to the disk. The default under most *nix distributions is a scheduler called cfq (Completely Fair Queuing). ...

December 31, 2017 · 3 min