The Mirages

樱桃沟夹事

阿里云RDS有个功能叫临时升级,你可以随意升级多久,但是默认阿里云给你自动升级1年,每次都得往回退。 今天说的是一个奇葩的bug。 6月份为了大促升级了一个RDS,升级33天,就升级了cpu和memory, 可前2天发现磁盘快不够了,于是想升级磁盘到1TB,结果不允许,跳出下面的提示。 rds-xufei 以为还有什么东西还没续费,可看了订单里没有什么东西,都是已经支付的。找售后问就如下回复了。 rds-gongdan   最后还是没有升级成,只能自己去清理DB了。 而阿里云的原因就是2个升级操作不能再同一时刻生效。在一个续费变配还没完成以前就不能执行其他的升级和降配的任何操作。 我觉得唯一的理由就是阿里云自己不会算这笔帐了。而这样其实是一个非常大的坑。 这种变配操作你不能设置的很长,但是设置短了可能又会导致自己的麻烦。

用了阿里云服务其实已经很多年了,但是一深入用,感觉各种问题。 这不这次又出问题了。 起因是增加了内存和CPU,阿里云只能在页面中关机,启动才能生效。 这也不说了,其它很多云也都是这样的。 这个机器原先单独加了一个磁盘,做了LVM卷,这下悲剧了,重启以后发现LVM卷丢失了。但是盘还在,没办法只能给阿里与发工单请求解决。 然后阿里云的售后要了root密码,找了半天就这样回复我 “服务器上没有看到任何有lvm创建过的痕迹,建议您其他机器先检查下创建过程是否正常。”。还特地给我截图了一下。 lvm1 要是pvs和lvs这些我能看到也就不找售后了。于是打回去让他们继续找。结果他们居然还是找到了,但是原因不知道。 lvm2   但有一点还是肯定,他们技术人员还是很敬业的,那么晚了还给我打电话呢,但是从这里可以看到,阿里云的技术是真不怎么样。 后来就懒得用那个数据恢复了。原因找不到没啥意义,我另外几台ES依然不能直接重启,不过后来试了几台,发现都没问题,应该是阿里云自己有什么bug在后台偷偷修复了给。 继续吐槽其他的吧。 原先没VPC,现在有了VPC,但是不支持迁移,也不能互访,就只能通过公网互访。 内部几乎没有标准,有的区使用xvda, xvdb这样的命名方式,但是有的区是vda, vdb也没有啥规律。 网段划分混乱,导致内部无法做nat服务都。 由于没有VPC原先,所以搞了安全组出来,结果一个机器只能有5个安全组,对于我们这种用户远远不够啊。 非高性能IO的机器可以挂载SSD云盘,但是IO还跟原先SATA磁盘一样,理由是底层不支持,但是不支持你倒是别让人挂载啊。 RDS sql审计的功能突然哪天就变成收费了的。 RDS机器居然都是100.xxx.xxx.xxx这样网段的,你们还真敢用。 SLB没有日志,导致没法查看详细的内容,经常出了问题只能摘除后端重建。 原先OSS只能有10个bucket, 不过现在已经增加到1000个,也不知道原先10个限制是怎么想出来的。 API不好用,经常碰到文档跟实际不符合,而且没有像AWS那样一个完整的SDK。 好了,吐槽就这样了。

做奶爸最重开心的就是看着自己的小宝一点点长大,特别前3个月,你会发现变化特别大。

刚出生的时候居然还有抬头纹,跟小老头似的,可一个多月就长开了。

然后你又会发现他的个子突然就高了,手指突然长长了,体重又重了,突然有一天会对着你咯咯乐了,突然有一天会发一些单音节的词了,总之一直在给你惊喜中。

拍嗝: 这是必须的,特别是前面2个月,小小球的肠胃还没发育好,所以每次吃完奶之后必须启动拍嗝程序,竖着拍,躺着按摩,必须要变换姿势。 你没有奶喂,那拍嗝自然落到你头上了。反正是必须要拍出来为止,但是有时候可能有一个嗝,有时候就比较多,这个不好判断了,主要看喝奶的时候吸了多少空气。

