python抓取的一些总结

python作为爬虫的最常见语言,很有自己的优势。这里举一些常见的用法。

1,使用scrapy框架。

https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html

2, 纯脚本

lib库

from concurrent.futures import ThreadPoolExecutor

from bs4 import BeautifulSoup

import Queue, time, random

import requests

提供一个比较粗糙的代码,使用到了python代理,queue,多线程,BeautifulSoup。最终print方法应该用线程锁避免打印错误。


#coding=utf-8
import requests
from concurrent.futures import ThreadPoolExecutor
import Queue, time, random
#import pymysql
from bs4 import BeautifulSoup
import re
import urllib
import urllib2
import gzip
import cStringIO
import datetime
import json
from StringIO import StringIO
import threading

import base64

index_url = 'https://www.juzimi.com/alltags'
page_url = 'https://www.juzimi.com/alltags?page=%s'

task_queue = Queue.Queue()

has_words = []
has_words_value = {}

lock=threading.Lock()

ip = ""
def getIp() :
global ip

url = 'http://s.zdaye.com/?api=201903221353043521&count=1&px=2'
ipret = curl(url, '', False, False)
time.sleep(5)
print "get ip:" + str(ipret)
ip = str(ipret)
def curl(url, data = '', isCompress = False, use_ip = True):

global ip
if(data):
data = urllib.urlencode(data)
else:
data = None
#headers = {"method":"GET","user-agent":self.ua,"Referer":self.refer, "Cookie":self.cookie, "Upgrade-Insecure-Requests": 1,"Accept-Encoding": "gzip, deflate, br"}
headers = {"method":"GET","Accept-Encoding": "gzip, deflate, br", "user-agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}

try :

#代理代码
if(use_ip) :
opener = urllib2.build_opener(urllib2.ProxyHandler({"https" : ip}))
urllib2.install_opener(opener)

request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request, timeout=10)

#response = opener.open(request)
if(isCompress) :
buf = StringIO(response.read())
data = gzip.GzipFile(fileobj=buf)
return data.read()
return response.read()

except :
exit()
getIp()
print "get ip retry"
self.curl(url, data, isCompress, use_ip)

#exit()

def setTaskR() :
task_queue.put({'url':'https://www.juzimi.com/tags/%E6%96%B0%E8%AF%97', 'title':'诗词'})

def setTask() :
#for i in range(0, 12) :
for i in range(0, 12) :
url = page_url % (i)
content = curl(url, '', True)
#print url
soup = BeautifulSoup(content, "html.parser")
span = soup.findAll('div',{'class':'views-field-name'})
for tmp in span :
data = {}
href = tmp.find('a').get('href')
title = tmp.find('a').get('title')
data = {"url":"https://www.juzimi.com" + href, "title" : title}
print data
task_queue.put(data)
#print tmp.get('title')
time.sleep(1)

def getFile() :

global has_words
global has_words_value

for line in open('word.log') :
if(line.find('juzimi.com') != -1) :
continue
line = line.split(":", 1)
if(len(line) > 1 and line[1] == 'test') :
continue

#print line[0]
if(not line[0] in has_words) :
has_words.append(line[0])
has_words_value[line[0]] = 1
#print line[0]
else :
has_words_value[line[0]] = has_words_value[line[0]] + 1
has_words = []
for k in has_words_value:
if(has_words_value[k] > 100) :
has_words.append(k)
for line in open('word.url') :
lines = eval(line)
url = lines['url']
title = lines['title'].encode('utf-8')
if(title in has_words) :
continue
task_queue.put(lines)

#runTask()
sleep_time = random.randint(30,60)
#time.sleep(sleep_time)
#time.sleep(60)

def runTask() :
while(not task_queue.empty()) :
data = task_queue.get()
printinfo =[]
hotword = data['title']
url = data['url']
hotword = hotword.encode('utf-8')
#print url
lastIndex = 0
content = curl(url, '', True)
#content = re.sub(r'\n|&nbsp|\xa0|\\xa0|\u3000|\\u3000|\\u0020|\u0020', '', str(content))
content = content.replace('<br/>', '')
content = content.replace('\r', ' ')
soup = BeautifulSoup(content, "html.parser")
last = soup.find('li', {'class', 'pager-last'})
if (not last) :

last = soup.findAll('li', {'class' : 'pager-item'})
if(not last) :
print "get empty:" + url
continue
for tmp in last :
if(int(tmp.text) > lastIndex) :
#print int(tmp.text)
lastIndex = int(tmp.text)
else :
lastIndex = last.text

span = soup.findAll('div',{'class', 'views-field-phpcode-1'})

if(not span) :
print "get empty:" + url
continue

#print url
for tmp in span :
words = tmp.findAll('a')
for word in words :
#printinfo.append({'hotword' : hotword, 'content' : word.text.encode('utf-8')})
print hotword + ":" + word.text.encode('utf-8')
#time.sleep(3)
sleep_time = random.randint(10,20)
#time.sleep(sleep_time)
for i in range(1, int(lastIndex)) :

url = "https://www.juzimi.com/tags/" +hotword + "?page=" + str(i)
#ret = getContent(url, hotword)

t = threading.Thread(target=getContent, args=(url, hotword))
t.start()
"""
for tmp in ret:
printinfo.append(tmp)
"""

"""
for tmp in printinfo :
print tmp['hotword'] + ":" + tmp['content']
"""

def getContent(url, hotword) :
printinfo =[]
#print url
content = curl(url, '', True)
#content = re.sub(r'\n|&nbsp|\xa0|\\xa0|\u3000|\\u3000|\\u0020|\u0020', '', str(content))
content = content.replace('<br/>', '')
content = content.replace('\r', ' ')
soup = BeautifulSoup(content, "html.parser")
last = soup.find('li', {'class', 'pager-last'})
span = soup.findAll('div',{'class', 'views-field-phpcode-1'})
for tmp in span :
words = tmp.findAll('a')
for word in words :
#printinfo.append({'hotword' : hotword, 'content' : word.text.encode('utf-8')})
print hotword + ":" + word.text.encode('utf-8')
sleep_time = random.randint(20,30)
#time.sleep(sleep_time)
#return printinfo

getIp()

getFile()

"""

#setTaskR()
#runTask()
#exit()
"""
executor = ThreadPoolExecutor(max_workers = 50)
#executor.submit(runTask)
#exit()
for i in range(0, 20) :
executor.submit(runTask)

&nbsp;

 

[转]python中str字符串和unicode对象字符串的拼接问题

一个很基本的问题,遇到了,这里记录下

str字符串

s = ‘中文’ # s: <type ‘str’>
s是个str对象,中文字符串。存储方式是字节码。字节码是怎么存的:

如果这行代码在python解释器中输入&运行,那么s的格式就是解释器的编码格式;

如果这行代码是在源码文件中写入、保存然后执行,那么解释器载入代码时就将s初始化为文件指定编码(比如py文件开头那行的utf-8);

unicode对象字符串

unicode是一种编码标准,具体的实现可能是utf-8,utf-16,gbk等等,这就是中文字符串和unicode有密切关系的原因。

python内部使用两个字节存储一个unicode对象(unicode对象并不只能是字符串,这两个字节还可以存其他内容),为什么要用unicode而不用str呢,因为中文转码的缘故,因为unicode的优点是便于跨平台。

s1 = u’中文’ # s1: <type ‘unicode’>
s2 = unicode(‘中文’, ‘utf-8’) # utf8是在指定解码方式, s2: <type ‘unicode’>
str字符串和unicode字符串拼接

只要注意正确的decode、encode方式,统一编码后就能顺利地拼接了。

# -*- coding: utf-8 -*-

s1 = ‘中文’
s2 = u’你好’
print s1 + unicode(s2, ‘utf-8’) # 中文你好
print s1 + s2.decode(‘utf-8’) # 中文你好
print s1.encode(‘utf-8’) + s2 # 中文你好

print type(s1) # <type ‘str’>
print type(s2) # <type ‘unicode’>
print type(s1.decode(‘utf-8’)) # <type ‘unicode’>
print type(s2.encode(‘utf-8’)) # <type ‘str’>
对于str要注意当前环境编码方式,也许是控制台那种设定好了的,也许是你自己在代码中指定的。(看你的代码是在哪里敲的了)
对于unicode对象,一般都是decode得到的,像直接【u’你好’】这种其实不是很常见,所以要注意字符串来源是什么编码,比如从gbk文件或utf8文件中读入的。
———————
作者:Joy_Shen
来源:CSDN
原文:https://blog.csdn.net/index20001/article/details/78974814
版权声明:本文为博主原创文章,转载请附上博文链接!

一款跨平台的Web目录扫描工具

工具是由安全盒子王松编写 是用Python编写的  其中包含脚本识别 后台地址 以及乌云抓的常见漏洞url

这对于Ubuntu系统的用户 特别方便  Windows上也有很多的扫描目录的好工具 比如御剑 wwwscan 等等很多

我自己加入了一点点字典

亲测

从github上下载即可

[AppleScript] 纯文本查看 复制代码
1
2
3
4
5
git clone [url]https://github.com/Strikersb/webdirscan[/url]
cd webdirscan
python webdirscan.py  url

报错的话 安装的第三方Python模块成功解决

[AppleScript] 纯文本查看 复制代码
1
pip install requests

运行图如下

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
root@xaiSec:/home/hacker# cd webdirscan
root@xaiSec:/home/hacker/webdirscan# python webdirscan.py -h
usage: webdirscan.py [-h] [-d SCANDICT] [-o SCANOUTPUT] [-t THREADNUM]
                     scanSite
positional arguments:
  scanSite              The website to be scanned
optional arguments:
  -h, --help            show this help message and exit
  -d SCANDICT, --dict SCANDICT
                        Dictionary for scanning
  -o SCANOUTPUT, --output SCANOUTPUT
                        Results saved files
  -t THREADNUM, --thread THREADNUM
                        Number of threads running the program
root@xaiSec:/home/hacker/webdirscan#

翻译后

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
用法:webdirscan.py [-h] [-d SCANDICT] [-o SCANOUTPUT] [-t THREADNUM]
                      scanSite
位置参数:
   scanSite要扫描的网站
可选参数:
   -h,--help显示此帮助消息并退出
   -d SCANDICT,--dict SCANDICT
                         扫描词典
   -o SCANOUTPUT,--output SCANOUTPUT
                         结果保存的文件
   -t THREADNUM, - thread THREADNUM
                         运行程序的线程数

首先我们先来扫描一个网站 比如我们来扫描下百度= =  嘿嘿
输出结果为以下

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
root@xaiSec:/home/hacker/webdirscan# python webdirscan.py [url]www.baidu.com[/url]
Dirscan is running!
Scan target: [url]http://www.baidu.com[/url]
Total Dictionary: 85025
[200]http://www.baidu.com/robots.txt
[200]http://www.baidu.com/index.htm
[200]http://www.baidu.com/index.php
[200]http://www.baidu.com/index.html
[200]http://www.baidu.com/index.html
[200]http://www.baidu.com/cache/
[200]http://www.baidu.com/index.htm
[200]http://www.baidu.com/robots.txt

 

