redis出坑记

monitor未关闭

redis的monitor运维调试用,返回服务器处理的每一个命令,能了解在数据库上发生了什么操作,所以在性能上会有一些消耗。有3种操作方法进monitor模式。

1
2
3
4
5
6
7
8
9
10
11
12
[lavenderuni@~]# redis-cli monitor
...
[lavenderuni@~]# redis-cli
127.0.0.1:6379> monitor
...
[lavenderuni@~]# telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
monitor

在测试redis-cluster时候,吃午饭回来发现某node内存持续占用,比其他node要高,主node正常,如果在非常大的key-value,例如某个key的value存了近百万数据,会造成内存占用,但是不应该是某个node不正常。主从复制出问题应该体现在主node。

经过排查找到,是该node上开启了monitor模式,饭前忘了关掉,导致请求的操作log越来越多。这和很多工具都一样,测试模式不要轻易开启,用完请及时关闭。注意,Telnet连上了同样可以monitor,所以端口不要轻易对外开放,避免被人利用

大map

产品上面的用户数据超过700万,一些用户的附加信息需要在新功能上使用,并且新功能取数据很频繁,需要把用户这部分信息从mongo存到redis,供接口获取。
有三种方案:

  • key-value,key=uid,val=rank
  • hash,key=”userinfo”,val={uid:rank}
  • hash,key=to_int(uid)/60,val={to_int(uid)%60:rank}

通过测试发现,第三种的内存最小。
为什么呢?要从数据类型的内部存储方式说起,

  • hash-max-zipmap-entries 64
  • hash-max-zipmap-value 512

hash-max-zipmap-entries含义是当value这个Map内部不超过多少个成员时会采用线性紧凑格式存储,默认是64,即value内部有64个以下的成员就是使用线性紧凑存储,超过该值自动转成真正的HashMap。

hash-max-zipmap-value 含义是当 value这个Map内部的每个成员值长度不超过多少字节就会采用线性紧凑存储来节省空间。

以上2个条件任意一个条件超过设置值都会转换成真正的HashMap,也就不会再节省内存了。它们值不是越大越好,HashMap的各种动作的时间复杂度都是O(1),采用一维存储的时间复杂度O(n),成员数量一多,会严重影响性能。

因此遇到Redis的大map,要选择合理的数据结构和hash-max-zipmap参数解决实际问题,达到高效省内存的目的。

星爷的背影变小了

咦 星爷的背影变小了

wukong

浮夸自虐虐他的草根形态和赤裸裸的真我是星爷电影的精华,又叫无厘头,比鲁迅眼里的阿Q,要酣畅淋漓,好比阿Q是一只在人群夹缝里面狼狈乱窜的落水狗,而阿星是一直雄赳赳、气昂昂的落水狗,边抖着身上的水,边叫道:“我落水了,大家快来打我啊,好好笑。”

相形之行,鲁迅指出了百姓的劣根性;而星爷说劣根性的人也可以自强,也可以快乐,也可以精彩。在某种世界形态里,鲁迅留下的是一副苦药,让人无地自容;星爷却戏谑地赞他可爱,让虾米们再度活蹦乱跳起来。

虾米们起身看到的,却是星爷渐行渐远渐老的背影。

我记得第一次接触到星爷的电影是《大话西游•月光宝盒》,小时候五年级的时候吧,我和表姐采完茶,回到家里,看到14寸的黑白电视上正在播,当时觉得孙悟空的造型实在是没有六小龄童的美感啊,疯疯癫癫的对白啰里啰嗦,音乐造型呢,有一种唱戏的感觉,故事情节和打斗场面远不如金庸的流畅精彩。那一遍真没留下什么印象,或者好印象,哪知若干年以后被感动得一塌糊涂。

