豪翔天下

Change My World by Program

0%

爱情是甜美的?爱情是苦涩的?花花世界,谁又能说得清呢。

《我依然爱你,我只是不喜欢你了》这本书是无意间在以前一位喜欢过的女生的一篇微博看到的,光看标题就有一种台湾的那种小清新爱情片的味道,看了一下简洁,是讲爱情的不是讲分手的爱情的,所以果断入手,毕竟和女朋友还处在热恋期,不知道为什么,我们俩热恋期咋这么长呢。

全书是由几十个小小的爱情故事汇聚而成,不知道真的是作者身边朋友的经历还是有很多朋友主动向作者倾诉的呢,我也好希望我身边能有一位情感专家,有什么心里问题她都能迎刃而解,什么心里话都能对她说,但是至今我的朋友圈也没出现过这样的人。作为书评,在这里我并不打算把我对爱情的理解写出来,因为也许可能大概我也写不出来,有些东西,在心里,就够了,是万万不能用我那笨拙的文字功底写出来的。另外,看了看豆瓣上的评分,其实还算不错,但是下面的有些评论我就不大赞成了。平淡、口水文,对于爱情来说,这样子有错吗?如果真的觉得平淡就觉得这是一本烂书,那我是该说你们不懂文学,还是该说你们不懂爱情呢?至少在我,一看到这个书名,就觉得这就是一本平平淡淡的书,就是一本贴近生活的书。这本书也绝不是一本只讲故事不走心的故事集,应该说它是很走心的,谁都可以深陷进那一个个的故事,也谁都可以从中体会到什么。

小井岩(作者)是个温柔的人,只有温柔的人,人们才会想他倾诉吧。很多时候,我也想做一个温柔的男朋友。虽然我比我女朋友小,我也很幼稚。和她刚在一起的时候就觉得她是那种很有气质型的,没想到,现在已经被我”调教“成一个每天都会向我撒娇的可爱女孩子了,虽然我也每天撒娇。她很好,我是她第五个男朋友,她是我第三个女朋友,我们谁都不知道会不会一直走下去,但又一直都朝着一直走下去的目标努力着。不仅我们过去爱的是人渣还是真的错过,过去的都已经翻篇了,就像我最开始说的以前喜欢过的那个女生,我现在女朋友也知道我以前喜欢过她,但是女朋友并不会阻止我和她聊天,说了半天,我到底想说什么呢,我也不知道。反正,米娜,有爱到来的时候就好好爱吧,不要刻意去回避,也不要刻意去追逐,一切随缘,不矫揉造作的爱,才是最真最纯的爱。(不要问我为什么不多谈谈书中的内容,因为看了大半年了吧,已经忘记了,只能从kindle里的笔记中找一点点当时的体会)

语录

我知道我已离开你的世界,也知道,彼此不再有交集,然而心中某块地方,始终无法抹去存在的痕迹。我依然爱你,我只是知道,自己不能再像以前那样喜欢你了。 依然祝你,平安幸福。

“你知道年轻的时候穷最大的问题是什么吗?”
“什么?”
“以为所有得不到的一切都是穷的错。眼睛盯着遥远的地方看不到身边一朵花的美丽。”

对那时的我来说,爱情是什么并不重要,就像我知道苹果就是苹果,而不需要知道它是蔷薇科还是落叶乔木;就像当我遇见你,我就知道遇见了爱情。

最温暖的相处模式,就是两个人在一起的时候,有一种自然而然的舒适氛围,能够消解心中的那些戾气,恢复成最放松而且淡然的自己。没有强烈的惴惴不安,也没有莫名的看不顺眼,没有所有那些消耗神经的累的东西。只要我知道你在,一切就都很好。

真的有些人,让你相信人是有上辈子的,不然为何一相见就可以自然而然跳过试探、了解、熟悉的人际程序直接成为那个直达灵魂的亲密之人。

做个称职的前任吧,不纠缠,不打扰,不撩拨。心里那些残存的想念,是怀念和感激。放下心中那多愁善感的郁金香,才会开出畅然伸展的蓝莲花。

我觉得真正爱一个人的表现肯定是努力使自己和对方变得更好,怎么会是拉着对方一起下沉呢?

我不认为一辈子只爱一个人是件可惜的事,也不认为一辈子爱过很多人就是一件不道德的事。

秒速五厘米间,樱花蹁跹了看客;人生聚散离合,伊人明媚了岁月。

如果我们费尽所有心力,都不能在那个心爱的心上留下一个深一点的痕迹,这不是对方的错,也不是你的错。因为不是你不努力,而是对方跑得太快,飞得太高。

感动不是爱情,爱情根本不需要这么累,你追我跑,那是狩猎,我又不是猎物!

最后献上知乎的几位朋友对”我爱你,我只是不再喜欢你了”的解释