换尿布,如何换,什么时候换。

如何换很简单,不要勒紧大腿就行,不然时间长了会有勒痕的。

阅读全文 »

log需求主要分2种: 一个是平时给开发人员和测试人员开放实时查看的。 另外一种是用来进行存储起来进行后面的统计分析。   由于给开发和测试,他们一般都没有服务器的权限,但是又需要实时查看,毕竟有时候问题的时间日志比较好在当场表现出来,后面再去log库里查就比较麻烦了,为了解决这个问题,那就需要一个单独的日志服务器去实时收集。 同时最好是web页面去展示出来,然后可以自己定义filter。 这个需求找了一圈发现了一个叫log.io的工具,但是需要装client,而且是nodejs写的,所以还得部署一套nodejs。这个对于我们的需求是不是太重了。 我们现在所有的机器上其实都已经有fluentd了,如何利用好现在的设施是需要考虑的,我不倾向于为了实现特地目的去引入特地的工具,这样对于运维人员会更好一点,毕竟后期维护成本是必须考虑,引入一个新的工具,后面监控维护是需要一长串事情要做的。 于是最终是2个方案集合成一个方案来进行。

  1. fluentd-client -> fluentd-aggregation -> elastichsearch -> kinbana
  2. fluentd-client -> fluentd-aggregation -> file

第一种方案kibana没有很好的认证,但是我们自己写了一个基于内部认证系统的接口挂在kinbana外面,使用nginx的subrequest来进行实现。 为了保证实时性,写入es的数据都设置为缓存10秒就进行写入,后期碰到瓶颈后再调整。 同时需要修改程序的logback,所有的log都写入到同一文件中,但是日志格式需要定义好:time,application-name, log-level, msg 这样的格式去定义好,然后在es中前3个字段都进行索引,msg内容就不索引了。 每天建立一个index,为了减少数据量index就只保留最近一周的,超过一周以上的还得从文件系统内进行查。但是开发人员一般很少查一周以上的数据。 统计分析的需求。纯文本对于各种分析工具都是最友好的,而且统计分析都是实时行要求很低的,但是又要经常看整个历史趋势的。所以对于一些长期的数据是必须要有机制来进行合并汇总的。 但是单纯文本可能占用的空间比较大,我个人是倾向用gz格式进行压缩的,而不是使用bz2格式,bz2虽然压缩比更高,但是耗费cpu time可是要高3,4倍左右了,得取一个相对经济的方法来进行。

终于用上了StartSSL的免费域名了。这个第一年是免费的。那第二年就继续申请一下了只能。 StartSSL申请的时候还挺逗,没有用户名密码的,只是在你的本机安装了一个key。剩下就是用csr来申请证书了。 接下来就是nginx的配置了。crt和key都是人家给你生成好的。 dhparams.pem是在本机进行生成的。还有要注意一些header的设置。经过这样设置后,我的网站ssllabs检测都是A+水平了。 ssl

1
openssl dhparam -out dhparams.pem 4096 
1
2
3
4
5
6
7
8
9
10
11
12
ssl_certificate      /etc/nginx/conf/ssl/mirages.dev.crt;
ssl_certificate_key  /etc/nginx/conf/ssl/mirages.dev.key;
ssl_dhparam          /etc/nginx/conf/ssl/dhparams.pem;
ssl_ciphers          ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;
ssl_prefer_server_ciphers  on;
ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header  Strict-Transport-Security  "max-age=31536000";
add_header  X-Frame-Options  deny;
add_header  X-Content-Type-Options  nosniff;
add_header  Content-Security-Policy  "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' img-src 'self' data: https://www.google-analytics.com; style-src 'self' 'unsafe-inline'";

但是访问的时候虽然做了301把http转为https,但是之前那些图片都是http的,所以浏览器还是会出现黄色警告。所以要把里面的图片地址也都转为https。 下面这个就是修改我的主题里的functions.php文件在最后添加如下内容:

1
/* 替换图片链接为 https */ function content_to_https($content){ if( is_ssl() ){ $content = str_replace('https://images.timoq.com', 'https://images.timoq.com', $content); } return $content; } add_filter('the_content', 'content_to_https'); 

需求是现在有些post请求的内容导致我们某个应用压力巨大,而正常是同样post的内容在24小时内只会请求一次。 初步思路就是将post内容里的变量部分写入到redis中,然后设置过期时间为1天。这样每次post的时候先查一下redis是否存在这个key。有就直接转到google上,没有就继续proxy_pass。 这里面会有几个坑。 不过lua我是第一次写,所以很多问题都没有提前预计到,测试的时候发生了很多问题。 首先自然是加入nginx-lua-redis模块支持。这里碰到个问题,ngx.say以后要是不加return就会报错。然后模块在应用的时候也要注意一下。

1
lua_package_path "/etc/nginx/lua/lua-resty-redis/lib/?.lua;;"; 

自己写一个lua模块。

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
local redis = require "resty.redis"
local cache = redis.new()
local ok, err = cache.connect(cache, '127.0.0.1', '6379')
ngx.req.read_body()
local method = ngx.var.request_method

cache:set_timeout(60000)

if not ok then
-- ngx.say("failed to connect:", err)
return
end

if method == 'POST' then
local data = ngx.req.get_body_data()
if data then
local i = ngx.re.match(data, "[0-9]{11}")
local phone = i[0]
local exist = cache:exists(phone)
if exist == 0 then
cache:set(phone, "phone")
cache:expire(phone, 86400)
else
ngx.redirect("http://www.google.com", 302)
ngx.say(phone, ' is in baned')
return ngx.exit(403)
-- ngx.say(phone, ' is in baned')
-- return ngx.exit(403)
end
end
end


local ok, err = cache:close()

if not ok then
-- ngx.say("failed to close:", err)
return
end

在location中进行应用。这里要用access_lua_by_file, 而不是 content_lua_by_file。但是用access_lua_by_file的时候必须要retrun好,如果return 200的话会继续proxy_pass, 其他的就直接返回了。

1
2
3
4
location = /VerifyCode { 
access_by_lua_file /etc/nginx/conf.d/include/ban-phone-number.lua;
proxy_pass http://test;
}
阅读全文 »

最近在centos7上用systemd进行管理启动进程,发现systemd启动的进程的limit都有问题。

open file都是4096,而不是在/etc/security/limits.conf 设置的数值。

于是看了下systemd本身的openfile, 这个确实都是对的。
然后我手动启动nginx的openfile都是根据limits.conf里设置的。  

看了下/etc/systemd/system.conf  里面确实可以单独设置openfile, 但是我直接修改system.conf里的值,再reload和restart都没有用,起来的nginx还是4096。

最后只能修改systemd的nginx配置文件。  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit] 
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
LimitNOFILE=999999
PIDFile=/opt/nginx/logs/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t
ExecStart=/opt/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
阅读全文 »