以下是1992-2004部分作品

  • 审死官、九品芝麻官,都是对体制权力的讽刺,无奈的败笔是最后胜利也要依靠更高的权力。这两部电影抛弃过往审案剧里那种凛然正气的权力,例如样板化的《包青天》,而是凸出智斗奸邪,借力打力的辛酸历程,更多的体现逻辑和民心所问。
    经典桥段:

    • 财主找宋世杰帮有罪的儿子打官司,拿出一箱银子,宋世杰不屑一顾,财主拿出一箱金子,宋世杰略有触动,财主出两车黄金。宋世杰坚定迅速接道:“那怎么行!”宋妻大喜老公有骨气,宋世杰却又说了句让所有人绝倒的话:“输了我也要一半!”
    • 宋世杰在衙门牌匾“光明正大”四个字下流了眼泪,感慨道:“官啊!…..”
    • 包龙星拿出一条内裤道:“我之所以有明天的成果,全多得皇上选拔,我对他呢,非常惦念,还好我收藏了一条皇上的龙内裤,闻一闻,精神百倍,抖一抖,生动筋骨,舔一舔,不会四处乱摆。来,闻一闻。”老板娘:“恩。”仆人道:“恬亲王到。”包龙星:“王爷大驾光临,有失远迎,恕罪,恕罪。”恬亲王道:“不必多礼,明天你开业,我不能恭喜你,要告知你一个坏消息,皇上驾崩了。”包龙星用龙内裤擦泪:“啊!皇上怎么会这样?怎么这样?皇上怎么会驾崩呢?”恬亲王:“生病了。”包龙星:“什么病呀? ”恬亲王:“是花柳病。”包龙星:“哎呀。”赶紧扔掉龙内裤。
  • 唐伯虎点秋香、月光宝盒、仙履奇缘对老传说改编,无疑,只有星爷才能改编得这么不一样,这么让人回味。
    经典桥段:

    • 旺财和小强,对社会病态比惨的讽刺,救济穷弱需要一套合理完善的制度助人自强,而不是作秀或者选秀,例如最惨最贫困之类的,也不是主观地干涉。
    • 打劫脚底板,二郎神的哮天犬奔着母狗去…..都是创意啊。
    • 一万年的誓言,是浑小子的最爱。
    • 紫霞仙子:“你看那个人,好奇怪哟,像一条狗。”
    • 紫霞仙子:“我的意中人是个盖世英雄,有一天他会踩着七色云彩来娶我,我只猜中了前头,可是我却猜不中这结局。”
  • 大内密探、国产凌凌漆,原来007可以不那么潇洒,却可以这么奇葩,不优秀也可以完成任务。
    经典桥段:

    • 让人想死的后宫佳丽三千,貌似历史上的后宫比片中的情形好不了多少。
    • 一段模仿奥斯卡颁奖的场面,最佳男主角是片中男主角的岳父。
    • 妓女道:“你以为躲起来就找不到你了吗?没有用的!象你这样拉风的男人,无论在什么地方,都像漆黑中的萤火虫一样,那样的鲜明,那样的出众。你那忧郁的眼神,稀嘘的胡喳子,神乎其神的刀法,和那杯Dry Martine,都深深地迷住了我。不过,虽然这是这样的出色,但是行有行规,无论怎样你要付清昨晚的过夜费呀,叫鸡不用给钱吗?”
    • 007那些一会儿正常一会儿不正常的工具和飞刀绝技。
    • 司令和李香琴用马桶通讯,道:“闭嘴,你以什么身份来问我,他是什么人跟你有什么关系?你妈妈是汉奸,你爸爸是走狗,你爷爷是卖国贼,你就是汉奸、走狗、卖国贼的生的,永远不能改变,当年要不是我收留你,你早就跟他们一起完蛋啦,你的命是我捡回来的,我叫你怎么办你就怎么办,知不知道?阿琴,我知道你这个人有时候心肠太软,你知不知道007是个什么样的的人?他是一个衣冠禽兽、他以前无恶不作,不但强奸大肚子,而且非礼小女孩,你看看,这些小女孩多可爱啊!这些大肚子又多凄残,都是他干的好事呀。你现在可以说是为民除害,你还有什么问题没有?”
    • 刑场,第一个瞎子被认定偷看机密文件,被枪毙。第二个官二代,还是被枪毙。第三个武林高手要跑路,被炮轰了。末了,007用一张钞票全身而退。
  • 喜剧之王、少林足球、功夫,草根的奋斗生活,像极了阿Q,尤其是《功夫》里面的阿星,却不是一个边顺从边逃避的阿Q,而是有点流氓气,有点善良,不停挣扎反抗的阿Q。
    经典桥段:

    • 尹天仇对柳飘飘:“其实我是一个演员。”
    • 用演技教一个斯文人去收保护费。
    • 命运真是不公平,为什么我这么帅却要掉头发,你们长的那么丑却不掉头发。
    • 赵薇:“我想帮你们比赛。”周星驰:“你怎么帮?你快点回火星吧,地球是很危险滴。”
    • 阿星和肥仔收租欺软怕硬,暗箭自伤。
    • 乞丐道:“小子,我看你骨骼惊奇,必是练武奇才,将来维护宇宙正义与和平的重任就交给你了!我这有本《如来神掌》,原价13块8,算你10块钱一本!”讽刺的是套路。
    • 包租婆:“你以为会功夫就不是兔子吗?”裁缝哭了:“会功夫不是罪啊。”包租婆:“你一日是兔子,终生是兔子。你看看你,穿条红内裤,白里透红,出来庆功吗?”