《One Day》里安妮海瑟薇的一句台词 我无法控制自己对你的难以忘怀 可是我关于你的一切已经再也没有了期待。 ——Pengsiya
我会想起我们的过去,却不会再去想我们的未来。 ——兵荒马乱
“不介意孤独,比爱你舒服” ——江白粥
我还是曾经的那个我,你已经不是曾经的那个你了。 —— 鬼木知

最近真的太忙,但是再忙我也强迫自己抽出一些碎片时间来阅读,所以写书评也是必要的,因为,一本书不写书评,我根本就看不下去另一本书。对了,其实前几天还看过一本书叫《程序员的数学思维修炼》,这本书几乎是直接翻过去的,因为里面的内容基本上是给没上过大学的人看的,所以也就没有写书评的必要了。

《暗时间》是本与效率有很大关系的书,有很多套路,但是也不乏新奇之处,很多章节虽然啰嗦而且段落太长(不知道是不是我kindle显示的原因),但是书中对于每一个结论的得出,都是经过了层层推敲,循序渐进地引导我们进入作者的思维中去。而不是如其他效率书一样,上来就是一个结论,然后教我们步骤。整体感觉上,这本书还是挺不错的,可以给四分。对于“暗时间”的概念,我是觉得作者在这里并不是标题党,确实作者的“暗时间”并不仅仅是指传统意义上的碎片时间。

更深层次地讲,此书,并不是完全讲时间管理,而更多的是一种引导,引导我们认知、学习,文中提到很多关于学习的方法以及很多学习不好的方法对我来说都受益匪浅。对于时间管理,我现在使用的是番茄工作法,基本上解决了碎片时间的利用率问题和工作休息切换的问题;但另一方面,天秤座最主要的特点,犹豫不决,我在这一点上依然会浪费很多的时间,而且总是给自己和身边的人造成困扰。我想或许经历得更多,我就能有更多的果断和从容,但是又该怎样在有限的时间里比普通人经历更多呢?

书中关于学习算法那个章节我的印象是十分深刻的,因为我也曾经参加过ACM比赛,也曾经疯狂地刷题,虽然最终放弃了,但是那段一心钻研算法的日子真心值得回忆。看了该书,我仿佛茅塞顿开,仔细想想,曾经的很多算法书,特别是我们的教材上面讲算法,包括数学的公式证明,在引导我们的中途几乎都会突然来一个转折,“不妨在这里…”这样的坑我以前也踩过很多次,特别是在啃那部《算法导论》的时候,当时我就一直想弄明白,这里凭什么就突然要这么做了。事实上,正如作者所说好多的书籍都弱化了思考的这一环节,事实上,我猜,那些书的作者可能也没理解到这样转折的理由,如果真要把思考的过程全部加起来,那么随便一个K(kan)M(mao)P(pian)算法也足矣成一本书了。在刷OJ的那几个月里,我记住了很多算法,也记不住很多算法,但现在仔细想来,基本上能记住的算法,我都能清清楚楚地知道那个算法是怎么演变而来的以及为什么要用那个算法和什么时候用那个算法。

书中还提到几个日常中非常实用的思维训练以及时间管理方法:

  • 设置自己的进度条,将目标分割成一个个里程碑,再讲里程碑分割为一个个TODO list列表
  • 如果有什么难题困扰你了,那就在睡觉前一直想,你永远不知道大脑在你睡着的时候会怎么奇迹般地解决这个问题。这点相信很多人都是有实际体会的吧。
  • 走路睡觉吃饭都可以思考,当你完完全全陷入一个问题的时候你就会知道你突然多了好多的时间
  • 时常反省和注意自己的思维过程。尤其是当遇到无法理解或解决的问题之后,最需要把原先的思维过程回顾一遍,看看到底是哪个过程被阻塞住了妨碍了理解。

后记:写完了整个书评,突然觉得这本书比我之前认为的还要有意义得多,我现在可以给它五星了。

语录

你会在这本书当中看到的一个重复出现的现象就是自学,大规模的自学,逃课自学,上网找书自学,程序员行业是最适合自学的行业,网络是程序员的天堂,需要的资源、工具,比课堂上的多出何止百倍,如果说还有一个学科,并不需要传统的教育就可以成才,估计非程序员莫属了。作为程序员如果没有查过wikipedia,没有看过几本原版电子书,没有在国内外主要邮件列表里面提过问题吵过架,没有用技术博客记录学习的独特体会,没有订阅技术牛人们的博客,怎么好意思说身在这个行业呢?

利用走路和吃饭的时候思考,还有睡觉前必然要弄一个问题放在脑子里面,在思考中迷糊入睡。发现这样一来往往在不知不觉中多出来大量的思考时间。将思考成为习惯还有一个很大的好处–避免焦虑。