在docker hub上下载了一个java8的image的,但是需要在里面进行一些调试,发现明明有apt的源,就是只读本地的,不去cache远程的源。 其实就2个配置的问题。 之前ubuntu用了好多年,居然也没发现这个,还是放狗搜索才知道的,有空要看下apt-conf.d了。 ```c
echo “force-unsafe-io” > /etc/dpkg/dpkg.cfg.d/02apt-speedup echo “Acquire::http {No-Cache=True;};” > /etc/apt/apt.conf.d/no-cache apt-get update apt-cache search telnet


  仅以此文纪念球子费劲的生产过程。 昨天下午护士就过来刮毛了,然后晚上12点以后不让吃东西和喝水了,因为这是刨腹产的要。 今天早上8点多护士又过来插上了导尿管, 虽然将近9点时候护工把球子从自己床挪到了手术室的床,这难道不能支持用自己的病床吗? 非要这样来回折腾一下啊。 真是吓折腾。 球子进手术室好半天后,麻醉医生终于叫上我们了,我们拿着之前手术的各种检查和片子,可这些为什么不在昨天跟我们交流一下呢,非要在马上手术了再看这个,之前已经找过医生,可医生的态度都是明天手术前再说。 这样可不是有助于病人跟医生直接的沟通。 最后的麻醉方案就是先局部麻醉取出孩子,然后再全身麻醉。麻醉用了4种药,我也具体没记住是哪些。可没过20分钟小小球居然推了出来了,而且跟之前我们20分钟前签字麻醉的一家人一起推出来的,这个实在是有点可疑的。 推出来的时候好玩了,2个小孩放在一个车里,我们都还以为谁家生了一对双胞胎,结果其中哭声响亮的居然是我们家小小球,穿着医院的小包被就出来了,于是4个爸爸妈妈就一起下去了,我得继续守着大球子。没过多久另外一家小宝的产妇就推出来了,可我们家大球子估计还早,上次手术的时候做完了2个小时后才推出来,这个怎么着估计也得1个多小时。但我赶忙问下大夫这次二次麻醉的一般要多久,大夫都一样完全没个准话,结果再过20分钟大球子居然出来了。 这个时候4个爸爸妈妈和小田子也都来了,那就一起推到病房里,然后又换下床,这也真够折腾的。 本来以为现在就到此结束了,结果这只是刚开始。 首先是小小球怎么测体温都低,就35.5度一直,没办法,护士抱着,我再跟着去新生儿重症监护室,那边的医生倒是不紧不慢的抽了一下足底血做测试,填完表格就让我们回病房了。 IMG_20151228.122153_副本 回到病房我就听了说我们家小小球已经打了一个疫苗了,说是促进脑部发育的,怎么没经过任何人同意就可以打呢? 我签字就签了乙肝和卡介苗的。这是什么玩意? 到了病房把空调开了,把小小球再裹上一层包被,这次检测终于超过36度了。小小球剩下的就是哭和吃了,以及注意拉屎的事情。 可大球子的噩梦才刚开始,医生说大球子子宫是别人的1.5倍,然后说手术的时候有出血,然后有血块需要排出来,于是整个下午就一会来个护士来压肚子,促排血,一会来个医生压肚子促排血,来来回回10次左右居然,结果球子说还是钱主任按完了之后排的多和舒服点,但是其他人按的估计也是起作用的。有可能也是心理作用而已。 这按肚子可真疼啊,球子握着我的手,都把我手抠出血了,这得有多疼啊,小田子看着我看眼里都有泪花了,估计这样会吓到她了。反正顺产就生的时候疼,生完就好了,而很多刨腹产就生完疼了。怎么着都不会绕过那一关的。 小小球喝奶,本来以为刚做完手术不能马上喝奶的,想不到现在是直接可以的,难道不怕把麻醉药和挂的点滴进到孩子身体里吗? 这里有个大大的疑问。 然后小护士一弄就喝上球子的奶了,可是呢,不是还有按肚子的活,结果一会儿来按肚子,然后小小球就停止喝奶,一会儿来擦身体,然后又停止喝奶,你跟她说过会再来,人还说这水到时候凉了就不管了,看来公立医院也就这个服务态度了。 后来我们自己弄小小球喝奶,这个还是很有技术水平的。

通常大家都用ELK,但是这个世界就永远不会被一样事物统一的,主要是grafana也支持从ES中进行查询了,那就用下,毕竟grafana的界面比kinbana好看很多,虽然都是现成的,也没有二次开发的内容,但是还是会碰到一些问题,这个用ELK其实也会碰到的。 首先,默认fluentd是没有type标志的,这样导致默认到es中的都是string类型,这样只能做count了。所以我们要在所有client上安装fluent-plugin-typecast这个插件。 然后在服务端需要安装2个插件,其实一个就可以了fluent-plugin-elasticsearch, fluent-plugin-secure-forward。 用来支持传输到es中。 好了下面就是fluentd的具体配置了。首先是client端就是靠tail来收集, 但是重点是format的部分如何去匹配,还得考虑日志中的多种不同格式。 同时在打tag的时候把机器名也打进去,这样汇总的时候方便找从哪个nginx过来的日志。 还有type的部分可以把非string的给单独拉出来进行处理,string的就不用处理了。 下面这个是fluentd客户端上的配置: ```c
type tail path /opt/server/log/nginx/nginx-access.log format /^(?[^ ])\s+(?[^ ]) (?[^ ]) \[(?)\] “(?\S+)(?: +(?[^\“]) +\S)?” (?[^ ]) (?[^ ])(?: “(?[^\“])” “(?[^\“])” “(?[^\“])” (?[^ ])\s+(?[^ ])\s+(?[^ ])\s+(?[^ ])\s+(?[^ ]))?$/ time_format %Y-%m-%dT%H:%M:%S%z types status:integer,size:integer,response_time:float,upstream_time:float,cache_status:integer,upstream_status:integer tag “#{Socket.gethostname}.nginx.access.log” pos_file /var/log/td-agent/tmp/nginx.access.log.pos <match .nginx.access.log> type forward flush_interval 60s buffer_type file buffer_path /opt/server/buffer/ host agg1.hk.op.xxx.com port 24224

