HackToday Walk Blog


  • Home

  • Tags

  • Archives

  • Search

无服务器 - Serverless 入门知识

Posted on 2018-02-25

Serverless 这个单词最早大约来源于Ken Form 的一篇文章中, 不过并不是今天我们要讨论的这个意思,如今的含义是无服务器,主要是指让开发人员专注于业务代码的本身逻辑上,无需关注代码部署的资源、维护、扩展性和高可用性,减少代码开发人员的业务无关的工作量,提高开发效率,具有无状态运行,基于事件触发,按需付费,运维完全托管到第三方等特点。

Read more »

故障分析平台 Sentry 的 LDAP 集成搭建

Posted on 2017-12-21

sentry 是一个支持软件系统故障信息报告和聚集的平台,可以扩平台的部署和管理故障信息,不同于传统的 ELK 日志分析平台,sentry 更加专注对于故障和异常类信息的处理,减少无关消息的干扰,实时的汇集和报告软件系统的潜在问题,帮助开发和管理人员迅速的解决问题。

sentry 本身提供了扩展点,方便第三方来实现相关的系统集成,以 LDAP 为例,sentry-ldap-auth 是一个 django 定制化实现,支持 LDAP, 具体的配置在 github 介绍中比较简陋,所以用户在配置中容易出现各类奇怪的问题,所以,今天我们以一个系统为例,说说 LDAP 相关的配置。

Read more »

tcpdump 调试 TCP 连接超时问题

Posted on 2017-12-15

问题简单描述: 服务端负载均衡 4 层有超时配置,如果没有数据交互,那么 tcp 连接会断开。

为了支持可定制化配置,需要验证超时生效的问题,于是我做了一个简单的 Flask app 的镜像(启动在8083 端口, 120 秒返回结果),启动后,
使用 curl http://ip:8083 发现, 过了超时时间后,服务端仍然完整了返回了结果。

调查:这种问题,一般用 tcpdump 跟踪一下就容易解决。

Read more »

解决 Nginx 502 Bad Gateway 问题

Posted on 2017-11-29

今天访问镜像页面的时候发现时不时的出现 502 这个奇怪的错误,感觉是个值得研究的性能相关的问题,
尤其是大量镜像访问的时候出现的频率加大,于是撸起袖子准备搞起。

环境: Nginx + gunicorn + Web App

解决思路:

Read more »

大话容器标准-OCI CNCF

Posted on 2017-10-29

这是以前写的文章,一直没有分享出来,一方面觉得业界还在不停的变化,另一方面还在忙别的事情,随着前些日子,docker 官方原生支持 Kubernetes 的部署,我觉得回过头来看看以前自己写的这篇文章还是很有意思的事情。

OCI 2015年6月建议,发起者主要是 docker 公司还有容器行业的其他的公司。最初主要是解决容器运行标准化的问题,后来扩展包括了对于容器镜像标准的问题的涵盖。

目前主要包含以下标准:
http://www.github.com/opencontainers/runtime-spec
http://www.github.com/opencontainers/image-spec

主要的流程是,从镜像源下载 OCI 镜像,解压符合 OCI 运行时的文件系统 Bundle,然后由 OCI Runtime 运行(例如runc)
不难看出,上面 OCI的使命主要是解决底层容器运行相关容器打包标准化和运行环境规范,实现容器镜像的跨云,平台的即插即用。

Read more »

相同的 pip 命令 --trusted-host 错误消息不一致

Posted on 2017-10-25

问题:
最近部署系统的时候,发现 ansible 执行同样的 pip 安装命令,结果不一样,一台正常,一台报错 –trusted-host 没有设置。

原因:
简单的调查发现,其中的 pip 版本不一致,一个没有涉及到 –trusted-host, 另外的新版的 pip 支持了 –trusted-host

修复:
简单的方法是,将其中支持 –trusted-host 配置到 pip.conf 文件中

Kubernetes 的 CRI-O 1.0 版本发布

Posted on 2017-10-18

CRI-O 的源头:

Kubernetes 作为编排领域的巨头,一直也是在标准化兼容的路上一路前行,为了支持多种的容器运行时系统(Docker, Rkt) 等,减少集成维护的成本,开发了自身的 CRI 接口规范,由于事实上的 OCI 已经被多方厂商认可,所以 CRI 和 OCI 的桥接也是自然的事情,CRI-O 这个项目来源也就是如此。