尽量避免琐事骚扰,不重要的事情能不做就不做。有时候,紧急的事情往往只是当事人觉得必须马上做完才显得紧急或者干脆就是紧他人之急,最糟糕的就是纯属性格上原因觉得每件事情都得第一时间完成,很多看上去紧急的事情实际上并不是真的”不能再拖了”,有的干脆就并不需要或值得去做。有很多事情都是可以先放一放甚至完全let go的,否则的话就整天被所谓”紧急”的事情牵着鼻子走了。

有一句话说:看一个人,只要看他读的书和见的人。还是很有道理的,这两者是一个人成长中最有价值的信息来源。

一个你不明白其证明的定理在我看来比不知道这个定理还要糟糕,因它给你造成一种懂了的错觉。与看定理必看证明类似,看一个问题的解法,必然要看解法所诞生的过程,背后是否隐藏着更具一般性的解决问题的思路和原则。否则一个解法就只是一个问题的解法,跟背口诀一样。即,知道了算法是怎样一步步被推导出来的,我们就一下拥有了大量的记忆提取线索:对算法发现过程中的任何一个关键步骤(尤其是本质)的回忆都可能使我们能够自己动手推导出剩余的内容

网络监听原理

无线网卡的监听模式

  • 托管模式(Managed mode): 在这个模式下,无线网卡只专注于接受从WAP发给自己的数据包文。
  • 监听模式(Monitor mode): 无线网卡会监听空气中所有的无线通信。不同的无线网卡启用监听模式的方式可能不相同。

表达式语法

  • IP过滤

    ip.src == 192.168.1.1 # 过滤源地址

     ip.dst == 192.168.1.1 # 过滤目的地址
     ip.addr == 192.168.1.1 # 过滤源或者目的地址
     !(ip.src == 192.168.1.1) # 排除某地址
     http.request.uri matches "login" # 过滤url中含有login的http请求
    
  • 端口过滤
    tcp.port == 80

  • 协议过滤
    http # 只显示http协议

  • 内容过滤
    udp.length > 20

     http.content_length > 20
    

HTTPS

https://imququ.com/post/http2-traffic-in-wireshark.html

在做毕业设计的时候,由于后端有一个耗时任务,所以想到了异步,又由于长期使用Python,进而想到了Tornado,然后,我就半个月没做毕设了,说来全是坑啊。在了解异步与阻塞的原理之前我就盲目地想从代码层面去实现,这样只会浪费时间。所以这里我就先描述一下我对这几个概念的理解。

异步与同步:是消息通信机制的层面

采用异步的时候,程序并不关心该操作的结果,所以并不会有返回结果,比如ajax,一般会给异步操作赋予一个回调函数,通过这个回调函数对结果进行处理,而不是直接将结果返回给外部(在ajax如果return结果则会是一个null值)

阻塞与非阻塞:指程序在等待调用结果时的状态

如果是阻塞,则程序会一直等待程序返回结果,如果是非阻塞,则不会等待,而继续执行下面或者其他的代码了。

阻塞式IO

耗时型任务一般分为两类:CPU耗时型任务和IO耗时型任务。CPU指一般的代码运算执行过程,IO一般分为两大类,计算型IO和阻塞式IO。如果仅有一个线程,那么同一时刻只能有一个任务在计算,但如果是阻塞式IO,它可以让它先阻塞掉,然后去计算其他的任务,等到内核告诉程序那边没有被阻塞了就、再回到之前的地方进行之后的运算。

所以,在了解了这些概念过后,我就知道了为什么要发挥tornado的异步特性就得依赖异步库(Tornado官方提供的第三方异步库),而不是随便一行代码都能变成异步非阻塞式的代码。比如我试验时使用的一个sleep函数:

1
2
3
4
5
def sleep(self):
for i in range(100000000):
if i % 100000 == 0:
print(i)
self.set_cookie('setting', 'hao')

看吧,这是一个计算型任务,由于tornado是单进程单线程,所以无论怎么做也不可能实现在访问该请求的时候访问其他请求,因为CPU只能执行当前任务,其他请求必须等到这个请求结束后才能成功,这也是为什么部署tornado的时候几乎都是用nginx+多实例事实上,同理,其他的框架基本上都是需要nginx、apache等配合才能同时服务于多个请求的。Tornado的异步库,几乎都是用来进行阻塞式IO任务的,所以只有他们才能发挥其异步特性。

Tornado的异步实现就是将当前请求的协程暂停,等待其返回结果,在等待的过程中当前请求不能继续往下执行,但是如果有其他请求(同样是一个协程),只要不也是阻塞式IO,那么就会直接去处理其他的请求了。