以下是2008-2016部分作品

  • 长江7号,算是温馨的,塑造的底层人物不错但是不够精彩。
  • 西游·降魔篇,为了搞笑而搞笑,越是迎合众人,越是容易失宠。
  • 美人鱼,不搞笑,除了票房高,还能想起什么呢?张雨绮的大胸。

星爷的电影是怎么了,越来越商业化,越来越没有味道了。

星爷老了吗?如果逃不过所谓的事业人生起伏定律,请您快快好起来,请您继续聚焦底层人民的生活,请您继续把世事的泪点转换成笑点吧,例如母亲卖姐姐,妹妹帮着数钱;卖肾买苹果;儿子是隔壁老王的……

星爷,千万万个我一直站在您的背后。

爬虫之路(1)

requests、lxml、phantomjs是Python爬虫的基础,也是利器。

requests vs pycurl

pycurl除了快,没有什么好。requests除了没有pycurl快,什么都好。
pycurl是用c语言写的,速度很快,比urllib和httplib都快,requests是基于urllib构建的,所以requests比pycurl慢。

pycurl的例子

python
1
2
3
4
5
6
7
8
9
10
11
>>> import StringIO
>>> import pycurl
>>> c = pycurl.Curl()
>>> str = StringIO.StringIO()
>>> c.setopt(pycurl.URL, "http://t.cn/aKln8T")
>>> c.setopt(pycurl.WRITEFUNCTION, str.write)
>>> c.setopt(pycurl.FOLLOWLOCATION, 1)
>>> c.perform()
>>> print c.getinfo(pycurl.EFFECTIVE_URL)
http://www.ladymax.cn/bbs/thread-46253-1-1.html

requests的例子

python
1
2
3
4
>>> import requests
>>> requests.get("http://t.cn/aKln8T").url
http://www.ladymax.cn/bbs/thread-46253-1-1.html

很明显requests用起来简洁直观。requests可以模拟实现restful的get,post,put,delete请求,并且可以通过post的file参数模拟上传,可以伪造headers、cookies。是否开启https用verify参数。是否允许重定向,使用allow_redirects参数。并且requests支持session,提供系列请求共同认证。

lxml vs beautifulsoup vs pyquery

  • beautifulsoup太慢,测试发现beautifulsoup比lxml要慢10多倍,lxml调用的libxml2+libxslt的原生c代码比较快。

  • beautifulsoup太耗内存,我在对接美团的团购开放api的时候,发现一个几十m的xml在beautifulsoup里面构建dom树几乎把服务器的内存都耗尽了,换成lxml就666。

  • beautifulsoup解析特殊符号或者字符串,会出现非正常的返回值。遇到这种情况,找到出问题的位置,然后在项目里面hack就行了。反观lxml的xpath太酸爽了。

  • pyquery依赖lxml,唯一的特点是完全的类jquery调用方式。

lxml的多线程有重入性问题,可以hack,将原来的各种变量放到thread local里面,实现参照webcral的lxmlclean
另外,beautifulsoup4可以选用lxml方式做解析。pyquery可以做试验品用。lxml适合大规模应用。

phantomjs vs ghost.py