CRI-O 的内部窥探:(下面的图片来源于 https://www.redhat.com/en/blog/introducing-cri-o-10)

CRI-O 项目也特别声明了自身的定位: 只是用于 Kubernetes 用来管理和运行 OCI 标准兼容的容器,也不是面向开发人员的,或者用来打包镜像的。

差不多另外一天, docker 官方也公布了自身的对于 kubernetes 的编排的原生支持,Docker 社区版和企业版都可以使用 docker 官方的类似 compose 工具来部署维护 Kubernetes 的pods 和 services 等。

参考文献:

  1. https://blog.docker.com/2017/10/kubernetes-docker-platform-and-moby-project/
  2. https://www.redhat.com/en/blog/introducing-cri-o-10

python 相同的 url 下载行为不一致调查 (Tornado)

Posted on 2017-08-24

前几天遇到一个神奇的问题,同样的一个 url,在浏览器访问这些远端的机器时,会出现不同的行为:直接下载或是打开。为什么行为不一致呢? 很奇怪。

没有很好的办法,只能从 debug 浏览器的 request 请求开始,发现一台机器是 application/octet-strea,另外一台是 text/plain
同样的 url 在不同的机器上有这个奇怪的表现,不多说了,肯定是 tornado web 中的一些代码逻辑导致的,于是决定翻源码。
https://github.com/python/cpython/blob/master/Lib/mimetypes.py
https://github.com/tornadoweb/tornado/blob/branch4.3/tornado/web.py

定位到决定 content 内容的源码如下:
点击(此处)折叠或打开

1
2
3
4
5
6
7
8
9
10
11
12
13
def get_content_type(self):

"""Returns the ``Content-Type`` header to be used for this request.



.. versionadded:: 3.1

"""

mime_type, encoding = mimetypes.guess_type(self.absolute_path)

# per RFC 6713, use the appropriate type for a gzip compressed file

mimetypes.py 中会根据不同的文件扩展类型来推测 mime_type ,一台机器是 application/octet-strea,另外一台是 text/plain
这就奇怪了,同样的操作系统和 tornadoweb 版本

再细看 mimetypes.py 源码发现,里面有一些蹊跷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
knownfiles = [

"/etc/mime.types",

"/etc/httpd/mime.types", # Mac OS X

"/etc/httpd/conf/mime.types", # Apache

"/etc/apache/mime.types", # Apache 1

"/etc/apache2/mime.types", # Apache 2

"/usr/local/etc/httpd/conf/mime.types",

"/usr/local/lib/netscape/mime.types",

"/usr/local/etc/httpd/conf/mime.types", # Apache 1.2

"/usr/local/etc/mime.types", # Apache 1.3

]

其中 /etc/mime.types 一台机器上没有,另外一台包含, 这个文件中包含了 .log 结尾的文件情况,那么看看是哪个包导致的不同:

1
2
# rpm -q --whatprovides /etc/mime.types
mailcap-xxx-.el7.noarch

后来确认才知道,一台机器当时使用的最小化安装,所以遗漏了一些后期的标准化安装的包。这个差别才导致了行为的差异。

Python 的性能分析利器——Django 篇

Posted on 2017-08-23

1) django debug_toolbar 这个插件可以使用,按照官方文档配置,https://django-debug-toolbar.readthedocs.io/en/stable/installation.html
但是最主要的一点是需要配置 INTERNAL_IPS ,对于这个是需要特别注意的,假设你是使用远程调试,这个时候需要把你的客户端的 ip 加入进去,这样启动的时候,就能看到 debug panel 了,否则就会不能显示出来,这个问题也是困扰我了半天,推荐一般 debug panel 不能正常显示的时候,查看这个是否正确设置。

特点,jazzband 开发, 可以看到相应页面的 sql query 数量 和 相应的时间,还有浏览器渲染等。

2)silk 也是 jazzband 开发,针对 django,配置更加简单,除了包含上面的一些统计数据,同时可以针对某块代码,进行 profiling。

3)python 自身标准库的profiler 支持,统计的数据,可以使用 pstats 模块进行格式化输出

3.1 cprofile: 基于 lsprof 模块, 以 C 扩展的方式实现,相对开销较小,可以针对对应的代码进行 profile
3.2 profile: python 的实现,接口和 cprofile 一致,开销较大,不过第三方开发基于此较容易

3.1 和 3.2 分别有接口 enable disable 对某块代码进行 profile,设置对应的是否对 built-in 进行 profile