当然,包括nodejs的异步等,这些统统都是有历史原因的,JavaScript和Python在发展之初都只支持单进程单线程,即使使用多线程技术最多也只能利用到100%的单核,多核在这里似乎并不使用,而如果要使用多进程变成,光靠框架是做不到的,必须自己根据实际需求来处理多进程之前的数据共享、资源竞争等问题。所以,在我的理解里,如果能直接利用多线程编程就不需要用服务端异步,毕竟,多线程的发明本身也是为了解决阻塞式IO的问题。

多线程实现异步、非阻塞、并行请求、并行计算

其实我认为多线程相比于异步非阻塞有很大的优点,不可否认,多线程在线程切换上存在开销,并且在资源竞争上需要写更多的逻辑,稍微控制不好就会导致服务出错,然而,多线程在处理并行任务上有先天的优势,这一点光看名字就看得出来,下面介绍Tornado的多线程和Flask多线程的用法,其中Tornado的多线程是指由程序将当前请求中的代码交由其他线程处理,而flask的多线程就是类似apache服务器,另起一个进程来处理请求。

注意:两者都可以使用global来引用全局变量

Tornado实现:当前请求会立马返回一个结果并断开当前http连接,所以不能在这里设置cookie

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
import tornado.ioloop
import tornado.web
import time
from concurrent.futures import ThreadPoolExecutor
import tornado.httpclient
from tornado.concurrent import run_on_executor

class Executor(ThreadPoolExecutor):
_instance = None

def __new__(cls, *args, **kwargs):
if not getattr(cls, '_instance', None):
cls._instance = ThreadPoolExecutor(max_workers=10)
return cls._instance

class SleepHandler(tornado.web.RequestHandler):
executor = ThreadPoolExecutor(10)

def get(self):
tornado.ioloop.IOLoop.instance().add_callback(self.sleep) # 相当于丢到下一个时间循环去
self.write("when i sleep") # 请求会立马返回这个值并断开连接

@run_on_executor
def sleep(self):
for i in range(100000000):
if i % 100000 == 0:
print(i)
self.set_cookie('username', 'hao')

print("yes")
return 5

class TestHandler(tornado.web.RequestHandler):
def get(self):
if not self.get_cookie('username'):
self.write('没有')
else:
self.write('有')

application = tornado.web.Application([
(r"/test", TestHandler),
(r"/sleep", SleepHandler),
], debug=True)

if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()

flask实现:直接在启动时添加参数,当前请求不会立马返回一个返回值,会一直处于连接状态,所以可以设置cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask,request,make_response
app = Flask(__name__)

@app.route('/')
def hello_world():
username = request.cookies.get('username')
if username is None:
return '没有'
else:
return '有'
return username

@app.route('/s')
def sleep():
for i in range(100000000):
if i % 100000 == 0:
print(i)
resp = make_response('ok')
resp.set_cookie('username', 'the username')
return resp

if __name__ == '__main__':
app.run(debug=True, threaded=True)

参考文章
知乎:怎样理解阻塞非阻塞与同步异步的区别?
Tornado文档:异步非阻塞I/O
Tornado教程:异步Web服务
使用tornado的coroutine进行编程
我在segmentfault的提问:无法理解tornado的异步

注意,Redis是单线程的,运行耗时任务时,会阻塞,导致不能响应其他的请求(对于耗时大的删除任务, Redis4.0提供lazy free功能)。

配置文件

如果是线上,可以用rename机制禁用一些命令例如keys、flushall、flushdb

在redis shell外部,可以通过命令行的方式获取或者设置一些配置,例如:

1
redis-cli config set notify-keyspace-events KEA  # 可以直接设置notify-keyspace-events的信息

常用配置:

1
2
3
4
5
6
hz = 10  # 表示每秒检查过期键的次数
save 900 1 # 数据写入硬盘的频率,表示如果900秒内有1个key发生变化就写入一次,300秒内有10个key发生变化写入一次,60秒内10000个key发生变化写入一次
save 300 10
save 60 10000
bind 127.0.0.1 # 绑定IP,表示只有该IP能够连接到该redis,默认所有IP均能连
requirepass 密码 # 访问需要密码

内存满了的策略

redis使用的内存超过maxmemory参数的时候,maxmemory-policy这个策略就开始生效了。默认是noeviction(不删除键,只返回错误),可以设置其他的策略如下(LRU算法及最近最少使用算法):

1
2
3
4
5
6
volatile-lru: 使用LRU算法删除一个键(只对设置了生存时间的键)
volallkeys-lru 使用LRU算法删除一个键
volatile-random 随机删除一个键(只对设置了生存时间的键)
allkeys-random 随机删除一个键
volatile-ttl 删除生存时间最近的一个键
noeviction 不删除键,只返回错误

查看信息

info命令可以查看redis的所有信息,常用的字段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Memory	内存信息
used_memory_human: 就是当前Redis所使用的内存
used_memory_peak_human:Redis的内存消耗峰值