whistle代理调试工具

首先看官方文档:http://wproxy.org/whistle/

whistle(读音[ˈwɪsəl],拼音[wēisǒu])基于Node实现的跨平台web调试代理工具,类似的工具有Windows平台上的Fiddler,主要用于查看、修改HTTP、HTTPS、Websocket的请求、响应,也可以作为HTTP代理服务器使用,不同于Fiddler通过断点修改请求响应的方式,whistle采用的是类似配置系统hosts的方式,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式,且可以通过Node模块扩展功能

这里简单介绍下安装

安装启动

安装启动whistle,需要以下四个步骤: 安装Node安装whistle启动whistle配置代理

1. 安装Node

whistle支持v0.10.0以上版本的Node,为获取更好的性能,推荐安装最新版本的Node。

如果你的系统已经安装了v0.10.0以上版本的Node,可以忽略此步骤,直接进入安装whistle的步骤,否则:

  1. Windows或Mac系统,访问https://nodejs.org/,安装LTS版本的Node,默认安装即可。
  2. Linux下推荐使用源码安装: 从Node官网下载最新版的Source Code(或者用wget命令下载),解压文件(tar -xzvf node-vx.y.z.tar.gz)后进入解压后的根目录(node-vx.y.z),依次执行./configure./make./make install

安装完Node后,执行下面命令,查看当前Node版本

$ node -v
v4.4.0

如果能正常输出Node的版本号,表示Node已安装成功(Windows系统可能需要重新打开cmd)。

2. 安装whistle