以 cprofile 为例,输出的内容每列信息如下:

ncalls — for the number of calls,
tottime — for the total time spent in the given function (and excluding time made in calls to sub-functions)
percall — is the quotient of tottime divided by ncalls
cumtime — is the cumulative time spent in this and all subfunctions (from invocation till exit). This figure is accurate even for recursive functions.
percall — is the quotient of cumtime divided by primitive calls
filename:lineno(function) — provides the respective data of each function

类似如下图:

相对的统计信息比较繁多,包含了很多 built-in

3.3 hotshot: (不再维护的)的方式, 进行代码级别的profile, 类似 https://code.djangoproject.com/wiki/ProfilingDjango 示例1

Scrapy 爬取 Blog 网页内容到 MD 文件

Posted on 2017-08-04

传统的 Blog 网站,没有提供完善的 md 格式支持,所以书写的 Blog 文件往往不具有 export 其他格式的功能。
以我自己的 Blog 为例,这里书写的都是按照网站的 Blog 样式进行转化都是 html 页面,如果要转化对应的 md 格式,需要提取相应的标题,文本主体和其他相应的格式处理。

目标清楚了,我们首先想到的是使用爬虫工具来快速的处理的这个事情,下面 scrapy 就隆重登场了。

scrapy 作为一个开源实现的基于 python 爬虫框架,它内部的架构图具体如下:

主要包括: 爬虫引擎、调度器、下载器、具体爬虫、Item 流水线、下载器中间件和爬虫中间件
具体作用分别如下:

引擎:控制中枢,系统核心数据流的具体流动,并且相应动作发生时触发事件
调度器:接受引擎的request 输入,队列处理,再需要时提供给引擎
下载器:获取实际的web 页面,并返回给引擎,最终到具体的爬虫
爬虫:根据获取的页面,进行实际的解析处理,提取 item
Item 流水线:处理爬虫获取的 item,比如清理,验证和持久化
下载器中间件:下载器和引擎之间的中介,处理下载器返回给引擎的 response
爬虫中间件:处理爬虫的输入(response),和输出(items,requests)

下面我们一个实际的例子来说明如何使用:
创建项目非常简单,类似 django 封装的效果。

1
scrapy startproject tutorial

项目创建完成后,就是具体的爬虫的编写了,以我的博客首页为例: http://blog.chinaunix.net/uid/21335514/

我们需要根据上述的 URL 依次按照 年份 –》 标题 –》 内容就行爬取,存储使用简单的 json 文件格式,根据存储的 json 文件格式,就行简化的 md 格式转换。

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
class UnixBlogSpider(scrapy.Spider):
name = 'unixblogtaker'
start_urls = ['http://blog.chinaunix.net/uid/21335514']

def parse(self, response):
for year in response.css('p.Blog_p4 > span'):
if year.css('.Blog_jia1') is None:
continue
blog_page = year.css('span + a::attr(href)').extract_first()
if blog_page:
yield response.follow(blog_page, callback=self.parse_title)

def parse_title(self, response):
for blog_summary in response.css('div.Blog_tit4 > b'):
if blog_summary.css('.Blog_b1') is None:
continue
b_content = blog_summary.css('b + a::attr(href)').extract_first()
if b_content:
yield response.follow(b_content, callback=self.parse_content)
next_page = response.css('li.next a::attr(href)').extract_first()
if next_page is not None:
yield response.follow(next_page, self.parse_title)

def parse_content(self, response):
......

parse_content 这里处理的时候,可能需要根据一些特殊的字符含义进行相应的转化,以为后续的 md 简化转化提供便利。

运行 scrapy crawl unixblogtaker -o blog.json 就生成了我们的 json 文件

简单的处理上述的 content,(simplemr_tool.py 中的一部分)

1
2
3
def raw_save(content, title):
with open(title, 'w') as new_file:
new_file.write(re.sub('(\r\n\r\n)+', '\r\n\r\n', content).encode('utf-8'))

然后执行 python simplemr_tool.py blog.json 就会生成一系列的 md 博客了。

参考:
https://doc.scrapy.org/en/latest/intro/tutorial.html#creating-a-project
http://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/architecture.html

123…26

Kai Qiang Wu

This is a place for thinking and writing

253 posts
32 tags
GitHub
© 2020 Kai Qiang Wu
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4
Visitor Total Visit