# Keyspace
db0:keys=100,expires=1,avg_ttl=7298 # 数据库0,设置了生存时间的key有1个,平均过期时间是7298ms

# stats 记录一般的统计信息
total_connections_received:服务器已经接受的连接请求数量
total_commands_processed:服务器已经执行的命令数量
instantaneous_ops_per_sec:服务器每秒钟执行的命令数量
rejected_connections:因为最大客户端数量限制而被拒绝的连接请求数量
expired_keys:因为过期而呗自动删除的数据库建数量

常用操作

系统

1
2
3
4
5
6
# redis-cli
redis-cli -h 127.0.0.1 -p 6379 -a password # 连接服务端
client list # 列出所有的客户端连接,客户端的IP
client kill 127.0.0.1:44444 # 断开某个连接

# redis-cli --bigkeys 查看redis中非常大的key

通用

  • 严禁在生产环境使用keys *进行搜索,因为这表命令会引发Redis锁,导致其他查询不可用,如果真有类似业务,可以使用scan命令
  • setnx常用于分布式锁,建议将value设置为一个随机字符串,而不是无意义的”OK”啥的,因为这样在释放锁的时候可以验证一下是否释放的是正确的锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SETNX	key value	# 将键key的值设置为value,如果key不存在则set成功返回1,如果key存在,则设置不成功返回0,常用与锁中
SET key value EX 10 PX 10000 NX# 原始SET命令后面其实也可以跟很多参数的,EX表示多少秒后过期,PX表示多少毫秒后过期,NX相当于SETNX,XX表示只有键盘存在时才设置

flushall # 删除所有数据库的key
flushdb # 删除当前数据库所有的key
del key # 删除某个key
redis-cli KEYS *name* | xargs redis-cli DEL # 使用通配符进行批量删除操作

select 2 # 切换数据库

key name # 查找某个key
keys pattern # 查找所有符合给定模式pattern 的key
keys * # 列出所有的key
exists key # 查找该key是否存在
TYPE KEY # 获取某个key的类型

scan 0 # 使用游标的方式取出一定数量的redis key,与keys不同的是,keys是一次性全部扫描

expire key seconds # 为某个key指定生存时间,单位为秒,时间到了后就不存在了,默认时间为永久
ttl key # 查看剩余生存时间

字符串

列表

1
2
3
4
5
6
7
8
9
10
11
12
13
lindex keyname index              # 返回列表中下标为index的元素
lpush keyname value value2 # 将一个或多个值插入到表头
lpush keyname value [value ...] # 将一个或多个值插入表头
lpushx keyname value [value ...] # 当且仅当key存在且是一个列表时插入表头
rpush keyname value # 插入表尾
rpushx keyname value # 当且仅当key存在且是一个列表时插入表尾
lrem key count value # 从列表删除元素,其中count>0时表示从头往尾移除count个值为value的元素,count为0时表示移除所有,count<-1时则是从尾往头移除
lrange keyname start count # 从表头的第start位开始取出count个元素
llen keyname # 返回列表长度
lpop keyname # 移除并返回key的头元素
rpop keyname # 移除并返回key的尾元素
lset key index value # key中下标为index的元素的值设置为value,如果key不存在则会报错no such key
LTRIM key start stop # 只会保留列表从左往右的start至stop数量的元素

集合(SET)

1
2
3
SADD key member [member...]
SMEMBERS key # 返回集合key中的所有成员
SISMEMBER key member # 判断集合key中是否存在成员

有序集合(ZSET)

  • 需要注意start/stopmin/max的区别,一个是排序后的顺序,一个是score值
  • 最大分数值可以用"+inf"代替,最小分数值可以用"-inf"代替
1
2
3
4
5
6
7
ZADD key score member	# 像有序集合中添加元素
ZCARD key # 返回有序集合的成员数量
ZCOUNT key min max # 返回有序集key中,score值在min和max之间的成员数量
ZRANGE key start stop [WITHSCORES] # 返回有序集key中,指定区间内的成员,其中成员的位置按score值递增(从小到大)来排序
ZRANGEBYSCORE key min max # 返回有序集key中,所有score值在min和max之间的成员
ZREM key member # 移除指定元素
ZREVRANGEBYSCORE key max min # 与上面相反,这是分数由高到低排列的

Hash(哈希)

1
2
3
4
5
6
7
8
9
HKEYS key	# 取出哈希表key中所有的域
HEXISTS key field # 判断field是否存在于hash中
HMGET key field [field...] # 取出某个key指定域的值
HSET key field value # 将hash表key中的域field的值设为value,如果key不存在则会新建,返回结果为1,如果已有field则会覆盖,返回结果为0
HSETNX key field value # 只在 key 指定的哈希集中不存在指定的字段时,设置字段的值。成功返回1,如果已经存在field,那么会失败返回0
HMSET key field value [field value ...] # 同时将多个field-value(域-值)对设置到哈希表key中,会覆盖哈希表中已存在的域
HINCRBY key field increment # 将hash key中的域field增加increment,如果没有key则会新建key,如果没有域则默认为0并增加increment
HGETALL key # 取出hash表中所有的域和值
HVALS key # 取出哈希表key中所有域的值