Node安装成功后,执行如下npm命令安装whistle (Mac或Linux的非root用户需要在命令行前面加sudo,如:sudo npm install -g whistle

$ npm install -g whistle

npm默认镜像是在国外,有时候安装速度很慢或者出现安装不了的情况,如果无法安装或者安装很慢,可以使用taobao的镜像安装:

$ npm install cnpm -g --registry=https://registry.npm.taobao.org
$ cnpm install -g whistle

或者直接指定镜像安装:
$ npm install whistle -g --registry=https://registry.npm.taobao.org

whistle安装完成后,执行命令 whistle help 或 w2 help,查看whistle的帮助信息

$ w2 help

 Usage: whistle <command> [options]


  Commands:

    status              Show the running status of whistle
    use/add [filepath]  Set rules from a specified js file (.whistle.js by default)
    run                 Start a front service
    start               Start a background service
    stop                Stop current background service
    restart             Restart current background service
    help                Display help information

  Options:

    -h, --help                                      output usage information
    -D, --baseDir [baseDir]                         set the configured storage root path
    -z, --certDir [directory]                       set custom certificate store directory
    -l, --localUIHost [hostname]                    set the domain for the web ui of whistle (local.whistlejs.com by default)
    -L, --pluginHost [hostname]                     set the domain for the web ui of plugin  (as: "script=a.b.com&vase=x.y.com")
    -n, --username [username]                       set the username to access the web ui of whistle
    -w, --password [password]                       set the password to access the web ui of whistle
    -N, --guestName [username]                      set the the guest name to access the web ui of whistle (can only view the data)
    -W, --guestPassword [password]                  set the guest password to access the web ui of whistle (can only view the data)
    -s, --sockets [number]                          set the max number of cached long connection on each domain (60 by default)
    -S, --storage [newStorageDir]                   set the configured storage directory
    -C, --copy [storageDir]                         copy the configuration of the specified directory to a new directory
    -c, --dnsCache [time]                           set the cache time of DNS (30000ms by default)
    -H, --host [host]                               set the listening host (INADDR_ANY by default)
    -p, --port [port]                               set the listening port (8899 by default)
    -P, --uiport [uiport]                           set the listening port of whistle (8900 by default)
    -m, --middlewares [script path or module name]  set the express middlewares loaded at startup (as: xx,yy/zz.js)
    -M, --mode [mode]                               set the way of starting the whistle mode (as: pureProxy|debug|multiEnv)
    -u, --uipath [script path]                      set the path of custom web ui
    -t, --timeout [ms]                              set the request timeout (66000ms by default)
    -e, --extra [extraData]                         set the extra parameters for plugin
    -f, --secureFilter [secureFilter]               set the path of secure filter
    -R, --reqCacheSize [reqCacheSize]               set the cache size of request data (600 by default)
    -F, --frameCacheSize [frameCacheSize]           set the cache size of webSocket and socket's frames (512 by default)
    -V, --version                                   output the version number

如果能正常输出whistle的帮助信息,表示whistle已安装成功。

3. 启动whistle

最新版本的whistle支持三种等价的命令whistlew2wproxy

启动whistle:

$ w2 start

Note: 如果要防止其他人访问配置页面,可以在启动时加上登录用户名和密码 -n yourusername -w yourpassword

重启whsitle:

$ w2 restart

停止whistle:

$ w2 stop

调试模式启动whistle(主要用于查看whistle的异常及插件开发):

$ w2 run

启动完whistle后,最后一步需要配置代理。

4. 配置代理

配置信息
  1. 代理服务器:127.0.0.1 (如果部署在远程服务器或虚拟机上,改成对应服务器或虚拟机的ip即可)
  2. 默认端口:8899 (如果端口被占用,可以在启动是时通过 -p 来指定新的端口,更多信息可以通过执行命令行 w2 help (v0.7.0及以上版本也可以使用w2 help) 查看)

勾选上 对所有协议均使用相同的代理服务器

代理配置方式(把上面配置信息配置上即可)
  1. 全局代理:直接配置系统代理:
    • Windows
    • Mac: System Preferences > Network > Advanced > Proxies > HTTP or HTTPS
       

      * Linux: Settings > Network > VPN > Network Proxy > Manual

       
  2. 浏览器代理:安装浏览器代理插件 (推荐)
    • 安装Chrome代理插件:推荐安装SwitchyOmega

      * Firefox: 地址栏输入访问 `about:preferences`,找到 `Network Proxy`,选择 `手动代理配置(Manual proxy configuration)`,输入代理服务器地址、端口,保存

       
  3. 移动端需要在设置中配置当前Wi-Fi的代理,以 iOS 为例:

PS: 如果配置完代理,手机无法访问,可能是whistle所在的电脑防火墙限制了远程访问whistle的端口,关闭防火墙或者设置白名单:http://jingyan.baidu.com/article/870c6fc317cae7b03ee4be48.html

访问配置页面

启动whistle及配置完代理后,用Chrome浏览器(由于css兼容性问题界面只支持Chrome浏览器)访问配置页面,如果能正常打开页面,whistle安装启动完毕,可以开始使用。

可以通过以下两种方式来访问配置页面:

[转]百度的春晚战事(猜猜哪个是博主)

百度的春晚战事

原创: 史中 浅黑科技 浅黑科技 今天

编辑

请点击输入图片描述

浅友们大家好~我是史中,我的日常生活是开撩五湖四海的科技大牛,我会尝试各种姿势,把他们的无边脑洞和温情故事讲给你听。如果你特别想听到谁的故事,不妨加微信(微信号:shizhongpro)告诉我。

百度的春晚战事

文 | 史中

我们对春晚一无所知。

罗振宇曾在跨年演讲上如是说。

无论悲喜,反正每个中国人都为春晚辟出了一块“专属记忆”。而从2015年开始,中国人的春晚记忆里被点上了一颗“红痣”。那就是——总有一家顶尖互联网公司面带羞赧地走上舞台,给十几亿人发红包。

“一无所知”的形容,可谓精妙。春晚时,你只知道自己在对着电视刷红包,但从空中俯瞰,十多亿人同时拿起手机,将会汇聚起怎样一种数据海啸,即使《2012》《后天》里的那种惊天排浪,也难以企及十分之一。

据说,美国“超级碗”直播中间插播广告的时候,电视机前的几亿观众会集体上厕所冲马桶,导致美国各大城市的市政供水出现崩溃。超级碗直播的全球观众有1.3亿。而我们的春晚直播,全球观众有13亿。

2015年,微信曾经上春晚发过红包,在全国观众的冲击下一度跪倒长达一小时,俯首拜年。

 

2018年,淘宝为春晚准备了三倍于“双11”的服务器资源。而就在主持人口播活动开始的一瞬间,服务器瞬间超过负荷。事实证明,春晚观众肉身涌进淘宝服务器的瞬时流量是当年“双11”的15倍。

精明的腾讯阿里,都是提前三个月准备春晚,尚且如此狼狈。

而2019年,央视春晚红包招标时间很晚,距离除夕只有一个多月的时间。巨头们都觉得凶险异常,百度却高高举手:我来!我来!

所有吃瓜群众都侧目,这种“情商低”的状态,还真是百度的风格。。。

接下来中哥就告诉你,2019年2月4日除夕晚上,这片土地上究竟发生了什么。

编辑

请点击输入图片描述

(零)百度的一封信、一部引擎和一场战役 

故事,要从一封信说起。

2018年12月18日,李彦宏突然发布了一封内部信,宣布了一个神秘的“1218改革”。其中一条如下:

所有部门的基础技术整合到“TG”(基础技术体系),数据中心、基础架构、运维这些百度核心技术和技术大牛全部兵合一处将打一家。

在一般人眼里,这好像是个路人甲的架构调整;但技术人看后却内心一惊,百度正在把所有部门的核心发动机拆开,重新组装成了一个硕大无朋的“擎天柱”。

用破釜沉舟来形容,丝毫不过分。

而“擎天柱”的负责人,是十五年的老百度人,百度云的创立者之一:侯震宇。震宇隐隐然觉得“天将降大任”,但他又实在猜不透,自己手上这个变形金刚将会用什么姿势书写历史。

2019年1月4日,刚刚划归震宇部门的大牛架构师汪瑫从上海来到北京汇报。工作聊罢,汪瑫轻描淡写地告诉震宇一个“One more thing”。

“听说业务部门刚刚拿下了今年的春晚红包,你知道吗?”汪瑫说。

“什么??!!”震宇当时如同全身过电,血往上涌。就在前后脚,百度 App 部门联系震宇,确认了春晚红包的项目。

编辑

请点击输入图片描述

侯震宇

那一刻震宇意识到,“擎天柱”的第一战已经来了——在履职的第16天,组织架构都来不及调整,新任务也来不及制定,甚至连人都没认全的情况下,要负责保障一个“全中国人都对其威力一无所知”的春晚。

这还真是一个故事的好开头啊。

就在此时此刻,穿越几道门,坐在办公室里的“厂长”李彦宏一如既往地气定神闲,没人能看出他内心究竟是平静如水还是波涛汹涌。

过去几年,百度过得并不轻松。

公司的一些商业决策失误被人诟病,正在艰难地走出泥泞;而在百度文化里如同“定盘星”一样闪耀的技术人,也一边忍受着旁人的侧目,一边度过艰难的日子。

商业上的是非博弈,永远有回旋的余地。但技术人的心一旦散了,百度的未来将会被彻底改写。

李彦宏比任何人都清楚,对士兵最大的慷慨,就是为他们准备一个盛大的战场。

百度人渴望一场大战,洗刷十年风尘。

编辑

请点击输入图片描述

李彦宏

(一)生死战 

不用多想,你都能把百度的春晚发红包的姿势猜得八九不离十:

1、时间:春晚期间,分几轮发红包;

2、地点:打开“百度 App”;

3、人物:全体中国人;

4、动作:点点点点点。

万万想不到,就是这么简单的四步,引发了接下来整整一个月惊天动地血雨腥风的故事。

说回当时。

远在三亚休假的百度信息流主任架构师吴永巍也同时接到这个消息,一刻不停地赶回他所在的上海研发中心,又赶最早的飞机降落北京。

编辑

请点击输入图片描述

吴永巍

震宇代表基础技术保障团队,吴永巍代表百度 App 的技术团队组成了联合作战组。他们一秒都不敢耽搁,当天就开始筹备组建春晚红包技术团队。

贺峰,十一年百度人,运维负责人,他责无旁贷地成为“百度春晚红包”稳定性计划总制定者。

 

陈曦洋,十一年百度人,系统性能优化大神,他的能力是像庖丁解牛一样把一个 App 拆解成细碎的零件,为每一个零件做细致的优化,使得 App 所需的系统网络资源降低到理论最低极限。

 

汪瑫,七年百度人,不仅是技术大牛,还和百度登录帐号团队非常熟悉。

 

宋磊,十年百度人,系统部网络组专家,主要工作是维护百度网络的稳定运行。

 

张家军,八年百度人,系统部供应链负责人,百度平日所需的新增服务器,都由他来搞定。

 

等等等等,后面的名单还有长长一串。

所有的技术人,听到“春晚任务”,第一反应都是懵逼。因为他们的很多朋友都在阿里、腾讯,这些人曾经哭诉春晚有多么残忍的场景还历历在目。风水轮流转,这下轮到自己了。。。

但是,几乎只有一秒钟的迟疑,他们又变得像孩子一样兴奋。

外界不总是说,百度在移动时代不行了么?但是,行不行别人说了可不算。十年了,我们终于不用再等了。厂长既然给我们这次机会,我倒要证明给所有人看,我们到底是行还是不行!

贺峰对所有人说。

编辑

请点击输入图片描述

贺峰

很快,经过全部专家组讨论,贺峰把最终的计划表拿出来了。(原任务表极其复杂,中哥用自己的话解释给你。)

任务一:陈曦洋“拆解”百度 App 的每一个零件,精确计算出当天每一个 App 将会发出多少流量,进而计算出春晚时百度所需准备的总资源数量。(时间:第一周。)

任务二:贺峰亲自操刀,制定“春晚剧本”。春晚当天,百度集团所有系统资源全部切换档位,其他系统让位给红包系统。红包抢完,要在最短时间内再把系统资源还给其他部门。为此,需要一个极其精密无缝切换的操作预案。(时间:第一周+第二周。)

任务三:由于百度内部所能协调出来的系统资源不够,张家军要向全国厂商发出数万台服务器的紧急采购,确保打仗所需的全部“粮草”及时到位。(时间:第二周+第三周。)

任务四:宋磊向运营商全面采购带宽等软资源,建设足够的 IDC 网络  CDN 网络。(时间:第二周-第四周。)

任务五:陈曦洋协助百度 App 团队,百度 App 每秒数据传输量降到最少,然后打包成最新版百度 App 下发,确保春晚当天每个人手上的百度 App 都是性能最佳的最新版。(时间:第二周+第三周。)

任务六:陈曦洋协助小程序团队,一起开发春晚当天红包的小程序,确保这个小程序也占用最少的资源。(时间:第四周)

任务七:汪瑫负责协助百度帐号登录体系(Passport)进行全方位加固,应对春晚涌来的登录请求。(时间:第一周直到春晚。)

任务八:通知各大第三方应用市场,告诉他们春晚的时候,可能会有大量用户去下载百度 App,让他们也做好准备。

任务九:所有资源+调优全部到位,联合百度 App 的业务部门进行四轮“全链路联合测试”。(时间:第四周。)

任务十:春晚当天,所有人全力以赴,抗住十三亿人的流量海啸

十大任务列阵于此,旌旗猎猎。

编辑

请点击输入图片描述

彼时,即使是计划制定者贺峰也难以想象,在未来四周时间里,百度、三大运营商、全球硬件供应链、中国数家服务器厂商、外包建设团队、机房运维团队、全世界总计数万人和他们的家人将会为此付出怎样艰苦卓绝的努力。

但此时此刻,已经没人能阻挡这一切发生了。

这将是我职业生涯的生死战。

贺峰说。

(二)太空变轨 

计算结果出来了!我预计春晚的流量,每秒峰值将会达到5000万次!每分钟的峰值将会达到10亿次!

陈曦洋一夜没睡,拿着最新出炉的报表对贺峰说。

编辑

请点击输入图片描述

为了测算流量,陈曦洋研究了不少腾讯、阿里红包相关新闻。

经过计算,支撑这些流量的云计算系统,需要由10万台服务器组成。

这意味着什么呢?

2018年全年,全中国960万平方公里销售的全部服务器是300万台。而百度需要在一个月内,毫无准备的情况下,搞定去年全国销量的三十分之一,并且完成采购、生产、调试、接入百度云的全过程。

贺峰知道,如果全靠临时采购,这件事不可能完成。百度内部必须让出至少5万台服务器来支持春晚红包计划。

“凤巢广告系统、原生广告系统、网盟变现系统,统统要在春晚过程中熄火,把资源让给红包系统。”贺峰的计划白纸黑字。

要知道,凤巢系统是百度的广告收入核心。凤巢暂停四小时,意味着百度这艘火箭要在万米高空强行熄火,失速四小时。

编辑

请点击输入图片描述

而这不仅是真金白银的损失,还是一个极其危险的操作——万一熄火之后点不着,凤巢系统将面临对数百万客户的巨额赔偿。

当贺峰把计划拿给凤巢负责人王岳的时候,内心是很打鼓的,他知道对方有一万个理由拒绝他的计划。但是,王岳仅仅花十分钟看完了方案,说了三个字:没问题!

“没问题”,意味着一部包含5万台服务器的超级引擎将会在春晚四小时交由贺峰团队驾驶,这一下就满足了计划所需的一半。

剩下的5万台,交给采购部门,这个等下再说。回来继续看陈曦洋。

10万台服务器已经是团队的极限了。但是陈曦洋知道,把服务器总数控制在10万台,这还是有前提的。前提就是每个用户手机上的百度 App 还需要进行大量优化。

当陈曦洋带着三个兄弟完成对百度 App 的解析之后,他的眼泪都快流下来了。

百度 App 在启动时,会对自家服务器发送100多个连接。这些连接来自于百度不同的业务团队。

 

陈曦洋一下就懂了。由于百度 App 是目前百度装机量最高的超级 App,是“全村人的希望”。所以很多业务和技术同学都把展示自己团队成果的模块挤进百度 App,只是希望自己的努力能够被更多的用户感受到。

这些年逆风行船,百度的技术产品人其实一直在用力。

编辑

请点击输入图片描述

但是对于此刻的陈曦洋来说,这意味着灾难。在春晚当天,每一秒钟,每一个连接都要乘以几千万人这么一个倍数,每个 App 100 个连接,每秒就是几十亿次连接,BAT 加在一起都必跪无疑。

只见陈曦洋,此时已经红了眼,变成了“操刀鬼”——对百度 App 所有连接大砍大杀。

1月10日,陈曦洋和指挥部的领导开会,大家一致认定,百度 App 对外连接的数量,要从100个砍到3个。

由于 AppStore 和各大安卓商店都需要有审核时间,百度 App 必须在春晚前两周发布最新版本,所以很多连接来不及修改背后的整体逻辑,只能用暂时抑制的方式来处理。

编辑

请点击输入图片描述

花开两朵,各表一枝。

那边“操刀鬼”陈曦洋正在为百度 App 瘦身,这边“拼命三郎”汪瑫已经代表项目组进驻了百度帐号体系团队。

多说一句,汪瑫本来属于上海团队,和春晚项目关系不大。但是由于他技术非常牛,又和帐号团队比较熟悉,被震宇和吴永巍“强行”拉来参与春晚计划。接到任务时他二话没说,第二天就飞到北京,开始了长达一个月的加班。

编辑

请点击输入图片描述

汪瑫

业内八卦显示:2018年,淘宝春晚发红包,最大的问题就出在了登录系统。

讲真,由于搜索业务天然不必须登陆操作。这么多年来,百度的帐号体系建设是弱于电商阿里和社交腾讯的。

祸不单行,就在接到春晚任务之前,帐号团队的技术负责人李盈沉浸在苦恼中,因为他团队的一位优秀的同学提出了离职。但是,就在接到任务的当天,那位原本想离职的同学找到李盈,说自己不走了。

“我想打仗。”他说。

百度 App 登录状态的比例比较低。但是抢红包的时候,技术上必须要登录才能知道给谁“结账”。所以汪瑫预计,春晚当天百度 App 会遭受一波剧烈的登录冲击。有多剧烈呢?预计会是平常登录峰值的 2500 倍。

这意味着将会有很多人请求短信验证码。

编辑

请点击输入图片描述

时间有限,汪瑫一边连夜协助帐号团队做各种优化,一边让团队向各大运营商和第三方服务商购买短信发送的服务。一时间,所有省市的三大运营商的短信发送能力,被百度一家预定一空。

但即使是这样,还是不能满足春晚当天的预计值,汪瑫紧急派出百度最好的工程师进驻第三方服务商,帮助他们优化代码,提高短信发送的能力。终于达到了预期数值。

所有工程师的这些操作都在短短两周内叠加在一起。对于百度来说,这是一场史诗级的“太空变轨”。

软件这边忙得热火朝天,转回头来看,还有5万台服务器的硬件缺口。所有人的目光都落在张家军身上。

编辑

请点击输入图片描述

张家军

(三)那个疯狂的夜晚 

贺峰看着张家军说:“不要有压力,我们这次肯定‘一战成名’。”

“此话怎讲?”张家军问。

“就是说,成功也会出名,失败也会出名。”

“。。。”

张家军盘点了一下手上的“数据中心地图”,他发现自己简直是太幸运了:

北京数据中心曾经预定了4万台服务器,约定春节前交货。此时已经有2万多台交付完毕,还剩1.8万台未交付。

于是,张家军的计划很快出炉:

1、催促北京数据中心在一周内交付1.8万台服务器。

 

2、拼尽全力,就是抢,也要在两周内抢来1万台新的服务器,放到南京数据中心。

这些服务器都会并入百度云统一调配。张家军发现,虽然百度云平时默不作声,但是这么多年对于技术的极致追求,越是在艰难的时刻越能体现出闪光的价值:

百度设计的服务器,大多是以整体机柜的方式制造的。也就是说,在服务器厂家出厂的时候,就已经是一台大机柜里面固定好30台服务器的形态了。

这意味着,百度云不需要像其他云计算厂商那样,一台服务器一台服务器地在现场安装,而是把整个机柜直接推进去就可以进行测试安装了。

编辑

请点击输入图片描述

这就是整体机柜在安装时的场景

在接下来的一周里,百度的合作伙伴浪潮也体现出了国际顶尖的专业精神,一队队卡车整齐地并入高速公路,直接开赴北京。

你可能不相信,这两个大厂,共同创造了8小时安装1万台服务器的世界纪录。

编辑

请点击输入图片描述

北京如期搞定。

但最让张家军头疼的是,如何凭空变出来南京机房的1万台服务器。

他给我算了一笔账:

电子行业的硬件备货周期,通常就是8-12周。也就是说,你要至少提前两三个月向服务器生产商和零部件供应商下订单。

 

即使是服务器厂商完全停掉手中其他的活,产能也是有限的。从接到订单到生产出来,一般也要一周时间。

 

从卡车从服务器厂商的车间开出来,到百度数据中心,一般需要3-5天时间。

 

从服务器检测安装,到并网调试,一般需要1-2天。

“我接到任务的时间是1月6日,我的任务是:1月21日早晨8点,1万台服务器要一台不少齐装满员站在南京机房里。”张家军看着我,一字一顿地说。

“对不起,我们的生产能力不够,不能耽误百度春晚这么大的事儿,这个单子我们不敢接。”这几乎是所有服务器生产商对于张家军的标准回复。

只有几家大型服务器生产厂商接受订单,但是,限于原料储备不足,他们未来两周的生产能力上限是——4000台。

这下张家军的任务变成了:帮助服务器厂商协调全球供应链,从全世界找到另外几千台服务器的所有配件。

如果换成别人,任务到此已经可以宣告失败了。

但是张家军不准备认输。

过去几年,他和同事们拼命了解产业链的运作方式,和各大厂商建立联系,一点一点构建百度云的基础设施。他们赌上了自己的青春和年华,却依然能听到外界很多讥讽的声音。这么多年都扛过来了,就是因为他们相信,有朝一日,所有的证明都会如数归来,那些不该他们承受的东西,终会像雾霾一样退散。

此时此刻,他怎么舍得认输。

他和团队给全球的供应商一个一个打电话,买最近的一班飞机飞到国外,到每一个工厂里查看零件配给数量。一天,两天,三天,这些原本计划分配给美国、欧洲的零部件,从以色列、美国、东南亚调转航向,一起向中国飞来。

这是一场全球供应链的胜利。

服务器厂商开足马力,所有工人放弃了提前回家的计划,回到岗位三班倒,服务器被源源不断地生产出来。卡车等在工厂门口,放弃编队,装满一辆车就出发一辆,在通往南京的高速公路上,每隔一百公里就有一辆满载服务器的卡车在飞驰。

南京数据中心里,百度的工作人员、机房运维人员、建设外包队伍已经严阵以待。

张家军在北京总部协调,不能脱身,于是他和南京24小时通着电话,时刻指挥进展。服务器进驻机房, 还要有调试的过程,但凡有哪一步出现差错,就会导致满盘皆输。所以,张家军团队为每一种想到的意外都做了周密的预案。

1月20日夜里,最大一波服务器抵达南京,眼看大功告成。此时,一个最不可能发生的意外,却真的发生了。

机房的货梯,由于承受不住一吨多的机柜上下折磨,毫无预警地罢工了。他们马上转战客梯,客梯很快也出现故障。

编辑

请点击输入图片描述

有人拍下了当时紧急修复电梯的场景

临近春节,电梯检修人员大多回家过年,人手非常紧张,要天亮才能赶到。但是百度的同学们知道,仅仅这一夜,他们也是等不起的。

漆黑的夜里,所有现场的人员,用双手和双肩扛起来一百多斤的服务器,一步一步地从楼梯往上爬。

当时一位同学用视频记录下了现场的场景:

人肉抬服务器上楼

有同学的手被划破了,血珠渗出来。同事要把它换下来,他只是摇头,说没事。有人看到了他眼角的泪水。

现场还有很多一吨多的整机柜服务器,靠人力根本搬不上楼。现场指挥部的同学,甚至叫来了一辆吊车,要砸开机房的窗户运进去。

张家军在视频里看到现场吊车的钩子在风中摇晃,惊出一身冷汗。他怕同学受伤,言辞拒绝了这个方案。但是现场的负责人反复恳求:你就让我们试试吧!服务器要上楼啊!!

终于,现场维修团队想到了一个办法,紧急把隔壁楼的电梯配件拆过来,货梯终于缓缓启动,那时,已经是半夜两点了。

2019年1月21日早晨八点,负责服务器软件调试的同学如期赶到,所有的服务器静静地站在机房里。它们就那样沉默着,仿佛昨夜什么都没发生。

(四)核弹头就位 

1月17日,百度召开总监会。

贺峰回忆,李彦宏的表情“非常淡定”。他只是笑眯眯地看着大伙儿,说:“你们一定能搞成的。”这次总监会只是比平常多了一个小环节,晚上大家一起吃了个饭,李彦宏挨桌给大伙敬了酒。

实际上,那几天正是所有团队最焦头烂额的时候。

震宇告诉我,就在这一个月的时间,百度的 IDC 新增带宽资源超过了过去20年的历史总和,CDN 资源新增了2018年的一半。

根据宋磊回忆,两周左右的时间里,69位工程师飞了7万多公里。北上广的剩余带宽资源几乎都被百度拿空了。

编辑

请点击输入图片描述

宋磊

和他的朋友可乐君

网络团队有两位工程师是夫妻,一个负责网络建设,一个负责网络测试。一个人刚建设好,回家看孩子,换另一个人来测试。有时候建设工程师要陪着测试工程师一起工作,两个人只好把孩子扔给老人,一夜都不回家。

而宋磊本人,从1月6日计划启动到大年初一,睡得最长的一晚是五个小时,最短只有一个小时。

编辑

请点击输入图片描述

一位同学躺在桌子上睡觉,被无情偷拍。

时间一刻不停,已经是1月26日。距离春晚还有8天。

这一边,张家军的“粮草”已经全部到位,工程师也把所有的服务器完整无误地接入百度云,10万台机器全副武装准备就绪。宋磊新建了相当于支撑全澳洲人口同时观看视频的 CDN 和 IDC 网络,并且连续几个通宵完成了压力测试。

另一边,陈曦洋成功地把百度 App 对外连接数从100个砍到3个,汪瑫把百度 App 的登陆能力从1500人次每秒疯狂提升到15万人次每秒。

百度开启了“春晚红包计划”全链路测试。

贺峰为这四个半小时制定了几百页的“剧本”。剧本分为两部分:

1、主持人播报抢红包开始的每一个时间点,百度系统分别提前多少秒做好什么准备。就像火箭发射一般精密。

 

2、一旦遇到意外情况,哪个子系统要做出怎样的调整,根据意外程度的不同,做出的调整力度也不同,这套预案中,涉及到了上千条意外情况。一旦条件触发,指挥部的同学只要点击一个按钮,就能启动相应的更改。

编辑

请点击输入图片描述

这就是“剧本”

根据经验,运维人员真正遇到问题的时候,心理会承受巨大的冲击,很容易慌乱。为了让同学们临危不乱,贺峰还专门编写了《作战守则》,上面写着“指令要清晰,行动听指挥”等等要求贴在墙上,发给每一个同学提前学习。

编辑

请点击输入图片描述

对于百度这群工程师来说,这几百页作战计划里的每一条预案,都不是凭空想出来的。他们在写每一个字的时候,都可以回忆起十多年来自己在百度的运维经验,这厚厚一本,哪里是作战计划,分明是一个百度工程师的技术人生。

百度科技园 K2 大楼的整整一个大厅被改成作战指挥室,中心一个核心指挥室,旁边20个小屋是包括百度 App、大搜、摇一摇、帐号系统、BFE中台、网络、系统监控、IT团队、红包核心系统等等在内的分组作战室。加上地下一层本来就有的中控室,组成了联合指挥作战系统。

编辑

请点击输入图片描述

核心指挥室

这里要稍微插一句。

2019年百度春晚的红包设计和之前阿里腾讯的稍有不同。他们把百度 App 日常的功能和红包相结合。比如你要在百度搜索框里语音说出“幸福快乐年”,或者手动刷一下百度 App 首页的新闻瀑布流查看“拜年视频”后才能进入,这就造成了用户行为的不可预测性加大。

这就形成了一个开放空间:难免有人说出方言,或者刷新瀑布流搞错了方向,从而对后台的人工智能系统带来不可预知的巨大压力。

这会导致测试的时候,非常难以模拟春晚真实场景。

百度人的“实在”在这里体现得淋漓尽致。反正我就是要实现这样的效果,技术上的问题,一点点搞就好了。

编辑

请点击输入图片描述

必不可少的步骤:拜杨超越

演习过程中,专门有一队“蓝军”,负责为春晚系统制造各种麻烦,例如掐断某个机房的数据通路,让某一个模块停止响应,甚至直接对百度系统发起攻击。而在另一边,指挥团队严格按照剧本对所有问题瞬间应对。百度安全团队也加入了护航编队,对夹杂在正常访问之间的进攻进行拦截。

虽然中间几经波折,但是在倒数两次联合测试中,整个百度春晚红包系统都经受住每秒5000万次访问的考验。所有人悬了一个月的心,这才稍稍放下一些。一向严谨的吴永巍对团队成员说,我现在的信心指数是85-90分!

就在大家紧锣密鼓忙活的时候,发生了两件怪事:

宋磊在那几周新增了一个习惯:每天半夜两点把自己加班的情况拍照,晒到朋友圈。当时大家还纳闷,为什么老宋那么低调的一个人,却要天天晒加班呢?

 

从上海过来支援的汪瑫,1月24日神秘消失了一天。他究竟去哪了呢?

这些小八卦,当时谁也没空探秘。因为春晚已经近在眼前了。

编辑

请点击输入图片描述

(五)除夕 

2月4日,除夕。

从当天零点开始,已经有同学在作战部值班。早晨八点,全员就绪,大战一触即发。

所有百度的同学里,有两位是最为特殊的。他们当天晚上会进驻到央视直播现场。人们开玩笑说,他们是百度押在央视的“人质”。这两位同学在去之前还满怀激动地打听,我们去了要做什么呢?其他人冷冷地说,根据腾讯和阿里的经验,你们去了只有一个任务:我们这里如果砸了,你们两个负责“挨骂”。

临走时,这两个同学用幽怨的眼神看了一眼百度大部队,决绝地赶赴央视。嘴里唱着“风萧萧兮易水寒。。。”

根据设计,在除夕当天上午11点,百度会向用户推送一个小红包活动作为预热,让真实的用户来参与,从而对系统进行一波实打实的终极测试。

11:00,预热活动开始,后台数据直线上升。百度 App 瞬间访问峰值达到88万次每秒。这个数值已经是百度 App 历史最大峰值的几十倍。但是贺峰知道,这还仅仅是毛毛雨,他们为春晚设计了5000万次每秒的能力。

直到这时,陈曦洋所负责的重要任务——掐断百度 App 的多余回连数据突然有所抖动。陈曦洋和百度 App 的技术同学各个满头大汗,直到直播前一个小时,才把问题解决妥当。

晚上八点,春晚准时开播。

凤巢系统缓缓熄火,红包系统接管引擎驾驶。所有系统齿轮咬合,像起跑线前的赛车一样低吼着冲出去。

编辑

请点击输入图片描述

作战室的同学仿佛进入了另一个世界。整个大厦,掉一根针在地上都能听到。

按照央视彩排的时间表,第一次摇红包应该发生在晚上八点半。但是,就在八点十八分的时候,主持人突然提前预告了一下:“观众朋友们可以下载百度 App 参与今年的春晚摇红包活动。”

这之后一分钟,指挥部的舆情监控群里,突然有人甩进来一张图片:

编辑

请点击输入图片描述

苹果的 AppStore 被网友挤垮,已经打不开了。

陈曦洋赶紧拿出手机测试,哪里是 AppStore,小米、华为等等 AppStore 全部躺尸。他这才明白,虽然当时自己派人和各大应用商店提前打过预防针,但事实证明,他们对春晚“一无所知”。。。

作战组马上给出数据,预计全国有200万-300万人无法下载百度 App,这将带来不小的损失。而另一组数据显示,无法下载 App 的人们又涌向了百度搜索,在手机浏览器里用关键词搜索的方式尝试下载百度 App。

贺峰评估了一下百度 CDN 的占用量,马上下令,把链接指向百度自家的下载接口,让大家不用通过第三方市场,而是直接从百度家下载百度 App。就这样,下载高峰直接冲击百度自家网络,一点一点,几百万人都安装了百度 App。

编辑

请点击输入图片描述

这一切被汪瑫看在眼里。

他的第一反应是:我厂真牛逼。他的第二反应是:这300万人下载了 App 之后,肯定是要登录的啊,我负责的登录系统看来马上就要挂了。。。。

还好,有惊无险,大家分散下载了 App,也就分散登录 App,并没有对登录系统带来致命的打击。

随着春晚的进行,访问百度 App 的流量一轮比一轮大,逼近预计中的峰值。

百度20年积累下来的遍布全国的数据通路,顺利扛过了前三轮红包的数据洪峰,只剩零点钟声敲响前的最后一次。根据预测,这将是最大的一波浪潮。

在最后一次红包到来之前23分钟,贺峰突然接到驻场春晚那两个同学的消息:根据测算,春晚比预计延迟了4分钟。

编辑

请点击输入图片描述

贺峰心里咯噔一下。

这会造成百度 App 红包开抢的时间早于主持人播报的时间。也就是说,听到主持人播报才进来的用户,很可能发现红包已经被准点动手的用户抢完了。。。

贺峰要做一个决定:是保持原计划放开红包,还是要按照春晚的进度延后 App 上红包开抢的时间。

把这么大规模的调整部署到10万台服务器上,起码需要五分钟。

所有人都看着贺峰。贺峰盯着屏幕,两手一压,对大伙说:再等等。

就在红包开启前十分钟,贺峰判断央视应该是无法抢回时间了,下令马上对10万台服务器发出指令,延后4分钟开启红包系统。

上天眷顾,最后百度 App 红包开启的时间,和主持人宣布红包开抢的时间严丝合缝。

一瞬间,上亿人手机屏幕上显示着百度 App 的红包界面,巨大的数据浪潮涌向北京和南京两地的数据机房。那一刻,百度大厦里1000多位同事,百度散落在各地机房的100位同事,带着备用零件守候在机房的100多位服务器厂商的工程师,三大运营商为了保护网络通畅而留守在各地机房的1000多位同事,那些中国通信行业和互联网行业的梦想者,用自己的付出搭建出了人类历史上最宽的信息通路。

暗夜无声,大地上烟花四起。

这个古老的民族,迈入了新的一年。

(六)那些小事 

燃烧了四个半小时的红包系统渐渐熄火。

间断了四个半小时的凤巢系统缓缓启动。

伴随着10万台服务器的嘶嘶声,百度这架火箭完成了太空中的第二次惊险变轨。

指挥部里,欢声雷动。

编辑

请点击输入图片描述

直到这个时候,吴永巍、震宇、贺峰、陈曦洋他们才敢确定,这个曾经击垮了阿里巴巴和腾讯的春晚,并没有击垮百度。他们用了三十个日夜,证明了自己是当之无愧的“老司机”;证明了自己对春晚并不是一无所知。

可叹的是,如此宏大的工程,调动了全球的供应链体系,调动了全中国的网络带宽,调动了全百度的技术资源。中间如果百度系统有任何一个技术环节卡住,百度云的服务器有任何一个螺丝钉松动,百度工程师、商务采购团队有任何一个人掉链子,全中国人都会面对一个完全不同的结局。

百度无疑是幸运的,但这世界上,只有勇者才有资格谈运气。

我听到很多百度同学回忆起那个瞬间,他们描绘的,正如《少林足球》里那个场景:

历经磨难,少林师兄师弟的武功全部觉醒,周星驰跪在地上,说:欢迎各位师兄弟归位!

编辑

请点击输入图片描述

直到正月末,我来到百度科技园来采访春晚红包故事的时候,我依然能够感觉到,在大厦里洋溢着的喜悦气氛。

哦对了,还有一些小事忘记交代。

那两个被“质押”在央视的小伙伴,期待中的指责并没有来,反而被冲进来的央视同事们握着手说:百度真是太牛了,你们是第一个没有出现问题的合作伙伴。你们不是有 AI 技术吗?你们不是有视频技术吗?合作起来呀~

编辑

请点击输入图片描述

而好奇的人们,也终于打听到了前几天神秘事件的原因:

宋磊羞涩地表示,之所以每天凌晨两点发朋友圈,是因为他怕老婆想多了,晒朋友圈以证清白。。。

而汪瑫消失的那一天,是飞回上海给儿子过两岁生日。因为去年儿子一周岁的生日时,他就在外地加班,没能陪他。这次儿子喊着要爸爸,他才连夜飞回去一天。第二天给儿子过完生日,晚上八点他陪儿子上床睡觉,确定儿子睡熟了,才赶紧跑出来,赶十点的飞机飞回北京。

而且,除夕那天其实是吴永巍的生日。但直到整个春晚战役结束,第二天凌晨他才告诉几个小伙伴这件事儿。“我和兄弟们过了最有意义的一个生日。”他说。

离别之前,我颇为郑重地问陈曦洋:“为百度付出了这么多,你觉得值得吗?”

“我只是想证明百度。”陈曦洋说完,沉默良久。

十一年前,我一毕业就加入百度,我的所有技术积累都是百度给我的。我把百度当成家。之前,百度遇到很多问题,我比外面的人更难受,就像对自己的孩子一样,恨铁不成钢。

 

我记得,在2016年百度最困难的时候,我们团队去杭州团建,秋天的杭州特别美。有一位家就在杭州附近的同学,回来之后就辞职去了杭州。

 

我知道,大家都有权做出自己的选择。从2016年到现在,几乎每周都有猎头给我打电话,但我从来都是直接挂掉。我觉得,总有人要让百度变得更好,而我应该是那些人中的一员。

他就这么安静地说着。

听到这里,我突然明白,在春晚红包成功的那一刻,那些百度技术人眼里的泪花,告慰的不是过去一个月的艰苦卓绝,而是十年前的自己,那个不解风情却无问西东的少年。

编辑

请点击输入图片描述

陈曦洋

他们在漫长的岁月里安静地忍受着孤独,这一次却像疯子一样拼尽全力,押上全部韶华和热血。他们也许并没想赢,他们,只是不想输。

有人说,生活是一场战役,结局或是千秋标榜,或是万古遗憾。

但我更相信,岁月是一张长长的考题,没人会逼你交卷。

你尽可以用一生的时间,慢慢给出自己的答案。

编辑

请点击输入图片描述

再自我介绍一下吧。我是史中,是一个倾心故事的科技记者。我的日常是和各路大神聊天。如果想和我做朋友,

可以搜索微信:shizhongpro

或者关注微博:@史中方枪枪 @浅黑科技

不想走丢的话,你也可以关注我的公众号“浅黑科技”。(记得给浅黑加星标哦)

编辑

请点击输入图片描述

岁月

是一张长长的考卷

编辑

请点击输入图片描述

阅读原文

阿里云CentOS 7上安装配置Docker

Docker 是一个开源工具,它可以让创建和管理 Linux 容器变得简单。容器就像是轻量级的虚拟机,并且可以以毫秒级的速度来启动或停止。Docker 帮助系统管理员和程序员在容器中开发应用程序,并且可以扩展到成千上万的节点。

1

这是一只鲸鱼,它托着许多集装箱。我们可以把宿主机可当做这只鲸鱼,把相互隔离的容器可看成集装箱,每个集装箱中都包含自己的应用程序。

Docker与传统虚拟区别

传统虚拟化技术的体系架构:

2

Docker技术的体系架构:

3

容器和 VM(虚拟机)的主要区别是:

  • 容器提供了基于进程的隔离,而虚拟机提供了资源的完全隔离。
  • 虚拟机可能需要一分钟来启动,而容器只需要一秒钟或更短。
  • 容器使用宿主操作系统的内核,而虚拟机使用独立的内核。

Doker 平台的基本构成

4

Docker 平台基本上由三部分组成:

  • 客户端:用户使用 Docker 提供的工具(CLI 以及 API 等)来构建,上传镜像并发布命令来创建和启动容器
  • Docker 主机:从 Docker registry 上下载镜像并启动容器
  • Docker registry:Docker 镜像仓库,用于保存镜像,并提供镜像上传和下载
  • 后面的文章会具体分析。

Docker 容器的状态机

5

一个容器在某个时刻可能处于以下几种状态之一:

  • created:已经被创建 (使用 docker ps -a 命令可以列出)但是还没有被启动 (使用 docker ps 命令还无法列出)
  • running:运行中
  • paused:容器的进程被暂停了
  • restarting:容器的进程正在重启过程中
  • exited:上图中的 stopped 状态,表示容器之前运行过但是现在处于停止状态(要区别于 created 状态,它是指一个新创出的尚未运行过的容器)。可以通过 start 命令使其重新进入 running 状态
  • destroyed:容器被删除了,再也不存在了

Docker 的安装

RedHat/CentOS必须要6.6版本以上,或者7.x才能安装docker,建议在RedHat/CentOS 7上使用docker,因为RedHat/CentOS 7的内核升级到了kernel 3.10,对lxc容器支持更好。

查看Linux内核版本(内核版本必须是3.10或者以上):

cat /proc/version

uname -a

lsb_release -a

##无法执行命令安装
yum install -y redhat-lsb

更新YUM源:

yum update

安装:

yum  install docker -y

检查版本:

docker -v

安装完成后,使用下面的命令来启动 docker 服务,并将其设置为开机启动:

service docker start
chkconfig docker on

下载官方的 CentOS 镜像:

docker pull centos

检查CentOS 镜像是否被获取:

docker images

下载完成后,你应该会看到:

[root@iZ2ze74fkxrls31tr2ia2fZ ~]# docker images centos
REPOSITORY       TAG        IMAGE ID     CREATED         SIZE
docker.io/centos latest    3fa822599e10    3weeks ago   203.5 MB

如果看到以上输出,说明你可以使用“docker.io/centos”这个镜像了,或将其称为仓库(Repository),该镜像有一个名为“latest”的标签(Tag),此外还有一个名为“3fa822599e10 ”的镜像 ID(可能您所看到的镜像 ID 与此处的不一致,那是正常现象,因为这个数字是随机生成的)。此外,我们可以看到该镜像只有 203.5 MB,非常小巧,而不像虚拟机的镜像文件那样庞大。

启动容器:

docker run -i -t -v /root/software/:/mnt/software/ 3fa822599e10 /bin/bash

docker run -ti ubuntu:14.04 /bin/bash

命令参数说明:
docker run <相关参数> <镜像 ID> <初始命令>

  • -i:表示以“交互模式”运行容器
  • -t:表示容器启动后会进入其命令行
  • -v:表示需要将本地哪个目录挂载到容器中,格式:-v <宿主机目录>:<容器目录>

Docker命令

我们可以把Docker 的命令大概地分类如下:

镜像操作:
    build     Build an image from a Dockerfile
    commit    Create a new image from a container's changes
    images    List images
    load      Load an image from a tar archive or STDIN
    pull      Pull an image or a repository from a registry
    push      Push an image or a repository to a registry
    rmi       Remove one or more images
    search    Search the Docker Hub for images
    tag       Tag an image into a repository
    save      Save one or more images to a tar archive 
    history   显示某镜像的历史
    inspect   获取镜像的详细信息

    容器及其中应用的生命周期操作:
    create    创建一个容器
    kill      Kill one or more running containers
    inspect   Return low-level information on a container, image or task
    pause     Pause all processes within one or more containers
    ps        List containers
    rm        删除一个或者多个容器
    rename    Rename a container
    restart   Restart a container
    run       创建并启动一个容器
    start     启动一个处于停止状态的容器
    stats     显示容器实时的资源消耗信息
    stop      停止一个处于运行状态的容器
    top       Display the running processes of a container
    unpause   Unpause all processes within one or more containers
    update    Update configuration of one or more containers
    wait      Block until a container stops, then print its exit code
    attach    Attach to a running container
    exec      Run a command in a running container
    port      List port mappings or a specific mapping for the container
    logs      获取容器的日志

    容器文件系统操作:
    cp        Copy files/folders between a container and the local filesystem
    diff      Inspect changes on a container's filesystem
    export    Export a container's filesystem as a tar archive
    import    Import the contents from a tarball to create a filesystem image

    Docker registry 操作:
    login     Log in to a Docker registry.
    logout    Log out from a Docker registry.

    Volume 操作
    volume    Manage Docker volumes

    网络操作
    network   Manage Docker networks

    Swarm 相关操作
    swarm     Manage Docker Swarm
    service   Manage Docker services
    node      Manage Docker Swarm nodes

    系统操作:
    version   Show the Docker version information
    events    持续返回docker 事件
    info      显示Docker 主机系统范围内的信息
# 查看运行中的容器
docker ps

# 查看所有容器
docker ps -a

# 退出容器
按Ctrl+D 即可退出当前容器【但退出后会停止容器】

# 退出不停止容器:
组合键:Ctrl+P+Q

# 启动容器
docker start 容器名或ID

# 进入容器
docker attach 容器名或ID

# 停止容器
docker stop 容器名或ID

# 暂停容器
docker pause 容器名或ID

#继续容器
docker unpause 容器名或ID

# 删除容器
docker rm 容器名或ID

# 删除全部容器--慎用
docker stop $(docker ps -q) & docker rm $(docker ps -aq)

#保存容器,生成镜像
docker commit 容器ID 镜像名称

#从 host 拷贝文件到 container 里面
docker cp /home/soft centos:/webapp

docker run与start的区别

docker run 只在第一次运行时使用,将镜像放到容器中,以后再次启动这个容器时,只需要使用命令docker start 即可。

docker run相当于执行了两步操作:将镜像放入容器中(docker create),然后将容器启动,使之变成运行时容器(docker start)。

6

而docker start的作用是,重新启动已存在的镜像。也就是说,如果使用这个命令,我们必须事先知道这个容器的ID,或者这个容器的名字,我们可以使用docker ps找到这个容器的信息。

7

因为容器的ID是随机码,而容器的名字又是看似无意义的命名,我们可以使用命令:

docker rename jovial_cori  centos

给这个容器命名。这样以后,我们再次启动或停止容器时,就可以直接使用这个名字:

docker [stop] [start]  new_name

而要显示出所有容器,包括没有启动的,可以使用命令:

docker ps -a

Docker配置

更改存储目录:

#复制docker存储目录
rsync -aXS /var/lib/docker/. /home/docker

#更改 docker 存储文件目录
ln -s  /home/docker  /var/lib/docker

获取IP:

docker inspect <container id>

要获取所有容器名称及其IP地址只需一个命令:

docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq)

docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

Docker 镜像加速器

注册个帐号

https://dev.aliyun.com/search.html

阿里云会自动为用户分配一个镜像加速器的地址,登录后进入”管理中心”–>”加速器”,里面有分配给你的镜像加速器的地址以及各个环境的使用说明。

镜像加速器地址:https://xxxxx.mirror.aliyuncs.com

如何配置镜像加速器

针对Docker客户端版本大于1.10.0的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器:

{
    "registry-mirrors": ["<your accelerate address>"]
}

重启Docker Daemon:

sudo systemctl daemon-reload
sudo systemctl restart docker

后续:
1,查看镜像
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1fef6edc3f23 docker.io/centos "bin/bash" About a minute ago Exited (0) 8 seconds ago affectionate_khorana
66f6e4ff1098 docker.io/centos "bin/bash" About a minute ago Exited (0) About a minute ago elastic_khorana
a44b68ea8265 75835a67d134 "/bin/bash" 7 minutes ago Exited (0) 2 minutes ago angry_meitner
d0c8cbacb8ce 75835a67d134 "/bin/bash" 25 minutes ago Exited (0) 13 minutes ago mystifying_perlman
2.更新镜像
docker commit #第一列容器ID centos:update
3.保存镜像
docker save centos:update > centos.tar
4.加载镜像
docker load < centos.tar