不是所有的数据都是取自html、lxml,也可以取自json api,也不是所有的json api就是找到url就能拿回来的,比如说去哪儿的api基本上都做前后端混合加密,想通过json api取数据,基本办不到。还是得考虑如何在后台渲染页面dom文档,把数据取出来。
可以采用phantomjs,一种无头浏览器,实现了Selenium的大部分功能,Selenium是HTML测试工具。phantomjs能将一个url地址,在后台渲染完成,包括等候各个json api取数据完成。phantomjs能支持编写函数接口实现点击拖拽等各种用户操作。
ghost.py是Python版本的PhantomJS,基本实现了PhantomJS的功能,有以下不足。

  • 相同的引用链接请求会请求多次。

  • 对于异步数据请求的执行,兼容性不够,无法捕获异步加载js文件的请求。

  • 请求超时控制的问题比PhantomJS更严重,不请求完成就拿不到数据。

phantomjs和python的结合实现参照webcral的request from phantomjs proxyphantomjs proxy

python is VS ==

python的世界里,一切皆指针,一切皆对象

python的对象三要素:id、type、value。

  • id,标识一个对象,寻址的指针
  • type,对象类型
  • value,对象值

python is

a is b 判断的是a对象是否就是b对象,是通过id寻址来判断的。

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def test_id():
print 'temporary int 1', id(1)
print 'temporary int 1', id(1)
a = 1
b = 1
print 'variable a 1', id(a)
print 'variable b 1', id(b)
print '\n'
print 'temporary str ab', id('ab')
print 'temporary str ab', id('ab')
a = 'ab'
b = 'ab'
print 'variable a ab', id(a)
print 'variable b ab', id(b)
print '\n'
a = 1
b = 1
print 'variable a reset 1', id(a)
print 'variable b reset 1', id(b)
print '\n'
def test_object():
class AB(object):
def __init__(self, c=1, d=2):
self.c = c
self.d = d
print 'temporary list []', id([])
print 'temporary list []', id([])
a = []
b = []
print 'variable a []', id(a)
print 'variable b []', id(b)
print '\n'
print 'temporary object of object', id(object())
print 'temporary object of object', id(object())
a = object()
b = object()
print 'variable a object()', id(a)
print 'variable b object()', id(b)
print '\n'
print 'temporary object of AB', id(AB())
print 'temporary object of AB', id(AB())
print 'temporary object of AB', id(AB(2))
print 'temporary object of AB', id(AB(3))
print 'temporary object of AB', id(AB(4, 5))
a = AB()
b = AB()
print 'variable a AB()', id(a)
print 'variable b AB()', id(b)
print '\n'
a = []
b = []
print 'variable a reset []', id(a)
print 'variable b reset []', id(b)
print '\n'
a = object()
b = object()
print 'variable a reset object()', id(a)
print 'variable b reset object()', id(b)
print '\n'
a = AB()
b = AB()
print 'variable a reset Ab()', id(a)
print 'variable b reset AB()', id(b)
print '\n'
if __name__ == '__main__':
test_id()
test_object()

python里面的匿名变量的分配是幂等的
一般情况,系统类型匿名变量,就是所谓的常量,每一种类型的每一种值在每一个进程里面只存在一个匿名变量,并且可以被具名变量无限赋值引用;例如1, 2, ‘a’, 0.123;自定义类型匿名变量,每一种类型在每一个进程里面只存在一个匿名变量,最多能被一个具名变量赋值引用;系统常量是匿名变量的子集(在python shell里面表现比较奇怪)

python ==

a == b 判断的是a对象的值是否和b对象的值相等,是通过value来判断的

is vs ==

为什么是 is None?
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> c = None
>>> c == None
True
>>> c is None
True
>>> c = 1
>>> c == 1
True
>>> c is 1
True
>>> c = 'ab'
>>> c == 'ab'
True
>>> c is 'ab'
True

对于系统常量的判断,== 等价于 is,而且 is的效率 > == 的效率,因为is是寻址判断,==先要通过id找到存储位置,再比较存储位置的值;

为什么不是 is 1,is ‘a’
估计是使用习惯的问题,对于系统常量的相等判断,is 1比 ==1更合适

有趣的python shell现象
pyiseid