过期策略

根据官方文档,redis对于过期的键有两种策略(过期的键并不会立马执行删除操作),分为主动与被动:

  1. 客户端试图去获取某个key的时候就会直接进行过期删除操作
  2. 由服务器去探测,探测方案如下(每秒执行10次下面的操作):
    1. 从设置了过期时间的所有key中随机取20个键
    2. 删除实际上已经过期了的键
    3. 如果删除的超过了已过期键的25%,重复前面的操作

如果想看效果,那么可以设置100000个过期时间很大的键,再设置一个过期时间很短的键,并开启键空间通知,你就知道多久才会发现那个键了😭,不过,如果全部时间多一样,那100000个键也能在瞬间完成所有通知,也就是说,每次扫描出来的20个键如果都满足第三条要求,那连续探测的频率是非常高的。检测频率可通过hz进行设置,默认为20

Keyspace notifications(键空间通知)

键空间通知,允许Redis客户端从“发布/订阅”通道中建立订阅关系,让客户端能够从Redis中接收到相应的事件。redis-cli config get notify-keyspace-events获取其配置值,如果value为空表示没有设置。可以直接用命令设置如:redis-cli config set notify-keyspace-events KEA其中,最后面的字符,每个字符都有特殊的含义:

  • K: 键空间通知,所有通知以__keyspace@__为前缀
  • E: 键事件通知,所有通知以__keyevent@__为前缀
  • g: DEL、EXPIRE、RENAME等类型无关的通用命令的通知
  • $: 字符串命令的通知
  • l: 列表命令的通知
  • s: 集合命令的通知
  • h: 哈希命令的通知
  • z: 有序集合命令的通知
  • x: 过期事件: 每当有过期键被删除的通知
  • e: 驱逐(evict)事件: 每当有键因为maxmemory政策被删除的通知
  • A: 所有通知

使用方法:

1
2
3
4
5
6
7
8
> config set notify-keyspace-events Ex	# 必须加E,这样才会通知事件
第一个终端进行监听:
> PSUBSCRIBE __keyevent@0__:expired

第二个终端进行操作
> set a b EX 1

这样第一个终端就会输出过期的键值

Redis组件

Redis从4.0开始支持组件的开发,能为redis提供更多实用的定制功能,热门组件可以参考Redis Modules

Redis数据库设计

  • 统计聚合情况

    例如,需要统计PV数量,精确到分钟,但是又有按小时、按天、按星期统计的需求,那么可以使用hash来进行聚合统计,例如这样设计

    1
    2
    3
    4
    5
    pv:post:id = {	 # 这是key值
    '2016-08-22': 2333 # 按天统计
    '2016-08-22:15': 23 # 按小时统计
    }
    pv:post:id:2016-08-22:15:list = [] # 那一个小时每分钟的数据,作为一个列表

Redis Sentinel高可用方案

Redis Cluster集群方案

redis sentinel不同的是,前者主要是高可用,每一个机器都保存完整的数据,而cluster则住重在分片,当内存占用大于每台机器实际内存时候更实用。Python连接Redis集群需要使用redis-py-cluster

TroubleShooting

  • 小数据量本地迁移数据

    网上找到的Redis的迁移方法都是从一个服务器至另一个服务器做主从复制,但我现在面临的情况是如何将localhost的数据迁移到Server上面去,用最笨也最简单的方法,直接将dump.rdb覆盖服务器上Redis目录,需要注意的是,覆盖的时候得先把原Redis进程关闭掉,覆盖后再重启

  • Redis 显示中文

    启动时redis-cli --raw

  • **windows长时间运行出现错误:Redis-Server:Windows is reporting that there is insufficient disk spaceavailable for this file (Windows error 0x70)**。原因是分配的堆栈太小了,默认的应该只有1M,这时候需要修改器配置文件redis.windows.conf,修改maxheap的值为2000000000,即2G

  • Redis自动退出,log无报错: 目前遇到的情况是可能连接数过高。操作系统让它挂掉了

  • **MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.**持久化的时候磁盘不可写了,一般是因为磁盘满了

扩展阅读

home

这一天终于还是来了,终于到了这个父母翻了好几遍老黄历还问了算命先生的约定日子。女朋友也专门请假过来,父母也是拉了几十个亲戚过来😂。虽然老家的亲戚总是能带给我惊喜(xia),但是这一天还是开开心心地过去了。我觉得上天总是比较眷顾我,搬家第二天就下大雨,订婚也是,前后都下雨,就当天的天气最好。