常见命令:

1,后台启动docker并且端口映射

docker run -itd -p 3390<物理机端口>:3390<容器端口> cd3c0fd5029a /bin/bash

2,进入docker

docker attach <容器ID>

3,退出docker,不关闭container

ctrl+p ctrl+q

4.更新镜像

docker commit <容器ID> centos:update<自己定义的名字:标签>

5.保存镜像

docker save centos:update > centos.tar

6.加载镜像

docker load < centos.tar

nginx proxy_cache 缓存配置

前言:
由于本人工作原因,涉及到网络直播领域,其中视频的回放下载,涉及到了一些视频下载方面的技术。针对于一个完整视频的下载,目前市面上的主流做法是,先将整个视频流切片,存储到文件服务器中,在用户需要观看回放视频时。通过一个视频回源服务器,去文件服务器中逐个请求切片,返回给用户播放。
今天着重探讨的是关于回源服务器缓存的配置以及合理的缓存策略。
通过给回源服务器配置缓存的案例,详细讲解一整套缓存配置机制,并且可沿用到其他任何缓存配置场景中。

今天的讲解分为四点:
回源服务器的工作是啥
为啥需要给回源服务器加缓存
如何配置缓存
如何针对业务场景配置完备的缓存机制

回源服务器的工作:
回源服务器在下面叙述中简称:源站
如图所示,在文件下载的过程中,横跨在cdn与文件服务器之间,作为下载枢纽。