这里主要就是填写es的地址,然后在time_slice_format稍微耍了小花样,这样可以按年月日的分目录进行存放。不然都放同一个目录也不好查找。 ```c
1
2
3
 <match *.nginx.access.log> type copy <store> type file path /opt/server/logs/nginx-access/ time_slice_format ./nginx-access/%Y/%m/%d/%Y%m%d%H.nginx.access compress gzip flush_interval 10m time_format %Y-%m-%dT%H:%M:%S%z buffer_path /opt/server/buffer/nginx_access_buffer buffer_type file buffer_chunk_limit 50m </store> <store> type elasticsearch host hk1.es.op.xxx.com port 9200 include_tag_key true tag_key @log_name logstash_format true flush_interval 10s </store> </match> 
```   es的安装的部分就不在这里展开了,也许会在其他地方说下。不过要推荐一个工具kopf, zou哥去es大会上听来后马上给装上了,还不错,可以看到index,  node, share 这些信息,而且随着cluster的健康状态会以不同的颜色来显示出来,这样还是很贴心的。 下面这个就是一个运行的截图 [![kopf](https://images.timoq.com/2015/12/kopf.png)](https://images.timoq.com/2015/12/kopf.png) grafana的安装也不说了,我用的是2.5 stable版本,支持了es做为datasource, 也支持用户验证等等。 默认grafana是用query_string来进行全文匹配,而且不支持正则,不过grafana也支持自定义书写es查询 [https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html) https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html 根据上面的语法我们就可以自定义自己的查询语句。不过我更喜欢正则匹配。 [![grafana-regex](https://images.timoq.com/2015/12/grafana-regex.png)](https://images.timoq.com/2015/12/grafana-regex.png) 第一天用正则匹配发现了问题,怎么都匹配不上URL,后来group by 一下,居然发现png,jpg这些排在最前面,于是查了下原因, 正则不匹配的原因是因为es默认通过/ . 这些符号来进行默认分词。 那就只好更改es的index template,  把某些字段不让它进行分词,下面是我自己建立的一个template, 只用在某些index中。也可以在kopf中进行定义。 ```c
curl -XPUT http://hk1.es.op.xxx.com:9200/_template/template_1 -d ' { "mappings": { "_default_": { "_all": { "enabled": false }, "_source": { "compress": true }, "properties" : { "path": { "type": "string", "index": "not_analyzed" }, "referer": { "type": "string", "index": "not_analyzed" }, "agent": { "type": "string", "index": "not_analyzed" } } } }, "settings": { "index.cache.field.type" : "soft", "index.refresh_interval": "5s", "index.store.compress.stored": true, "index.number_of_shards": "3", "index.query.default_field": "querystring", "index.routing.allocation.total_shards_per_node": "2" }, "template": "logstash-*" }'
0%