压力肯定是有的,每个月2500的房贷,30年,不过,想想我这种对理财一点儿不了解的人,这可能算是这辈子少数的几次可以应对通货膨胀的投资行为了,所以我也是能贷就尽量多贷一点,相信自己,相信党,相信国家。毕竟,从大三到大四,重庆一套房子的放假就涨了我现在的年薪,然后从我买房到我住进去,又涨了我几年的年薪,不是我年薪低,是重庆这一年来的放假真的是直线上升,现在,只能庆幸自己下手还算早,不然,我可能就再也买不起房了。真是傻人有傻福啊,根本不懂房产却下手得比较准确。

以前可从来没想过毕业不到一年我就买了房子,虽然是小两房,但至少够我和女朋友住十年了,顺便生个女儿也能住得下。而且走路十分钟以内就能从幼儿园一直读到高中,虽然不是学区房,但是这其实在重庆也是很少见的。他们都说,我真积极,连婴儿床都买好了,其实我暂时还没想过要生孩子,只是以防万一而已😁,反正有了这张婴儿床,我小小的次卧居然能睡7个人,搬家当天晚上9个大人,6个小孩子居然没打地铺就睡下了,看来以后得多叫些朋友来玩儿,不然真的浪费了这些床了。

有了大冰箱,终于可以做自己想做的菜了;有了大电视,终于可以在55英寸4K上面玩儿ps了;有了大沙发,终于可以不用没晚回家就上床了;有了大阳台,终于可以沐浴每天清晨的阳光了;有了大窗帘,终于可以在家放心的裸奔了;有了双层隔音玻璃,终于可以在晚上好好看”大片”了;有了全套智能家居,终于可以好好的玩玩儿极客玩具了;有了千兆网线,终于可以尽情看大片了;有了大浴室,终于可以好好享受洗澡时光了。刚住进去几天,感觉一切都是那么的美好,这才是人生啊,每天早早的下班,回到家做饭吃饭,然后躺沙发上边看电视,边玩电脑,边玩手机。。。

其实,这并不是我预想中的搬家。墙上挂的,地上铺的,桌子上放的装饰品我都还没装呢,本来就是现代简约的风格,结果连一点儿装饰都没有,所以现在看起来特别简单,主要父母急着让我住进来,我也没办法了。而且现在女朋友还没毕业,再等两个月我们就能真正住进新家了。

面对未来,我还是那句话,美好的生活才刚刚开始。

zabbix