源站架构:源站是nginx+php的webserver架构,如图所示:

但如果源站只是简单的收到请求,然后下载资源,再返回,势必会存在以下几点不够优化的问题:
1、cdn可能存在多次回源现象
2、源站对同一资源的多次下载,存在网络流量带宽浪费,以及不必要的耗时。
所以为了优化这些问题,需要给源站做一层缓存。缓存策略采用nginx自带的proxy_cache模块。

proxy_cache原理:
proxy_cache模块的工作原理如图所示:
如何配置proxy_cache模块
在nginx.conf文件中添加如下代码:
http{
……
proxy_cache_path/data/nginx/tmp-test levels=1:2 keys_zone=tmp-test:100m inactive=7d max_size=1000g;
}
代码说明:
proxy_cache_path 缓存文件路径

levels 设置缓存文件目录层次;levels=1:2 表示两级目录

keys_zone 设置缓存名字和共享内存大小

inactive 在指定时间内没人访问则被删除

max_size 最大缓存空间,如果缓存空间满,默认覆盖掉缓存时间最长的资源。

当配置好之后,重启nginx,如果不报错,则配置的proxy_cache会生效

查看  proxy_cache_path /data/nginx/目录,
会发现生成了tmp-test文件夹。

如何使用proxy_cache
在你对应的nginx vhost server配置文件中添加如下代码:
location /tmp-test/ {
proxy_cache tmp-test;
proxy_cache_valid 200 206 304 301 302 10d;
proxy_cache_key $uri;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_passhttp://127.0.0.1:8081/media_store.php/tmp-test/;
}
配置项介绍:
Proxy_cache tmp-test 使用名为tmp-test的对应缓存配置
proxy_cache_valid  200 206 304 301 302 10d; 对httpcode为200…的缓存10天