默认用户名Admin,默认密码zabbix

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 先安装MySQL,根据[初始化数据导入](https://www.zabbix.com/documentation/2.4/manual/appendix/install/db_scripts)来创建用户
# 安装主程序
rpm -ivh http://repo.zabbix.com/zabbix/2.4/rhel/6/x86_64/zabbix-release-2.4-1.el6.noarch.rpm
yum install zabbix-server-mysql zabbix-web-mysql # 服务端安装
yum install zabbix-agent # 客户端安装
# 基本配置,vim /etc/zabbix/zabbix_server.conf
DBHost=localhost
DBName=zabbix
DBUser=zabbix
DBPassword=zabbix

# 安装zabbix的辅助工具
yum install zabbix-get zabbix-sender
zabbix_get -s 客户端IP -k "agent.ping" # 在服务端运行该命令可检测服务端是否能娶到数据

# 启动服务
/etc/init.d/zabbix-server start

# 安装完成后会在httpd目录下面的conf.d生成相应的配置文件,唯一需要改的就是它注释了的date.timezone,修改一下httpd的监听端口和IP就可以访问了,默认用户名密码是Admin zabbix,注意大小写

监控配置

[添加自定义监控项目](http://yangrong.blog.51cto.com/6945369/1548670)
[邮件报警设置](http://www.osyunwei.com/archives/8113.html)

常用参数

1
2
3
4
5
6
7
8
9
10
--connect-timeout:设置最大连接时间
-d:传递数据,可以是JSON数据也可以是直接的POST数据
-F: 发送form表单数据的一个参数
-I:仅显示文档信息(HTTP状态码什么的)
-k:禁用ssl验证
-o/-O: 下载文件(前者指定下载文件名,后者不用指定)
-s:静默模式,不输出任何东西
-x: 设置代理,代理一定要加端口
-X:请求方式,GET、POST、DELETE等
-H: 设置请求头,比如-H "Content-Type: application/json"
阅读全文 »

我的kindle里面收藏了太多的书,此书就是一本我也不知道什么时候一时兴起将其收藏的,光看书名还以为是一部心灵励志类的小说,没想到竟是包含人生、哲理、财经、政治的集大成者。自然,在看本书前我对作者也是一无所知,到后面越看越觉得作者不是等闲之辈,便去维基了一下:吴晓波,就是那个《激荡三十年》和《跌宕一百年》等著作及纪录片的作者,他的《大败局》被评为‘影响中国商业界二十本书’之一。一路走来,吴晓波亲身经历了中国改革开放的几十年,并深入其中,握其精髓,无论书中哪一篇文章都让我感觉仿佛身临其中,无法自拔。

其实,这部作品从形式上来说是一篇文集,“把生命浪费在美好的事物上”只是这部著作其中一篇的标题,作者从人生谈到家国,谈了几个人,仿佛谈了几千年。他不仅经历过,而且还和很多成功或曾经成功的人士聊了很多事,历史的沉浮中升华出自己的理解。其间的内涵可能也只有自己能体会。我想,一个知识分子,姑且这样称呼自己,想要在浮躁的社会中,必然得有自己的一片精深田地,可以入世,但不能抛弃一个知识分子的道德、心境、理想。

当然,另一方面,有人读书的目的就是当前对自己有没有用。客观地说,书的前面一份主要讲一些鸡汤,中间以及后面的部分才是全书的内涵所在,从叙事中领悟不同的人生。

看完这本书,我也忍不住想去看作者其他几本书,光从书名上就感觉是我目前思想境界还未能企及的,所以暂时,放下,等我继续,沉淀。

最后关于“把生命浪费在美好的事物上”这几个字,我一直很喜欢。中考的时候,阅读理解,大意是“珍惜那些浪费的时光”,两个主题其实如出一辙。生命中总有好多的事,我们很喜欢,但是这些事可能无法给我们带来直接的价值,所以很多人尽量选择回避自己所喜欢的,而不得不接受自己不喜欢的。我一直不希望成为这样的人,因为这样子活着,真的好累。在这个浮躁的社会,每晚拿出kindle,摆上一杯清水,就这样,静静地看,这一刻你会发现,你的灵魂终于跟上了你的身体。

语录

其实,人生如草,活的就是“从容”两字。

这一生中,你遇见怎样的人,然后有机会成为那样的人。

我们对这个世界还是这么好奇,我们还有舍弃一切的勇气,即便手中的黄金变成了砂砾,但若放手出来,空掌仍能握铁。

你看,我们对这个世界还是这么好

你看,我们对这个世界还是这么好奇,我们还有舍弃一切的勇气,即便手中的黄金变成了沙砾,但若放手出来,空掌仍能握铁。还是邱兵同学说得好:“我只知道,我心澎湃如昨。”

自由是世俗的,它不在空中,不在别处,它就在地上。作为一个读书人,你能否自由地支配时间,你能否自由地选择和放弃职业,你能否自由地在四月去京都看樱花,你能否自由地与富可敌国的人平等对视,你能否自由地抵制任何利益集团的诱惑,这一切并不仅仅是心态或勇敢的问题,而是一种现实能力。

在这个世界上,不是每个国家、每个时代、每个家庭的年轻人都有权利去追求自己所喜欢的未来。所以,如果你侥幸可以,请千万不要错过。

每一件与众不同的绝世好东西,其实都是以无比寂寞的勤奋为前提的,要么是血,要么是汗,要么是大把大把的曼妙青春好时光。

金钱让人丧失的,无非是他原本就没有真正拥有的;而金钱让人拥有的,却是人并非与生俱有的从容和沉重。金钱会让深刻的人更深刻,让浅薄的人更浅薄。金钱可以改变人的一生,同样,人也可以改变金钱的颜色。 把金钱当对手和敌人的人,将一生为金钱而烦恼;而把金钱当朋友的人,将获得金钱给予的欢乐和平和。成为金钱的奴隶,或将金钱视为奴隶的人,都无法与金钱平视对坐。

花开在眼前/已经开了很多很多遍/每次我总是泪流满面/像一个不解风情的少年

一箪食,一瓢饮,在陋巷,人不堪其忧,回也不改其乐。贤哉,回也!

SQLite是一个遵守ACID的关系数据库管理系统,本身是一个嵌入式的程序,并不是客户端/服务端模式的架构,可以直接继承到应用程序中,Pyhton就内置了SQLite的。它的数据是直接存储在一个文件里面的。

安装

OSX: brew install sqlite

Ubuntu: apt install sqlite3

客户端: sqlitebrowser

命令行工具

1
2
3
4
# 首先进入db所在目录
sqlite3 my.db # 这样就能进入命令行了

.tables # 列出当前所有的表,相当于SHOW TABLES;

TroubleShooting

  • **报错sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in thread xxxx **,原因是SQLite是不能多个线程同时访问的,要么直接不使用多线程,更好的做法是在连接是添加check_same_thread参数。

    1
    connect = sqlite3.connect('test.db', check_same_thread=False) # 允许在其他线程中使用这个连接