proxy_cache_key $uri  定义缓存唯一key,通过唯一key来进行hash存取

proxy_set_header  自定义http header头,用于发送给后端真实服务器。

proxy_pass  指代理后转发的路径,注意是否需要最后的/

到这里,最基本的proxy_cache功能就配置成功了。当uri成功匹配到该location,则proxy_cache就会生效。

添加proxy_cache之后,请求过程的变化:
1、第一次访问:
第一次访问,proxy_cache并没有找到对应的缓存文件(未命中缓存MISS),所以当第一次请求完成的同时,proxy_cache会保持缓存:
2、保存缓存,如图所示:

3、同一个url第二次访问,当同一个文件再次到达源站,proxy_cache就会找到其对应的缓存文件(命中缓存HIT)直接返回给请求端,无需再执行php程序,如图所示:
提出疑问:
到此,就完成了最基本的proxy_cache配置和访问过程介绍,但是最基本的配置,往往无法满足我们的业务需求,我们往往会提出以下几点疑问和需求:
需要主动清理缓存文件
写入路径为一块磁盘,如果磁盘打满该怎么解决?
如何让源站支持断点续传,以及断点续传的缓存策略
如果请求端 range 请求(分片下载)一个大资源,同样的uri,如何区别请求?
还需要告诉请求端,资源的过期时间
日志统计,如何配置命中与不命中字段,如何做统计?
面对以上疑问,我们一个一个解决。

问题一:主动清理缓存
采用:nginx  proxy_cache_purge 模块 ,该模块与proxy_cache成对出现,功能正好相反。
设计方法:在nginx中,另启一个server,当需要清理响应资源的缓存时,在本机访问这个server。
例如:
访问 127.0.0.1:8083/tmp-test/TL39ef7ea6d8e8d48e87a30c43b8f75e30.txt 即可清理该资源的缓存文件。
配置方法:
location /tmp-test/ {
allow 127.0.0.1; //只允许本机访问
deny all; //禁止其他所有ip
proxy_cache_purge tmp-test $uri; //清理缓存
}
proxy_cache_purge:缓存清理模块
tmp-test:指定的key_zone
$uri:指定的生成key的参数
proxy_cache_purge缓存清理过程,如图所示:
问题二:缓存文件强磁盘打满该怎么办?
由于写入路径为一个单一目录,只能写入一块磁盘。一块磁盘很快就会被打满,解决该问题有如下两种方法:
1、将多块磁盘做磁盘阵列? 缺点是:减小了实际的存储空间。
2、巧妙得运用proxy_cache_path的目录结构,由于levels=1:2,这导致缓存文件的目录结构为两层,每层目录名,都是由hash函数生成。如图所示:

总共含有16*16*16=4096个文件目录。对该一级目录进行软连接,分别将0-f软连接到你所需要的指定磁盘目录上,如图所示:

通过软链的方法,实现:将不同盘下的目录作为真正存放数据的路径,解决了多盘利用,单盘被打满的问题。

问题三:支持range(断点续传)
添加上缓存代理之后,客户端发起的range请求将会失效,如下图所示:

导致range参数无法传递到下一级的原因如下:
当缓存代理转发http请求到后端服务器时,http header会改变,header中的部分参数,会被取消掉。其中range参数被取消,导致,后端nginx服务器没有收到range参数,最终导致这个分片下载不成功。所以需要对代理转发的header进行配置。
例如:
location /tmp-test/ {
proxy_cache tmp-test;
proxy_cache_valid 200 206 304 301 302 10d;
proxy_cache_key $uri;
<span style=”color:#ff0000;”>proxy_set_header Range $http_range;</span>
proxy_pass http://127.0.0.1:8081/media_store.php/tmp-test/;
}
红色部分的含义:将http请求中的range值($http_range)放到代理转发的http请求头中作为参数range的值。

问题四,当支持range加载后,proxy_cache_key,则需要重新配置:
如果请求端 Range请求(分片下载)一个大资源,同样的uri,proxy cache如何识别资源对应的key。
由于nginx配置为:proxy_cache_key $uri,用uri作为key
所以当请求为普通请求和range请求时,都是同样的uri作为key。proxy_cache将有可能导致错误返回。如下图所示:

解决方法如下:
修改proxy_cache_key ,配置proxy_cache_key $http_range$uri;
这样就能解决:key唯一性。可以避免不管是正常请求还是不同的range请求,第一次获取的内容和之后获取的缓存内容都不会出现异常。

问题五:如何配置-返回过期时间
需要通过返回过期时间来指定请求端,哪些资源需要缓存,哪些资源不缓存,
参数 正常请求 range请求
返回过期时间 返回 不返回
为了防止请求端将分片资源当做完整资源缓存起来,我们需要对正常请求,返回过期时间;对range请求, 不返回过期时间。
解决该问题,通过对nginx配置即可解决:
location /media_store.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index media_store.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
include fastcgi_params;
if ( $http_range = ”){
expires 2592000s;
}
}
在proxy_pass代理之后的location中加入对$http_range的判断,expires 表示过期时间。 2592000s指缓存过期时间。

问题七:缓存命中情况如何在http头中体现,以及在nginx日志中查看
解决方法:
利用nginx $upstream_cache_status变量:该变量代表缓存命中的状态,
如果命中,为HIT;如果未命中,为MISS
在返回nginx server配置中添加:
add_header  Nginx-Cache “$upstream_cache_status”;
在nginxlog中添加:
log_format       combinedio  …$upstream_cache_status;
http返回head截图:
nginx log日志截图:
总结:
整个一套完备的缓存策略就介绍到此,这套方案中不仅实现了基本的缓存配置,还解决了实际场景应用中会遇到的,磁盘扩展,缓存清理,断点续传,缓存过期时间,缓存命中提示等问题,只要将这套方案灵活运用,不管是再复杂的场景,基本都能满足需求。以上都是我在工作中爬过的坑,不断完善总结出的结果,希望对读者能有帮助。

基于OpenResty的web开发框架Lor

https://github.com/sumory/lor

Lor是一个运行在OpenResty上的基于Lua编写的Web框架.

  • 路由采用Sinatra风格,结构清晰,易于编码和维护.
  • API借鉴了Express的思路和设计,Node.js跨界开发者可以很快上手.
  • 支持多种路由,路由可分组,路由匹配支持正则模式.
  • 支持middleware机制,可在任意路由上挂载中间件.
  • 可作为HTTP API Server,也可用于构建传统的Web应用.

文档

http://lor.sumory.com

示例项目

快速开始

特别注意: 在使用lor之前请首先确保OpenResty已安装,并将nginx/resty命令配置到环境变量中。即在命令行直接输入nginx -vresty -v能正确执行。

一个简单示例(更复杂的示例或项目模板请使用lord命令生成):

local lor = require("lor.index")
local app = lor()

app:get("/", function(req, res, next)
    res:send("hello world!")
end)

-- 路由示例: 匹配/query/123?foo=bar
app:get("/query/:id", function(req, res, next)
    local foo = req.query.foo
    local path_id = req.params.id
    res:json({
        foo = foo,
        id = path_id
    })
end)

-- 错误处理插件,可根据需要定义多个
app:erroruse(function(err, req, res, next)
    -- err是错误对象
    ngx.log(ngx.ERR, err)
    if req:is_found() ~= true then
        return res:status(404):send("sorry, not found.")
    end
    res:status(500):send("server error")
end)

app:run()

安装

1)使用脚本安装(推荐)

使用Makefile安装lor框架:

git clone https://github.com/sumory/lor
cd lor
make install

默认lor的运行时lua文件会被安装到/usr/local/lor下, 命令行工具lord被安装在/usr/local/bin下。

如果希望自定义安装目录, 可参考如下命令自定义路径:

make install LOR_HOME=/path/to/lor LORD_BIN=/path/to/lord

执行默认安装后, lor的命令行工具lord就被安装在了/usr/local/bin下, 通过which lord查看:

$ which lord
/usr/local/bin/lord

lor的运行时包安装在了指定目录下, 可通过lord path命令查看。

2)使用opm安装

opm是OpenResty即将推出的官方包管理器,从v0.2.2开始lor支持通过opm安装:

opm install sumory/lor

注意: 目前opm不支持安装命令行工具,所以此种方式安装后不能使用lord命令。

3)使用homebrew安装

除使用以上方式安装外, Mac用户还可使用homebrew来安装lor, 该方式由@syhily提供, 更详尽的使用方法请参见这里

$ brew tap syhily/lor
$ brew install lor

至此, lor框架已经安装完毕,接下来使用lord命令行工具快速开始一个项目骨架.

使用

$ lord -h
lor ${version}, a Lua web framework based on OpenResty.

Usage: lord COMMAND [OPTIONS]

Commands:
 new [name]             Create a new application
 start                  Starts the server
 stop                   Stops the server
 restart                Restart the server
 version                Show version of lor
 help                   Show help tips

执行lord new lor_demo,则会生成一个名为lor_demo的示例项目,然后执行:

cd lor_demo
lord start

之后访问http://localhost:8888/, 即可。

更多使用方法,请参考use cases测试用例。

Mycat【数据库方式】实现全局序列号

说明:本文参考mycat官方提供的文档,结合自己的实践以及理解,做出如下整理,并附带一个分库分表的插入数据例子。
原理
在数据库中建立一张表,存放sequence名称(name),sequence当前值(current_value),步长(increment int类型每次读取多少个sequence,假设为K)等信息;
Sequence获取步骤:
1)当初次使用该sequence时,根据传入的sequence名称,从数据库这张表中读取current_value,和increment到MyCat中,并将数据库中的current_value设置为原current_value值+increment值;
2)MyCat将读取到current_value+increment作为本次要使用的sequence值,下次使用时,自动加1,当使用increment次后,执行步骤1)相同的操作.
3)MyCat负责维护这张表,用到哪些sequence,只需要在这张表中插入一条记录即可。若某次读取的sequence没有用完,系统就停掉了,则这次读取的sequence剩余值不会再使用。
配置方式
server.xml配置:

<system><property name=”sequnceHandlerType”>1</property></system>
1
注:sequnceHandlerType 需要配置为1,表示使用数据库方式生成sequence.
数据库配置:
1)创建sequence表

CREATE TABLE MYCAT_SEQUENCE (
name VARCHAR (50) NOT NULL comment “名称”,
current_value INT NOT NULL comment “当前值”,
increment INT NOT NULL DEFAULT 100 comment “步长”,
PRIMARY KEY (name)
) ENGINE = INNODB;
1
2
3
4
5
6
2)创建相关function

#取当前squence的值
DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER $$
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50))RETURNS VARCHAR(64) CHARSET ‘utf8′
BEGIN
DECLARE retval VARCHAR(64);
SET retval=’-999999999,NULL’;
SELECT CONCAT(CAST(current_value AS CHAR),’,’,CAST(increment AS CHAR)) INTO retval FROM
MYCAT_SEQUENCE WHERE NAME = seq_name;
RETURN retval;
END$$
DELIMITER ;

#设置 sequence 值
DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64) CHARSET ‘utf8’
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END$$
DELIMITER ;

#取下一个sequence的值
DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) CHARSET ‘utf8′
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END$$
DELIMITER ;
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
3)sequence_db_conf.properties相关配置,指定sequence相关配置在哪个节点上:
例如:

COMPANY=dn3
1
注:COMPANY为表名,必须大写,dn3为schema.xml配置的dataNode节点。建议专门独立一个数据库,存放sequence表和相关的function,方便维护管理和隔离。

注意:MYCAT_SEQUENCE表和以上的3个function,需要放在同一个节点上。function请直接在具体节点的数据库上执行,如果执行的时候报:
you might want to use the less safe log_bin_trust_function_creators variable
需要对数据库做如下设置:
windows下my.ini[mysqld]加上log_bin_trust_function_creators=1
linux下/etc/my.cnf下my.ini[mysqld]加上log_bin_trust_function_creators=1
修改完后,即可在mysql数据库中执行上面的函数.
使用示例:

SELECT next value for MYCATSEQ_SAM_TEST
insert into sam_test(id_,name_) values(next value for MYCATSEQ_SAM_TEST,’test’);
# 数据库表定义了自增,在mycat也定义了主键和自增,可以用如下方式
insert into sam_test(name_) values(‘test’);
1
2
3
4
测试
1.配置schema.xml

<schema name=”TESTDB” checkSQLschema=”false” sqlMaxLimit=”100″>
<table name=”company” dataNode=”dn1,dn2″ rule=”companyRule” primaryKey=”id” autoIncrement=”true” />
</schema>

<dataNode name=”dn1″ dataHost=”localhost1″ database=”mycat_test” />
<dataNode name=”dn2″ dataHost=”localhost1″ database=”mycat_test2″ />
<dataNode name=”dn3″ dataHost=”localhost2″ database=”testmycat” />

<dataHost name=”localhost1″ maxCon=”1000″ minCon=”10″ balance=”0″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″ slaveThreshold=”100″>
<heartbeat>select user()</heartbeat>
<writeHost host=”hostM1″ url=”192.168.1.95:3306″ user=”admin” password=”admin”/>
<writeHost host=”hostM2″ url=”192.138.1.112:3306″ user=”root” password=”root”/>
</dataHost>
<!– 存放sequence数据库 –>
<dataHost name=”localhost2″ maxCon=”1000″ minCon=”10″ balance=”0″
writeType=”0″ dbType=”mysql” dbDriver=”native” switchType=”1″ slaveThreshold=”100″>
<heartbeat>select user()</heartbeat>
<writeHost host=”localhost2M2″ url=”192.138.1.112:3306″ user=”root” password=”root”/>
</dataHost>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2.配置server.xml

<property name=”sequnceHandlerType”>1</property><!– 1:使用数据库方式生成sequence –>
1
3.配置rule.xml

<tableRule name=”companyRule”>
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name=”mod-long” class=”org.opencloudb.route.function.PartitionByMod”>
<!– how many data nodes –>
<property name=”count”>2</property>
</function>
1
2
3
4
5
6
7
8
9
10
4.配置sequence_db_conf.properties

COMPANY=dn3
1
5.数据库配置文件修改my.ini

log_bin_trust_function_creators=1
# 忽略大小写
lower_case_table_names=1
1
2
3
6.数据库表
1)分别到192.168.1.95的mycat_test数据库和mycat_test2数据库新建如下的表,由于是分库分表,所以两边都要创建。

DROP TABLE IF EXISTS `company`;
CREATE TABLE `company` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1
2
3
4
5
6
注:只有数据库和mycat都设置AUTO_INCREMENT才能通过mycat命令LAST_INSERT_ID()获取插入的id
2)到192.168.1.112的testmycat数据库中执行上面的创建sequence和function过程。
3)插入数据到MYCAT_SEQUENCE表

insert into MYCAT_SEQUENCE(name,current_value,increment) values(‘COMPANY’,19,5);
1
7.mycat测试
配置完之后,重启mycat
执行

insert into company(id,name) values (next value for MYCATSEQ_COMPANY,”test”)

insert into company(name) values (“test”)
1
2
3
插入数据成功后
执行

select LAST_INSERT_ID()
1
可以看到本次插入的id

小结
如果要获取插入数据后的id,必须同时在mysql和mycat设置表的自增。
sequence_db_conf.properties配置的表名必须大写。
存放sequence表和function在同一个数据库中,且只有一个。
以上【Sequence获取步骤】是mycat原理,注意理解。
———————
作者:黄晓杰Aries
来源:CSDN
原文:https://blog.csdn.net/u010956470/article/details/70837876
版权声明:本文为博主原创文章,转载请附上博文链接!

PSSH 批量管理服务器

pssh命令是一个python编写可以在多台服务器上执行命令的工具,同时支持拷贝文件,是同类工具中很出色的,类似pdsh,个人认为相对pdsh更为简便,使用必须在各个服务器上配置好密钥认证访问。

1. 安装

安装可以使用yum或者apt-get安装,还可以使用源码安装, 由于我使用apt-get安装不好用,所以这里我只说下源码安装

wget http://parallel-ssh.googlecode.com/files/pssh-2.3.1.tar.gz 
tar xf pssh-2.3.1.tar.gz 
cd pssh-2.3.1/ 
python setup.py install

2. pssh选项说明

复制代码
--version:查看版本 
--help:查看帮助,即此信息 
-h:主机文件列表,内容格式”[user@]host[:port]” 
-H:主机字符串,内容格式”[user@]host[:port]” 
-:登录使用的用户名 
-p:并发的线程数【可选】 
-o:输出的文件目录【可选】 
-e:错误输入文件【可选】 
-t:TIMEOUT 超时时间设置,0无限制【可选】 
-O:SSH的选项 
-v:详细模式 
-A:手动输入密码模式 
-x:额外的命令行参数使用空白符号,引号,反斜线处理 
-X:额外的命令行参数,单个参数模式,同-x 
-i:每个服务器内部处理信息输出 
-P:打印出服务器返回信息
复制代码

 

3. 实例

(1) 查看版本

#pssh --version
#2.3.1

(2) 查看帮助

复制代码
#pssh --help
Usage: pssh [OPTIONS] command [...]

Options:
  --version             show program's version number and exit
  --help                show this help message and exit
  -h HOST_FILE, --hosts=HOST_FILE
                        hosts file (each line "[user@]host[:port]")
  -H HOST_STRING, --host=HOST_STRING
                        additional host entries ("[user@]host[:port]")
  -l USER, --user=USER  username (OPTIONAL)
  -p PAR, --par=PAR     max number of parallel threads (OPTIONAL)
  -o OUTDIR, --outdir=OUTDIR
                        output directory for stdout files (OPTIONAL)
  -e ERRDIR, --errdir=ERRDIR
                        output directory for stderr files (OPTIONAL)
  -t TIMEOUT, --timeout=TIMEOUT
                        timeout (secs) (0 = no timeout) per host (OPTIONAL)
  -O OPTION, --option=OPTION
                        SSH option (OPTIONAL)
  -v, --verbose         turn on warning and diagnostic messages (OPTIONAL)
  -A, --askpass         Ask for a password (OPTIONAL)
  -x ARGS, --extra-args=ARGS
                        Extra command-line arguments, with processing for
                        spaces, quotes, and backslashes
  -X ARG, --extra-arg=ARG
                        Extra command-line argument
  -i, --inline          inline aggregated output and error for each server
  --inline-stdout       inline standard output for each server
  -I, --send-input      read from standard input and send as input to ssh
  -P, --print           print output as we get it

Example: pssh -h hosts.txt -l irb2 -o /tmp/foo uptime
复制代码

(3) 使用主机文件列表执行pwd命令

复制代码
#pssh -h ip.txt -A -i pwd
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 19:58:51 [SUCCESS] root@192.168.200.152
/root
[2] 19:58:51 [SUCCESS] root@192.168.200.154
/root
[3] 19:58:51 [SUCCESS] root@192.168.200.153
/root
[4] 19:58:52 [SUCCESS] root@192.168.200.155
/root
复制代码

说明: -h 后面的ip是要操作的机器ip列表,格式如下: root@192.168.200.152   -A 表示手动输入密码模式  -i表示要执行的命令

(4) 使用主机文件列表执行date命令

 

复制代码
#pssh -h ip.txt -A -i date
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 20:13:36 [SUCCESS] root@192.168.200.152
2016年 07月 11日 星期一 20:10:24 CST
[2] 20:13:36 [SUCCESS] root@192.168.200.154
2016年 07月 11日 星期一 20:10:11 CST
[3] 20:13:36 [SUCCESS] root@192.168.200.153
2016年 07月 11日 星期一 20:10:56 CST
[4] 20:13:36 [SUCCESS] root@192.168.200.155
2016年 07月 11日 星期一 20:10:10 CST
复制代码

 

(5) 指定用户名

复制代码
#可以通过-l命令指定用户名
$pssh -h ip.txt -A -i -l root date
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password: 
[1] 20:13:36 [SUCCESS] 192.168.200.152
2016年 07月 11日 星期一 20:10:24 CST
[2] 20:13:36 [SUCCESS] 192.168.200.154
2016年 07月 11日 星期一 20:10:11 CST
[3] 20:13:36 [SUCCESS] 192.168.200.153
2016年 07月 11日 星期一 20:10:56 CST
[4] 20:13:36 [SUCCESS] 192.168.200.155
2016年 07月 11日 星期一 20:10:10 CST
复制代码

 

(6) 批量初始化服务器key

#让远程服务自动在/root/.ssh生成秘钥,方便部署证书信任
pssh -h host1.txt -l root -A "ssh-keygen -t rsa -f /root/.ssh/id_rsa -P \"\""

 

(7)批量修改机器密码

pssh -h host.txt -l root -A 'echo root:xxxxxxxx | chpasswd'

 

 

 

4. 介绍软件包内其他命令

     pscp   传输文件到多个hosts,他的特性和scp差不多
# 通过pscp对多个机器传文件,把test.sh传送到多个机器上
$ pscp.pssh -h host.txt -l root -A test.sh  

使用pscp对多个机器传文件,然后再通过pssh执行脚本,方便快捷

 

    pslurp   从多台远程机器拷贝文件
    pnuke    kill远程机器的进程

通过上面我们可以看到直接可以远程执行命令,对于机器的批量操作很方便。 大家使用的时候可以根据自己的实际需求编写相应的脚本

这里就简单写这几个例子。