生产环境中使用Docker Swarm的条款


【编者的话】实践中会发现,生产环境中使用单个Docker节点是远远不够的,搭建Docker集群势在必行。然而,面对Kubernetes,Mesos以及Swarm等众多容器集群系统,我们该如何选择呢?它们之中,Swarm是Docker原生的,同时也是最简单,最易学,最节省资源的,至少值得我们多了解一下。本文将介绍一些非常实用的建议。

【深圳站|3天烧脑式Kubernetes训练营】培训内容包括:Kubernetes概述、架构、日志和监控,部署、自动驾驶、服务发现、网络方案等核心机制分析,进阶篇——Kubernetes调度工作原理、资源管理及源码分析等。

如果你在单个生产节点上用过Docker,然后发现单个节点的资源不够用,那么你会怎么做呢?我也遇到过这种情况! 关于在生产环境中使用Docker Swarm,我会为你提供一些建议,也许能够帮到你。这些都是我一年来积累的一些经验。

另外,如果你对Docker Swam不熟悉的话,可以参考我之前的博客My experience with Docker Swarm – when you may need it?

1. 阅读官方文档

我并不打算重复官方文档。尽管文档非常短,但是通过它可以了解Swarm的基本知识。另外,我也不会写如何搭建Swarm集群,这方面的资料太多了,你可以查看 Digital Ocean或者自己谷歌。PS:我是使用Ansible搭建Swarm集群的。

2. Docker Swarm要点

Swarm的负载非常低。据我观察,Swarm进行调度和通信的CPU负载非常低。因此,Swarm的管理节点(Manager)可以同时作为工作节点(Worker)。如果你需要搭建一个非常大的集群(1000+ 节点),管理节点需要更多资源,但是对于中小型集群来说,管理节点需要的资源可以忽略不计。另外,这篇博客介绍了Swarm3k(一个4700节点的Swarm集群的实验),不妨了解一下。

Swarm集群的网络通信(服务发现,负载均衡以及容器间通信)非常可靠。当你开启一个服务的端口之后,在Swarm集群中的任何一个节点都可以访问它。负载均衡也是由Swarm提供的。后文会提到一些之前遇到的问题,但是Docker 1.13之后,这些问题都解决了。

使用Swarm只需要掌握少量命令。下面是我每天需要用到的所有命令:

bash

创建服务

docker service create \  
--image nginx \
--replicas 2 \
nginx 

更新服务

docker service update \  
--image nginx:alpine \
nginx 

删除服务

docker service rm nginx

减少服务实例(这比直接删除服务要好)

docker service scale nginx=0

增加服务实例

docker service scale nginx=5

查看所有服务

docker service ls

查看服务的容器状态

docker service ps nginx

查看服务的详细信息。

docker service inspect nginx  

实现零宕机部署也非常简单。这样也可以方便地实现持续部署:

bash

构建新镜像

docker build -t hub.docker.com/image . 

将新镜像上传到Docker仓库

docker push hub.docker.com/image

更新服务的镜像

docker service update --image hub.docker.com/image service  

Swarm非常容易入门。分布式系统通常是非常复杂的。与其他容器集群系统(Mesos、Kubernetes)相比,Swarm的学习曲线最低。在没有任何Swarm知识的情况下,我只花了一周时间,就把服务从单个Docker主机迁移到20个节点的Docker集群上。

更新服务要慎重。 你的容器同时运行在多个主机上。更新服务时,只需要更新Docker镜像。合理的测试和部署流程是保证成功的关键。

3. 决定哪些容器部署在Swarm集群

并非所有服务都应该部署在Swarm集群内。数据库以及其他有状态服务就不适合部署在Swarm集群内。理论上,你可以通过使用labels将容器部署到特定节点上,但是这样的话,Swarm集群外的节点就很难访问它们了(Docker 1.12没有很好的方法,但是1.13之后可以使用attachable network)。如果你允许集群外的节点访问数据库,则所有节点都可以访问它,这显然不符合你的需求。另外,Docker Swarm的跨节点数据卷(cross-host mounted volumes)并不可靠,一个简单的文件上传都可能引起问题。

无状态的容器就非常适合部署在Swarm集群中,它们可以由环境变量进行配置(使用ENV指令)。建议为开源工具构建镜像,例如,可以将Nginx的配置文件放到Docker镜像中。

下面是我部署在Swarm集群中的服务:

  • Django channels(网页应用)
  • Nginx(代理)
  • Celery(周期性任务)
  • Sensu(监控)

下面是我部署在Swarm集群之外的容器:

  • Postgres(数据库)
  • Redis(缓存)

由于一个获取真正IP的问题,我很可能会将Nginx运行在Swarm集群之外,或者采用host模式。

4. 配置Docker仓库

Docker仓库,你值得拥有!你可以自己搭建一个,或者使用Docker仓库服务,比如DockerHub或者GitLab Container Registry。不要在服务器上直接构建Docker镜像,因为你有多个节点(在每个节点上构建镜像非常麻烦),而且在创建服务的时候你需要指定镜像(这个镜像所有节点都应该可以下载)。如果你配置了私有Docker仓库,则需要指定--with-registry-auth,否则这些节点将无法下载镜像。

另外,你应该为Docker镜像设置版本,这样更加易于回滚。

5. 将半无状态的服务变得完全无状态

所谓半无状态服务,就是容器需要依赖一些不太重要的外部文件。你可以使用数据卷(volume),但是更好的选择是使用S3或者其他云存储服务。记住,想要获得扩展性,云是最好的选择。

例如,我不得不构建Nginx镜像,将配置文件放到镜像中。使用数据卷挂载Nginx配置文件不是很方便。

6. 配置日志收集服务

使用分布式系统时,集中管理日志是非常必要的。我们有很多方案,包括开源工具或者SaaS服务,比如ELK,Grafana, Graylog…自己搭建完整的系统是非常复杂的,所以我建议搭建先使用SaaS服务(比如Loggly, Logentries ),当费用太高时,则自己搭建一个系统。ELK可以这样配置:

bash
docker service update \  
--log-driver gelf \
--log-opt gelf-address=udp://monitoring.example.com:12201 \
--log-opt tag=example-tag \
example-service

7. 创建attachable network

attachable network是一个非常重要的特性。你最好使用它,否则docker run创建的容器将无法接入Swarm集群的网络。这是Docker 1.13之后的版本才有的功能,也许你需要升级。

创建attachable network的命令如下:

bash
docker network create --driver=overlay --attachable core  

8. 先使用环境变量,再考虑Secrets API

如果你按照How to write excellent Dockerfiles构建Docker镜像,你很可能会使用环境变量去配置很多东西。如果你这样做的话,则迁移到Swarm集群时问题会少很多。示例命令如下:

bash

创建服务时指定环境变量

docker service create \  
--env VAR=VALUE \
--env-file FILENAME \
...

增加、删除环境变量

docker service update \  
--env-add VAR=NEW_VALUE \
--env-rm VAR \
..

下一步是使用Secrets API 。简单地说,你可以将私密数据(比如密码,SSL证书等)以文件的形式挂载到容器中。虽然我还没有用过Secrets API,但是我觉得值得尝试一下。

9. 设置合理的服务容器个数以及并行更新的容器个数

一方面,你需要保证足够多的容器数来处理负载以及作为灾备,另一方面,太多的容器会导致CPU和内存资源不足。因此,你需要配置合理的服务容器个数,也就是说,某个服务,需要运行合理个数的容器。

另外,默认的update-parallelism 值是1,这就意味着更新服务时,每次只更新1个容器。通常,这个值太小了。我的建议是将它设为 服务容器数 / 2.。

相关命令

bash

将同时更新的容器数设为10

docker service update \  
--update-parallelism 10 \
webapp

同时增加多个服务的容器数

docker service scale redis=1 nginx=4 webapp=20

查看服务状态

docker service ls

查看服务的详情(排除关闭的容器)

docker service ps webapp | grep -v "Shutdown"  

10. 将Swarm配置代码化

最佳方式是使用Docker Compose v3 语法,这样可以将服务的所有配置选项代码化。我将 docker-compose.yml用于开发环境, docker-compose.prod.yml用于生产环境。使用docker-compose文件部署服务的话,需要使用 docker stack deploy 命令(参考docker stack

docker-compose文件示例

# docker-compose.prod.yml
version: '3'  
services:  
webapp:
image: registry.example.com/webapp
networks:
  - ingress
deploy:
  replicas: ${WEBAPP_REPLICAS}
  mode: replicated
  restart_policy:
    condition: on-failure

proxy:
image: registry.example.com/webapp-nginx-proxy
networks:
  - ingress
ports:
  - 80:80
  - 443:443
deploy:
  replicas: ${NGINX_REPLICAS}
  mode: replicated
  restart_policy:
    condition: on-failure

networks:  
ingress:
external: true

部署命令:

export NGINX_REPLICAS=2 WEBAPP_REPLICAS=5

docker login registry.example.com  
docker stack deploy \  
-c docker-compose.prod.yml\
--with-registry-auth \
frontend

另外,docker-compse文件支持环境变量(${VARIABLE}),这样你可以动态地调整配置。

11. 设置资源限制

根据我的经验,你需要限制所有服务的CPU使用。这样可以防止单个容器占用主机的所有的CPU资源。

reserve-cpu 选项也非常有用。当我希望平均地将所有容器部署到各个主机时,我会使用reserve-cpu ,它可以保证每个容器都有足够地资源。示例:

bash

限制服务占用的CPU资源

docker service update  
--limit-cpu 0.25
--reserve-cpu 0.1
webapp

12. 监控网络连接

我遇到过Swarm网络方面的问题。有时候所有的请求都被转发到某一个容器,然而还有9个其他容器正在运行。这时,可以尝试减少/增加实例个数,或者改变路由类型(使用--endpoint-mode选项)。

如果没有监控日志的话,这样的问题很难被发现。因此,搭建监控系统是非常必要的。

欢迎加入我们FundebugDocker技术交流群: 305097057

原文链接:Tips for using Docker Swarm mode in production(译者: Fundebug

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习

在Rancher上运行Elasticsearch 最佳实践


Elasticsearch是当前最流行的大数据集分析平台之一,对于日志聚合、商业智能以及机器学习等各类用例而言,Elasticsearch都是一个很有用的工具。Elasticsearch基于 REST的简单的API,使得创建索引、添加数据和进行复杂的查询变得非常简单,这也是它大受欢迎的一大原因。但是,在你开始构建数据集和运行查询之前,您需要设置一个Elasticsearch集群,这可能会有点难。现在我们来看看Rancher Catalog是如何让配置一个可扩展、高可用的Elasticsearch集群变容易的。

假设你已经有一个运行中的Rancher集群,那么让Elasticsearch在你的集群上运行起来非常简单 。只要通过顶部菜单打开 Catalog,然后搜索Elasticsearch。Elasticsearch条目有两个版本,我们假设你使用的是2.x,这是最新的稳定版本。要从集群启动stack,请选择查看详细信息(View Detail),然后在后续屏幕中选择stack名称( Stack Name),集群名称(Cluster Name),然后选择启动。

这里写图片描述

这个stack会启动以下服务:kopf、client(s)、datanode(s) 和master(s)。kopf容器提供了web界面,用来管理你的elasticsearch 集群。Datanodes储存实际的索引。主节点运行集群管理任务,客户端节点发起和协调你的搜索和其他操作。开始时,你的Elasticsearch集群各种类型的容器都只有一个(master、client、datanodes有两个辅助容器)。但是,您可以根据查询负载和索引的大小扩展每个组件。请注意,你需要不同的物理主机才能使每个datanode容器正常工作。因此,您可能需要注册更多Rancher计算节点。

这里写图片描述

当所有容器都处于active状态时,您就可以到运行着kopf容器的主机中,启动kopf界面。点击 nodes选项卡,就会看到我之前提过的各种组件。如你所见,为了为我的索引提供冗余存储,我启动了第二个数据节点。我们将很快看到,当创建索引时,我们可以控制数据片的数量和每个片的备份。这样不仅可以提供冗余,还可以提升查询处理的速度。

这里写图片描述

在kopf的顶部的菜单中,选择更多(more),然后选择创建索引(create index)。在之后的页面中,你会被要求输入索引名称(Index Name),分片数(Number of Shards)和副本数(Number of replicas)。默认值为5个分片和1个副本。为索引设置的分片数和副本数高度依赖于数据集和查询模型。shard数有助于将数据扩展到多个节点,并且并行处理查询。如果你只有一个datanote,多分片可能看不到很多好处。此外,如果你期望数据快速增长,你可能需要更多分片,以便于你稍后添加节点并将数据移动到这些分片上。另外要注意的一点是,Elasticsearch建议最大的堆大小为32GB,所以最大的分片大小应该约为该大小,以便它可以尽可能地保存在内存中。

另一方面,副本与数据大小不太相关,它与冗余和性能的关系更紧密。所有对索引的查询都需要查看每个分片的一个副本,如果一个分片有多个副本,当一个节点不可用时,数据也依然可用。此外,使用多个副本,对指定分片的查询负载会分散在多个节点间。多个副本只有在集群中具有多个数据容器或节点时才有意义,而且在扩展越来越大的集群时会变得更加重要。

举例来说,我们来定义一个叫movies的索引,给它设置2个分片和2个副本。现在从顶部菜单中选择Rest选项卡,以便我们向索引中添加一些文档并测试一些查询。Elasticsearch是无模式的,所以我们可以向索引中添加任意形式的数据,只要它是合法的JSON格式就行。将path字段更新为 /movies/movie/1。path的格式为 /INDEX_NAME/TYPE/ID,movies是我们刚刚创建的索引,movie是我们给即将提交的文档类型的名称,id是这个索引中文档的唯一ID。ID是可选的,如果你在path中省略了,那么你的文档会被创建一个随机的ID。添加了path之后,选择POST方法,在底部的文本字段中输入你的JSON文档,点击发送。这样将把这个文档添加到索引中,并且向你发送一个确认消息。

这里写图片描述

在添加了几个movie到索引中之后,我们就可以用同样的界面从索引中搜索和聚合数据了。将path字段更新为 /movies/movie/_search。path的格式为 /INDEX_NAME/TYPE/_search,INDEX_NAME,TYPE都是可选的。如果省略type,则会搜索所有类型,如果省略索引名,则会搜索所有索引。

Elasticsearch支持多种不同类型的查询,我们在这里只介绍几种常见的类型。第一种类型是自由文本查询,查询字符串参数允许使用Elasticsearch Query DS进行相当复杂的查询。当然我可只输入简单的字符串进行匹配,这将匹配文档任何字段中指定的词。

{
"query": {
   "query_string": {
       "query": "Apocalypse"
   }
}
}

例如,上面的查询会返回下面的结果。结果中包含处理查询花费的时间、搜索的分片数、结果总数以及每个结果的详细信息。

{
"took": 139,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.5291085,
"hits": [{
 "_index": "movies",
  "_type": "movie",
 "_id": "AVSvEC1fG_1bjVtG66mm",
 "_score": 0.5291085,
 "_source": {
    "title": "Apocalypse Now",
   "director": "Francis Ford Coppola",
   "year": 1979,
   "genres": [
     "Drama",
     "War"
   ]
 }
}
....

除了查询文本之外,你还可以指定一个字段或一些字段的估计值,从而将查询限制为搜索文档的一个子集。比如,下面的查询会返回与之前一样的结果,但是必须查看文档的一个子集,且更大的数据集会有更好的性能。这里还有很多其他操作。

{
"query": {
"query_string": {
 "query": "Apocalypse"
 "fields": ["title"]
}
}
}

我们可以把查询字符串包裹在filtered对象中,这样会对查询的结果进行过滤。这允许我们对初始数据集保持任意格式的查询,但随后过滤出我们查找的特定数据。

{
"query": {
"filtered": {
 "query_string": {
   "query": "Apocalypse"
   "fields": ["title"]
 }
 "filter": {
   "term": { "year": 1979 }
 }
}
}
}

最后,聚合可能是你会运行的另外一种形式的查询,它对于计算有关数据的统计信息很有用。下面展示了这些类型的聚合的两个例子。第一个将返回每个导演指挥的电影的数量,第二个将返回我们的数据集中所有电影的平均评分。

{
"aggs": {
"group_by_director": {
 "terms": {
   "field": "director"
 }
}
}
}

{
"aggs" : {
"avg_rating" : { "avg" : { "field" : "rating" } }
}
}

Elasticsearch是在大型非结构化数据集上运行分析的最佳方法之一,在从日志聚合、机器学习到商业智能等许多领域中皆被广泛使用。本文中,我们看到了使用Catalog在Rancher上设置一个功能齐全的Elasticsearch集群是多么简单。此外,我们还快速了解了Elasticsearch使用REST API的强大功能。只要你有Elasticsearch可用并且运行了起来,你就可以使用它作为许多不同的用例与许多可用的可视化和聚合框架的主机,比如实时可视化的Kibana或业务分析的Pentaho框架。

原文来源:Rancher Labs

久久热在线视频精品 在线免费av片

nginx限制请求数模块 ngx_http_limit_req_module

一. 前言

在《nginx限制连接数ngx_http_limit_conn_module模块》我们说到了ngx_http_limit_conn_module 模块,来限制连接数。那么请求数的限制该怎么做呢?这就需要通过ngx_http_limit_req_module 模块来实现,该模块可以通过定义的 键值来限制请求处理的频率。特别的,可以限制来自单个IP地址的请求处理频率。 限制的方法如同漏斗,每秒固定处理请求数,推迟过多请求。
二. ngx_http_limit_req_module模块指令

limit_req_zone
语法: limit_req_zone $variable zone=name:size rate=rate;
默认值: none
配置段: http
设置一块共享内存限制域用来保存键值的状态参数。 特别是保存了当前超出请求的数量。 键的值就是指定的变量(空值不会被计算)。如

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
1
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
说明:区域名称为one,大小为10m,平均处理的请求频率不能超过每秒一次。
键值是客户端IP。
使用$binary_remote_addr变量, 可以将每条状态记录的大小减少到64个字节,这样1M的内存可以保存大约1万6千个64字节的记录。
如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
速度可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,所以如果你需要指定每秒处理少于1个的请求,2秒处理一个请求,可以使用 “30r/m”。
limit_req_log_level
语法: limit_req_log_level info | notice | warn | error;
默认值: limit_req_log_level error;
配置段: http, server, location
设置你所希望的日志级别,当服务器因为频率过高拒绝或者延迟处理请求时可以记下相应级别的日志。 延迟记录的日志级别比拒绝的低一个级别;比如, 如果设置“limit_req_log_level notice”, 延迟的日志就是info级别。
limit_req_status
语法: limit_req_status code;
默认值: limit_req_status 503;
配置段: http, server, location
该指令在1.3.15版本引入。设置拒绝请求的响应状态码。
limit_req
语法: limit_req zone=name [burst=number] [nodelay];
默认值: —
配置段: http, server, location
设置对应的共享内存限制域和允许被处理的最大请求数阈值。 如果请求的频率超过了限制域配置的值,请求处理会被延迟,所以所有的请求都是以定义的频率被处理的。 超过频率限制的请求会被延迟,直到被延迟的请求数超过了定义的阈值,这时,这个请求会被终止,并返回503 (Service Temporarily Unavailable) 错误。这个阈值的默认值为0。如:

limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;
server {
location /www.ttlsa.com/ {
limit_req zone=ttlsa_com burst=5;
}
}
1
2
3
4
5
6
limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;
server {
location /www.ttlsa.com/ {
limit_req zone=ttlsa_com burst=5;
}
}
限制平均每秒不超过一个请求,同时允许超过频率限制的请求数不多于5个。
如果不希望超过的请求被延迟,可以用nodelay参数,如:

limit_req zone=ttlsa_com burst=5 nodelay;
1
limit_req zone=ttlsa_com burst=5 nodelay;
三. 完整实例配置
http {
limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;

server {
location ^~ /download/ {
limit_req zone=ttlsa_com burst=5;
alias /data/www.ttlsa.com/download/;
}
}
}
1
2
3
4
5
6
7
8
9
10
http {
limit_req_zone $binary_remote_addr zone=ttlsa_com:10m rate=1r/s;

server {
location ^~ /download/ {
limit_req zone=ttlsa_com burst=5;
alias /data/www.ttlsa.com/download/;
}
}
}
可能要对某些IP不做限制,需要使用到白名单。名单设置参见后续的文档,我会整理一份以供读者参考。请专注。

python框架之 Tornado, IOLoop 指南

tornado 一个简单的服务器的例子:

首先,我们需要安装 tornado ,安装比较简单:

pip  install tornado

测试安装是否成功,可以打开python 终端,输入:

import     tornado.httpserver

若无报错,则证明安装成功

接下来就可以写一个简单的服务器了,如下:

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from  tornado.options import define, options


‘‘‘
此处是定义命令行参数,如果参数与此名称相同,会将指定参数的值应用为全局变量,否则默认为default的值
若参数为 help 则打印help 的值以及所有释, type 定义这个参数的类型,惹类型不符则报错
‘‘‘
define("port", default=8000, help="run on the given port", type=int)


class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        # 指定浏览器地址栏中的查询条件值,如 localhost:8080/?greeting=hello
        greeting  =  self.get_argument(‘greeting‘, ‘hello‘)
        
        # 输出到返回页面
        self.write(greeting + ‘,friendly user‘)
    
    
if __name__ == ‘__main__‘:
        # 创建一个实例化对象
    app = tornado.web.Application([
       (r"/",  IndexHandler),
    ])
    
    # 指定此对象的监听端口
    app.listen(8000)
    
    # 启动程序等待连接
    tornado.ioloop.IOLoop.current().start()

以上是自己做的一个学习笔记,欢迎大家批评指正,谢谢

DockOne微信分享(一一八):容器技术在企业级服务里的实践


【编者的话】邻盛在做面向中小微企业做服务的时候, 实际遇到很多情况, 比如对方IT基础过于薄弱, 比如基础设施过于简陋, 比如产品要解决行业需求, 企业个性需求等等,经过几年积累目前摸索出了一套完整的产品方案。目前产品是以容器为核心的一套完整的PaaS平台+全新的微服务架构+底层能力构成的完整解决方案, 目前也进入到了几家传统大型制造企业协助他们完成新一代的信息升级。

【深圳站|3天烧脑式Kubernetes训练营】培训内容包括:Kubernetes概述、架构、日志和监控,部署、自动驾驶、服务发现、网络方案等核心机制分析,进阶篇——Kubernetes调度工作原理、资源管理及源码分析等。

邻盛在企业级服务市场面向对象以及产品说明

邻盛是一家企业级服务创业企业,主要面向企业提供业务管理方案(产品),目前客户主要对象是中型和小微型企业,目前也在探索面向大型制造企业的方案。目前针对中型企业提供私有云、混合云、公有云多种方案,对小微型企业主要提供公有云方案。

私有云产品:

QQ图片20170514083604.png

产品截图:

QQ图片20170514083614.png

以上每个应用都是一组独立的容器组,企业可以根据需要随时删除、添加、关闭相应的应用。

IT架构

QQ图片20170514083627.png

如何利用容器技术实现企业免部署免维护

由于我们用户IT基础较差,而我们要产品化,必须解决不管是哪种云(私有云、公有云,混合云)必须是免部署,免维护,特别是在私有云上。因为我们是做的业务系统,企业的核心数据都在上面,因此很多企业选择数据放在本地。我们将几个核心容器设置为--restart=always,比如定时任务容器,base容器,健康检查容器,注册中心容器。同时利用健康检查来实现免维护。用户拿过去直接接上电源和网线,在局域网内下载客户端激活即可。

(题外话,我们为了解决企业恶劣环境,无机房、经常断电问题造成设备损坏,我们在第七代产品设备上采用全封闭式服务器,无风扇,解决大量静电灰尘问题,采用全铜导片将内部热量全部通过底部导出到外壳,外壳和内壳之间采用真空绝热,同时在设备前端安装小UPS提供20分钟以上电源供应,在刚才的定时容器上面提供网络监测,一旦网络断网,会过15分钟左右再次检测如果没有通就会执行自动关机,避免断电带来的硬件损坏。)

如何利用容器编排工具实现计算资源的随意扩展

在企业发展过程中,用户会越来越多,那么如何实现用户随意扩展?我们提供单独的设备,用户只需要在局域网内插上网线,便可以实现资源扩展,整个过程流程:添加的设备会以NODE节点注册到server端;接着会在节点起在原来设备里面压力较大的应用容器组并注册到网关上,网关通过流量来做相关流量分配。

如何利用容器实现业务的扩展?

比如我原来就是个贸易企业,现在我想开厂了,需要生产了,也就是原来是进销存那几个应用,现在需要加入生产几个应用,实际在系统内就是新起几组容器。微服务架构如下:

企业内部应用微服务架构是LINKSAME全新开发的框架,网关是采用的Nginx + Lua开发的。

企业内部应用–lote网关设计说明:

QQ图片20170514083642.png

Lote网关是企业内部应用的核心组件,主要负责2部分功能:第一,授权验证以及合法性验证,当用户通过用户名和密码进来后,除了在SDN网络上做了私有验证外,还提供了本地授权验证,是否为本企业用户,是否有权限进入到对应的应用,应用KEYNOTE是否合法;第二,引导合法请求到对应的微服务应用,具备一定的路由功能。Lote网关在企业下载应用时候还会验证应用是否合法,能否安装,保证企业数据的安全性与可靠性。

如何解决产品在各个行业或者企业可适应性的问题?

任何一个产品不可能去满足所有的行业,所有的用户,但大致业务是基本类似的,因此我们在单个应用上开发了一个相关企业单应用网关–mote网关设计说明:

QQ图片20170514083655.png

单个应用(比如CRM其实是无法一定满足一个企业的全部需求的,现在要修改其中某一部分业务逻辑)要修改某一部分业务逻辑来满足行业或者企业的需求,开发者或者用户只需要指定主应用(from keyapp:),通过我们指定的接口(by setp2 第二步流程『替换第二部流程』或者更细的修改 by setp 2.1『替换第二步流程里面的2.1小步流程』)便可以随意开发对应业务逻辑,无需了解和关注原应用本身背后的代码和数据,自己修改部分是个完全单独的应用,数据也是单独存储。PS:单应用不允许超过5个修正应用。

利用容器与IOT框架在物联网领域实践

QQ图片20170514083706.png

底层通信基于UDP,CoAP是IETF为constrained device制定的通信标准,包含了两层:Message和req/rsp,Message层定义了数据传输的格式,并且针对UDP传输的不可靠性,加入了安全传输的机制,req/rsp层为RESTful框架提供链路支撑。目前我们自己和相应合作伙伴开发了物联网门禁和打印机(注意不是互联网的),也兼容市面上机器手臂等制造型设备或者带物联网芯片设备。当然这个部分还有跟区块链的整合,主要是为了解决物联网里面的安全问题,有机会再跟大家做更详细的交流。

利用容器与MXNet实现AI人工智能在企业初始化和产品设计中的优化

用户在用软件的过程中一开始最大的障碍就是大量的初始化数据输入,比如组织结构、权限、行业数据(物料、产品),行业打印模板等等。我们一开始提供一些基础模板在云上,用户云上修改过程我们记录下来,通过收集大量的样板进行分析,最后通过程序给出一个最优模板数据和词汇,行业用户使用越多越接近行业标准。另外一个应用就是用户设计完产品后,我们提供一个产品云端评测,整个流程就是用户将产品提交后,AI会通过提交的一些信息跟我们云端AI库进行对比,通过维度来判断值,最后返回给用户一个产品竞争力表给用户提供参考,例如一件衣服,我们会从图片上抽取出一些维度(纹路,颜色),再从文本信息中提取一些信息,通过AI接口自动建立衣服的相关模型。

Q&A

Q:请问在容器和虚拟机之间访问网络有什么经验,通过Calico使跨主机之间容器互访,容器外的虚拟机如何访问容器,特别是在公有云环境下PaaS服务如何与容器之间进行访问?

A:我们现在公有云PaaS每个用户是一个虚拟机的方式,虚拟机内部的通讯采用的默认的网络方式Overlay,在不是大并发情况下这种问题并不明显。

Q:容器是否裸机部署、容器编排和调度工具?

A:我们私有云产品是裸机部署,容器编排和调度工具目前有版Kubernetes。

Q:请问你们的私有云建设主要用了什么软件?

A:私有云就是裸机+容器+编排工具+基础能力容器(比如消息、SDN等)。

Q:Auto Scaling是垂直的,还是水平的?

A:是水平扩展的,就是在另外设备里面重新启动一组容器,并且将数据库容器加入到ge节点中取。

Q:微服务注册,服务发现是怎么做到的?

A:微服务注册分成2部分:1. 微服务是否经过了云审核,是否能通过LOTE网关验证;2. 在内部是通过etcd一整套来实现的(健康检查)。

以上内容根据2017年5月2日晚微信群分享内容整理。分享人武汉邻盛在线科技有限公司创始人。10年企业级经验, 连续创业者, 技术爱好者, 架构师。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesz,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

python 浅谈正则的常用方法

python浅谈正则的常用方法覆盖范围70%以上

上一次很多朋友写文字屏蔽说到要用正则表达,其实不是我不想用(我正则用得不是很多,看过我之前爬虫的都知道,我直接用BeautifulSoup的网页标签去找内容,因为容易理解也方便),而是正则用好用精通的很难(看过正则表的应该都知道,里面符号对应的方法规则有很多,很灵活)。对于接触编程不久的朋友们来说很可能在编程的过程上浪费很多时间,今天我把经常会用到正则简单介绍下,如果不是很特殊基本都覆盖使用。

1.正则的简单介绍

首先你得导入正则方法 import re 正则表达式是用于处理字符串的强大工具,拥有自己独立的处理机制,效率上可能不如str自带的方法,但功能十分灵活给力。它的运行过程是先定一个匹配规则(”你想要的内容+正则语法规则”),放入要匹配的字符串,通过正则内部的机制就能检索你想要的信息。

2.findall的常用几种姿势

基本结构大致: nojoke = re.findall(r’匹配的规则’,’要检索的愿字符串’)   nojoke就是我们最后通过正则返回的结果,re正则findall查找全部r标识代表后面是正则的语句(这样在代码多的时候好查阅),下面我们看看几个例子好深入了解

这段代码是找出检索字符串中所有的bi并以列表的形式返回,这个会经常用到计算统一字符出现的次数。继续看下一个

这里加了个符号^表示匹配以abi开头的的字符串返回,也可以判断字符串是否以abi开始的。

这里在的用$符号表示以gbi结尾的字符串返回,判断是否字符串结束的字符串。

这里[…]的意思匹配括号内a和f,或者b和f,或者c和f的值返回列表。

“d”是正则语法规则用来匹配0到9之间的数返回列表,需要注意的是11会当成字符串’1’和’1’返回而不是返回’11’这个字符串,切记用不好这里是大坑。

当然解决的办法就你要取几位数就写几个d,上面这里演示取字符串中3位数字,这里展现了正则灵活一方面。

这里小d表示取数字0-9,大D表示不要数字,也就是出了数字以外的内容返回。

“w”在正则里面代表匹配从小写a到z,大写A到Z,数字0到9包含前面这三种的如上面打印的一样.

“W”在正则里面代表匹配除了字母与数字以外的特殊符号,但这里斜杠的用法要注意在字符串是转义符号具体百度去学。

这里括号()的用法表示匹配是取括号内里面的内容,这里.*是正则贪婪匹配语法百话点就是贪心利益最大话最大范围的匹配准则如上图所示。

这里加了个问号.*?就是限制它不让他最大范围的匹配也叫非贪婪模式匹配。结果是把两个div内的内容匹配返回。

这里加re.I(大写的i)表示匹配无论公的母的大小写都通吃都要,不然后面有大小写就会出现上面匹配找不到返回空列表给你。

这里又搞事了就是n俗称换行符,一旦换行程序就SB了不认了,所以我们加上了re.S(大写)这样代表比匹配包括换行在内的所有字符内容返回,基本你把上面的语法和用法学会后基本70%以上匹配方法全都搞定,当然还有很方法我就不列举了,大家可以自己去学习(剩下的基本我都很少用到了)。

2.match和search的用法及区别:

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。re.search 扫描整个字符串并返回第一个成功的匹配。来看看代码就容易理解了。如下:

这里直接打印结尾加上.span()可以得到匹配字符串的位置以元组tuple返回(起始位置,结束位置),有一个没写,因为他返回空加上会编译器报错。

是不是一目了然,match只会开头匹配,找不到就返回None,这里我没加.group()是因为返回值是空值我加了编译器会报错,search不挑食扫描整个字符串,当然里面也可以用上面的正则方法去匹配,这里就不过多介绍了大家可以动手练练。

3.sub替换的用法

sub用于替换字符串中的匹配项,语法一般是re.sub(r’正则匹配规则’,’替换的字符串’,需要检索的字符串)

这里很直观的反应了结果,把#号及后面的字符串替换想要改的字符串。

4.最后福利

在给最后福利之前,希望大家能多练练上面的用法和使用规则,只有多出错多总结才会积累经验,最后的福利讲给大家几个常用的邮箱匹配规则如下:

必杀技能最后送了合体多种匹配或者发|用来匹配多个不同的邮箱使用,大家只要用熟以上的方法保守70%以上的地方都能够使用到,最后声明只是小弟个人理解分享,大佬们忽略就忽略吧,谢谢,最后还还是老台词:感谢观看,下次再见!

SED单行脚本快速参考(Unix 流编辑器)


英文标题:USEFUL ONE-LINE SCRIPTS FOR SED (Unix stream editor)
原标题:HANDY ONE-LINERS FOR SED (Unix stream editor)

整理:Eric Pement – 电邮:pemente[at]northpark[dot]edu 版本5.5
译者:Joe Hong – 电邮:hq00e[at]126[dot]com

在以下地址可找到本文档的最新(英文)版本:
http://sed.sourceforge.net/sed1line.txt
http://www.pement.org/sed/sed1line.txt

其他语言版本:
中文 – http://sed.sourceforge.net/sed1linezh-CN.html
捷克语 – http://sed.sourceforge.net/sed1line
cz.html
荷语 – http://sed.sourceforge.net/sed1linenl.html
法语 – http://sed.sourceforge.net/sed1line
fr.html
德语 – http://sed.sourceforge.net/sed1line_de.html

葡语 – http://sed.sourceforge.net/sed1line_pt-BR.html

文本间隔:

在每一行后面增加一空行

sed G

将原来的所有空行删除并在每一行后面增加一空行。

这样在输出的文本中每一行后面将有且只有一空行。

sed ‘/^$/d;G’

在每一行后面增加两行空行

sed ‘G;G’

将第一个脚本所产生的所有空行删除(即删除所有偶数行)

sed ‘n;d’

在匹配式样“regex”的行之前插入一空行

sed ‘/regex/{x;p;x;}’

在匹配式样“regex”的行之后插入一空行

sed ‘/regex/G’

在匹配式样“regex”的行之前和之后各插入一空行

sed ‘/regex/{x;p;x;G;}’

编号:

为文件中的每一行进行编号(简单的左对齐方式)。这里使用了“制表符”

(tab,见本文末尾关于’\t’的用法的描述)而不是空格来对齐边缘。

sed = filename | sed ‘N;s/\n/\t/’

对文件中的所有行编号(行号在左,文字右端对齐)。

sed = filename | sed ‘N; s/^/ /; s/ *(.{6,})\n/\1 /’

对文件中的所有行编号,但只显示非空白行的行号。

sed ‘/./=’ filename | sed ‘/./N; s/\n/ /’

计算行数 (模拟 “wc -l”)

sed -n ‘$=’

文本转换和替代:

Unix环境:转换DOS的新行符(CR/LF)为Unix格式。

sed ‘s/.$//’ # 假设所有行以CR/LF结束
sed ‘s/^M$//’ # 在bash/tcsh中,将按Ctrl-M改为按Ctrl-V
sed ‘s/\x0D$//’ # ssed、gsed 3.02.80,及更高版本

Unix环境:转换Unix的新行符(LF)为DOS格式。

sed “s/$/echo -e \r/” # 在ksh下所使用的命令
sed ‘s/$'”/echo \r/” # 在bash下所使用的命令
sed “s/$/echo \r/” # 在zsh下所使用的命令
sed ‘s/$/\r/’ # gsed 3.02.80 及更高版本

DOS环境:转换Unix新行符(LF)为DOS格式。

sed “s/$//” # 方法 1
sed -n p # 方法 2

DOS环境:转换DOS新行符(CR/LF)为Unix格式。

下面的脚本只对UnxUtils sed 4.0.7 及更高版本有效。要识别UnxUtils版本的

sed可以通过其特有的“–text”选项。你可以使用帮助选项(“–help”)看

其中有无一个“–text”项以此来判断所使用的是否是UnxUtils版本。其它DOS

版本的的sed则无法进行这一转换。但可以用“tr”来实现这一转换。

sed “s/\r//” infile >outfile # UnxUtils sed v4.0.7 或更高版本
tr -d \r outfile # GNU tr 1.22 或更高版本

将每一行前导的“空白字符”(空格,制表符)删除

使之左对齐

sed ‘s/^[ \t]*//’ # 见本文末尾关于’\t’用法的描述

将每一行拖尾的“空白字符”(空格,制表符)删除

sed ‘s/[ \t]*$//’ # 见本文末尾关于’\t’用法的描述

将每一行中的前导和拖尾的空白字符删除

sed ‘s/^[ \t]//;s/[ \t]$//’

在每一行开头处插入5个空格(使全文向右移动5个字符的位置)

sed ‘s/^/ /’

以79个字符为宽度,将所有文本右对齐

sed -e :a -e ‘s/^.{1,78}$/ &/;ta’ # 78个字符外加最后的一个空格

以79个字符为宽度,使所有文本居中。在方法1中,为了让文本居中每一行的前

头和后头都填充了空格。 在方法2中,在居中文本的过程中只在文本的前面填充

空格,并且最终这些空格将有一半会被删除。此外每一行的后头并未填充空格。

sed -e :a -e ‘s/^.{1,77}$/ & /;ta’ # 方法1
sed -e :a -e ‘s/^.{1,77}$/ &/;ta’ -e ‘s/( *)\1/\1/’ # 方法2

在每一行中查找字串“foo”,并将找到的“foo”替换为“bar”

sed ‘s/foo/bar/’ # 只替换每一行中的第一个“foo”字串
sed ‘s/foo/bar/4’ # 只替换每一行中的第四个“foo”字串
sed ‘s/foo/bar/g’ # 将每一行中的所有“foo”都换成“bar”
sed ‘s/(.)foo(.foo)/\1bar\2/’ # 替换倒数第二个“foo”
sed ‘s/(.*)foo/\1bar/’ # 替换最后一个“foo”

只在行中出现字串“baz”的情况下将“foo”替换成“bar”

sed ‘/baz/s/foo/bar/g’

将“foo”替换成“bar”,并且只在行中未出现字串“baz”的情况下替换

sed ‘/baz/!s/foo/bar/g’

不管是“scarlet”“ruby”还是“puce”,一律换成“red”

sed ‘s/scarlet/red/g;s/ruby/red/g;s/puce/red/g’ #对多数的sed都有效
gsed ‘s/scarlet\|ruby\|puce/red/g’ # 只对GNU sed有效

倒置所有行,第一行成为最后一行,依次类推(模拟“tac”)。

由于某些原因,使用下面命令时HHsed v1.5会将文件中的空行删除

sed ‘1!G;h;$!d’ # 方法1
sed -n ‘1!G;h;$p’ # 方法2

将行中的字符逆序排列,第一个字成为最后一字,……(模拟“rev”)

sed ‘/\n/!G;s/(.)(.*\n)/&\2\1/;//D;s/.//’

将每两行连接成一行(类似“paste”)

sed ‘$!N;s/\n/ /’

如果当前行以反斜杠“\”结束,则将下一行并到当前行末尾

并去掉原来行尾的反斜杠

sed -e :a -e ‘/\$/N; s/\n//; ta’

如果当前行以等号开头,将当前行并到上一行末尾

并以单个空格代替原来行头的“=”

sed -e :a -e ‘$!N;s/\n=/ /;ta’ -e ‘P;D’

为数字字串增加逗号分隔符号,将“1234567”改为“1,234,567”

gsed ‘:a;s/\B[0-9]{3}>/,&/;ta’ # GNU sed
sed -e :a -e ‘s/(.*[0-9])([0-9]{3})/\1,\2/;ta’ # 其他sed

为带有小数点和负号的数值增加逗号分隔符(GNU sed)

gsed -r ‘:a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g;ta’

在每5行后增加一空白行 (在第5,10,15,20,等行后增加一空白行)

gsed ‘0~5G’ # 只对GNU sed有效
sed ‘n;n;n;n;G;’ # 其他sed

选择性地显示特定行:

显示文件中的前10行 (模拟“head”的行为)

sed 10q

显示文件中的第一行 (模拟“head -1”命令)

sed q

显示文件中的最后10行 (模拟“tail”)

sed -e :a -e ‘$q;N;11,$D;ba’

显示文件中的最后2行(模拟“tail -2”命令)

sed ‘$!N;$!D’

显示文件中的最后一行(模拟“tail -1”)

sed ‘$!d’ # 方法1
sed -n ‘$p’ # 方法2

显示文件中的倒数第二行

sed -e ‘$!{h;d;}’ -e x # 当文件中只有一行时,输入空行
sed -e ‘1{$q;}’ -e ‘$!{h;d;}’ -e x # 当文件中只有一行时,显示该行
sed -e ‘1{$d;}’ -e ‘$!{h;d;}’ -e x # 当文件中只有一行时,不输出

只显示匹配正则表达式的行(模拟“grep”)

sed -n ‘/regexp/p’ # 方法1
sed ‘/regexp/!d’ # 方法2

只显示“不”匹配正则表达式的行(模拟“grep -v”)

sed -n ‘/regexp/!p’ # 方法1,与前面的命令相对应
sed ‘/regexp/d’ # 方法2,类似的语法

查找“regexp”并将匹配行的上一行显示出来,但并不显示匹配行

sed -n ‘/regexp/{g;1!p;};h’

查找“regexp”并将匹配行的下一行显示出来,但并不显示匹配行

sed -n ‘/regexp/{n;p;}’

显示包含“regexp”的行及其前后行,并在第一行之前加上“regexp”所

在行的行号 (类似“grep -A1 -B1”)

sed -n -e ‘/regexp/{=;x;1!p;g;$!N;p;D;}’ -e h

显示包含“AAA”、“BBB”或“CCC”的行(任意次序)

sed ‘/AAA/!d; /BBB/!d; /CCC/!d’ # 字串的次序不影响结果

显示包含“AAA”、“BBB”和“CCC”的行(固定次序)

sed ‘/AAA.BBB.CCC/!d’

显示包含“AAA”“BBB”或“CCC”的行 (模拟“egrep”)

sed -e ‘/AAA/b’ -e ‘/BBB/b’ -e ‘/CCC/b’ -e d # 多数sed
gsed ‘/AAA\|BBB\|CCC/!d’ # 对GNU sed有效

显示包含“AAA”的段落 (段落间以空行分隔)

HHsed v1.5 必须在“x;”后加入“G;”,接下来的3个脚本都是这样

sed -e ‘/./{H;$!d;}’ -e ‘x;/AAA/!d;’

显示包含“AAA”“BBB”和“CCC”三个字串的段落 (任意次序)

sed -e ‘/./{H;$!d;}’ -e ‘x;/AAA/!d;/BBB/!d;/CCC/!d’

显示包含“AAA”、“BBB”、“CCC”三者中任一字串的段落 (任意次序)

sed -e ‘/./{H;$!d;}’ -e ‘x;/AAA/b’ -e ‘/BBB/b’ -e ‘/CCC/b’ -e d
gsed ‘/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d’ # 只对GNU sed有效

显示包含65个或以上字符的行

sed -n ‘/^.{65}/p’

显示包含65个以下字符的行

sed -n ‘/^.{65}/!p’ # 方法1,与上面的脚本相对应
sed ‘/^.{65}/d’ # 方法2,更简便一点的方法

显示部分文本——从包含正则表达式的行开始到最后一行结束

sed -n ‘/regexp/,$p’

显示部分文本——指定行号范围(从第8至第12行,含8和12行)

sed -n ‘8,12p’ # 方法1
sed ‘8,12!d’ # 方法2

显示第52行

sed -n ’52p’ # 方法1
sed ’52!d’ # 方法2
sed ’52q;d’ # 方法3, 处理大文件时更有效率

从第3行开始,每7行显示一次

gsed -n ‘3~7p’ # 只对GNU sed有效
sed -n ‘3,${p;n;n;n;n;n;n;}’ # 其他sed

显示两个正则表达式之间的文本(包含)

sed -n ‘/Iowa/,/Montana/p’ # 区分大小写方式

选择性地删除特定行:

显示通篇文档,除了两个正则表达式之间的内容

sed ‘/Iowa/,/Montana/d’

删除文件中相邻的重复行(模拟“uniq”)

只保留重复行中的第一行,其他行删除

sed ‘$!N; /^(.*)\n\1$/!P; D’

删除文件中的重复行,不管有无相邻。注意hold space所能支持的缓存

大小,或者使用GNU sed。

sed -n ‘G; s/\n/&&/; /^([ -~]\n).\n\1/d; s/\n//; h; P’

删除除重复行外的所有行(模拟“uniq -d”)

sed ‘$!N; s/^(.*)\n\1$/\1/; t; D’

删除文件中开头的10行

sed ‘1,10d’

删除文件中的最后一行

sed ‘$d’

删除文件中的最后两行

sed ‘N;$!P;$!D;$d’

删除文件中的最后10行

sed -e :a -e ‘$d;N;2,10ba’ -e ‘P;D’ # 方法1
sed -n -e :a -e ‘1,10!{P;N;D;};N;ba’ # 方法2

删除8的倍数行

gsed ‘0~8d’ # 只对GNU sed有效
sed ‘n;n;n;n;n;n;n;d;’ # 其他sed

删除匹配式样的行

sed ‘/pattern/d’ # 删除含pattern的行。当然pattern

可以换成任何有效的正则表达式

删除文件中的所有空行(与“grep ‘.’ ”效果相同)

sed ‘/^$/d’ # 方法1
sed ‘/./!d’ # 方法2

只保留多个相邻空行的第一行。并且删除文件顶部和尾部的空行。

(模拟“cat -s”)

sed ‘/./,/^$/!d’ #方法1,删除文件顶部的空行,允许尾部保留一空行
sed ‘/^$/N;/\n$/D’ #方法2,允许顶部保留一空行,尾部不留空行

只保留多个相邻空行的前两行。

sed ‘/^$/N;/\n$/N;//D’

删除文件顶部的所有空行

sed ‘/./,$!d’

删除文件尾部的所有空行

sed -e :a -e ‘/^\n$/{$d;N;ba’ -e ‘}’ # 对所有sed有效
sed -e :a -e ‘/^\n
$/N;/\n$/ba’ # 同上,但只对 gsed 3.02.*有效

删除每个段落的最后一行

sed -n ‘/^$/{p;h;};/./{x;/./p;}’

特殊应用:

移除手册页(man page)中的nroff标记。在Unix System V或bash shell下使

用’echo’命令时可能需要加上 -e 选项。

sed “s/.echo \b//g” # 外层的双括号是必须的(Unix环境)
sed ‘s/.^H//g’ # 在bash或tcsh中, 按 Ctrl-V 再按 Ctrl-H
sed ‘s/.\x08//g’ # sed 1.5,GNU sed,ssed所使用的十六进制的表示方法

提取新闻组或 e-mail 的邮件头

sed ‘/^$/q’ # 删除第一行空行后的所有内容

提取新闻组或 e-mail 的正文部分

sed ‘1,/^$/d’ # 删除第一行空行之前的所有内容

从邮件头提取“Subject”(标题栏字段),并移除开头的“Subject:”字样

sed ‘/^Subject: */!d; s///;q’

从邮件头获得回复地址

sed ‘/^Reply-To:/q; /^From:/h; /./d;g;q’

获取邮件地址。在上一个脚本所产生的那一行邮件头的基础上进一步的将非电邮

地址的部分剃除。(见上一脚本)

sed ‘s/ (.)//; s/>.//; s/.[:<] *//’

在每一行开头加上一个尖括号和空格(引用信息)

sed ‘s/^/> /’

将每一行开头处的尖括号和空格删除(解除引用)

sed ‘s/^> //’

移除大部分的HTML标签(包括跨行标签)

sed -e :a -e ‘s/<[^>]*>//g;/

将分成多卷的uuencode文件解码。移除文件头信息,只保留uuencode编码部分。

文件必须以特定顺序传给sed。下面第一种版本的脚本可以直接在命令行下输入;

第二种版本则可以放入一个带执行权限的shell脚本中。(由Rahul Dhesi的一

个脚本修改而来。)

sed ‘/^end/,/^begin/d’ file1 file2 … fileX | uudecode # vers. 1
sed ‘/^end/,/^begin/d’ “$@” | uudecode # vers. 2

将文件中的段落以字母顺序排序。段落间以(一行或多行)空行分隔。GNU sed使用

字元“\v”来表示垂直制表符,这里用它来作为换行符的占位符——当然你也可以

用其他未在文件中使用的字符来代替它。

sed ‘/./{H;d;};x;s/\n/={NL}=/g’ file | sort | sed ‘1s/={NL}=//;s/={NL}=/\n/g’
gsed ‘/./{H;d};x;y/\n/\v/’ file | sort | sed ‘1s/\v//;y/\v/\n/’

分别压缩每个.TXT文件,压缩后删除原来的文件并将压缩后的.ZIP文件

命名为与原来相同的名字(只是扩展名不同)。(DOS环境:“dir /b”

显示不带路径的文件名)。

echo @echo off >zipup.bat
dir /b .txt | sed “s/^(.).TXT/pkzip -mo \1 \1.TXT/” >>zipup.bat

使用SED:Sed接受一个或多个编辑命令,并且每读入一行后就依次应用这些命令。
当读入第一行输入后,sed对其应用所有的命令,然后将结果输出。接着再读入第二
行输入,对其应用所有的命令……并重复这个过程。上一个例子中sed由标准输入设
备(即命令解释器,通常是以管道输入的形式)获得输入。在命令行给出一个或多
个文件名作为参数时,这些文件取代标准输入设备成为sed的输入。sed的输出将被
送到标准输出(显示器)。因此:

cat filename | sed ’10q’ # 使用管道输入
sed ’10q’ filename # 同样效果,但不使用管道输入
sed ’10q’ filename > newfile # 将输出转移(重定向)到磁盘上

要了解sed命令的使用说明,包括如何通过脚本文件(而非从命令行)来使用这些命
令,请参阅《sed & awk》第二版,作者Dale Dougherty和Arnold Robbins
(O’Reilly,1997;http://www.ora.com),《UNIX Text Processing》,作者
Dale Dougherty和Tim O’Reilly(Hayden Books,1987)或者是Mike Arst写的教
程——压缩包的名称是“U-SEDIT2.ZIP”(在许多站点上都找得到)。要发掘sed
的潜力,则必须对“正则表达式”有足够的理解。正则表达式的资料可以看
《Mastering Regular Expressions》作者Jeffrey Friedl(O’reilly 1997)。
Unix系统所提供的手册页(“man”)也会有所帮助(试一下这些命令
“man sed”、“man regexp”,或者看“man ed”中关于正则表达式的部分),但
手册提供的信息比较“抽象”——这也是它一直为人所诟病的。不过,它本来就不
是用来教初学者如何使用sed或正则表达式的教材,而只是为那些熟悉这些工具的人
提供的一些文本参考。

括号语法:前面的例子对sed命令基本上都使用单引号(’…’)而非双引号
(”…”)这是因为sed通常是在Unix平台上使用。单引号下,Unix的shell(命令
解释器)不会对美元符($)和后引号(...)进行解释和执行。而在双引号下
美元符会被展开为变量或参数的值,后引号中的命令被执行并以输出的结果代替
后引号中的内容。而在“csh”及其衍生的shell中使用感叹号(!)时需要在其前
面加上转义用的反斜杠(就像这样:!)以保证上面所使用的例子能正常运行
(包括使用单引号的情况下)。DOS版本的Sed则一律使用双引号(”…”)而不是
引号来圈起命令。

‘\t’的用法:为了使本文保持行文简洁,我们在脚本中使用’\t’来表示一个制表
符。但是现在大部分版本的sed还不能识别’\t’的简写方式,因此当在命令行中为
脚本输入制表符时,你应该直接按TAB键来输入制表符而不是输入’\t’。下列的工
具软件都支持’\t’做为一个正则表达式的字元来表示制表符:awk、perl、HHsed、
sedmod以及GNU sed v3.02.80。

不同版本的SED:不同的版本间的sed会有些不同之处,可以想象它们之间在语法上
会有差异。具体而言,它们中大部分不支持在编辑命令中间使用标签(:name)或分
支命令(b,t),除非是放在那些的末尾。这篇文档中我们尽量选用了可移植性较高
的语法,以使大多数版本的sed的用户都能使用这些脚本。不过GNU版本的sed允许使
用更简洁的语法。想像一下当读者看到一个很长的命令时的心情:

sed -e ‘/AAA/b’ -e ‘/BBB/b’ -e ‘/CCC/b’ -e d

好消息是GNU sed能让命令更紧凑:

sed ‘/AAA/b;/BBB/b;/CCC/b;d’ # 甚至可以写成
sed ‘/AAA\|BBB\|CCC/b;d’

此外,请注意虽然许多版本的sed接受象“/one/ s/RE1/RE2/”这种在’s’前带有空
格的命令,但这些版本中有些却不接受这样的命令:“/one/! s/RE1/RE2/”。这时
只需要把中间的空格去掉就行了。

速度优化:当由于某种原因(比如输入文件较大、处理器或硬盘较慢等)需要提高
命令执行速度时,可以考虑在替换命令(“s/…/…/”)前面加上地址表达式来
提高速度。举例来说:

sed ‘s/foo/bar/g’ filename # 标准替换命令
sed ‘/foo/ s/foo/bar/g’ filename # 速度更快
sed ‘/foo/ s//bar/g’ filename # 简写形式

当只需要显示文件的前面的部分或需要删除后面的内容时,可以在脚本中使用“q”
命令(退出命令)。在处理大的文件时,这会节省大量时间。因此:

sed -n ‘45,50p’ filename # 显示第45到50行
sed -n ’51q;45,50p’ filename # 一样,但快得多

如果你有其他的单行脚本想与大家分享或者你发现了本文档中错误的地方,请发电
子邮件给本文档的作者(Eric Pement)。邮件中请记得提供你所使用的sed版本、
该sed所运行的操作系统及对问题的适当描述。本文所指的单行脚本指命令行的长
度在65个字符或65个以下的sed脚本〔译注1〕。本文档的各种脚本是由以下所列作
者所写或提供:

Al Aab # 建立了“seders”邮件列表
Edgar Allen # 许多方面
Yiorgos Adamopoulos # 许多方面
Dale Dougherty # 《sed & awk》作者
Carlos Duarte # 《do it with sed》作者
Eric Pement # 本文档的作者
Ken Pizzini # GNU sed v3.02 的作者
S.G. Ravenhall # 去html标签脚本

Greg Ubben # 有诸多贡献并提供了许多帮助

译注1:大部分情况下,sed脚本无论多长都能写成单行的形式(通过-e'选项和;’
号)——只要命令解释器支持,所以这里说的单行脚本除了能写成一行还对长度有
所限制。因为这些单行脚本的意义不在于它们是以单行的形式出现。而是让用户能
方便地在命令行中使用这些紧凑的脚本才是其意义所在。

使用python爬虫工具Scrapy统计简书文章阅读量

突然发现多年来一直断断续续在学习使用的python,拥有着广泛的使用场景,从开源硬件、服务器运维、自动化测试,到数学计算,人工智能,都有python的一席之地,在各个领域python有丰富的框架和工具。

听闻python的Scrapy爬虫已久,最近正好想对去年一年在简书写作的文章做一下统计。作为软件工程师,肯定不能去按计算器,正好找到一个可以使用scrapy的场景,直接用爬虫来抓取简书页面,然后提取数据作统计。

工作原理和步骤

  1. 分析要抓取的页面结构,找到有价值的信息;
  2. 通过发起http请求,获得要抓取页面的html正文;
  3. 分析html页面的标签结构,根据xml层级结构或者css选择器语法,读取到需要的document元素;
  4. 设计数据结构和计算规则,进行统计,然后将结果输出

抓取网页的话使用urllib库其实就可以完成,css选择器的话,python也有pyquery提供类似jquery的功能。剩下就是简单的数据统计了。

使用Scrapy动手操作

完整的项目还没有整理好,暂时不提供代码,本身核心业务逻辑的代码量并不多。

安装python和scrapy

#安装pip
apt-get install -y build-essential libffi-dev libxml2-dev libxslt1-dev libevent-dev libssl-dev zlib1g-dev  python-dev python-pip
pip install -U pip

#安装scrapy
pip install scrapy

本次应用中使用pip来安装scrapy,详细安装可以参看官网,安装pip的同时,需要安装一些linux开发相关的工具。

需要注意的事项有两点,首先如果是在mac上安装的话,由于操作系统以来sis这个库,而scrapy需要更高版本的sis,无法升级,所以可能有坑,笔者直接使用docker搭建的容器进行开发,所以不存在问题;另外一个是pip源,在国内可能下载速度会比较慢,可以使用国内的源或者翻墙下载。

import sys
import scrapy
import csv

class MyJianShuSpider(scrapy.Spider):
    name = 'my_jisnshu_spider'
    page = 1
    userid = 'yourid'
    base_url = 'http://www.jianshu.com/u/yourid?order_by=shared_at&page='
    start_urls = ['http://www.jianshu.com/u/yourid?order_by=shared_at&page=1']
    headers = {
      "Host": "www.jianshu.com",
      "User-Agent": "your agent",
      "Accept": "*/*"
    }

    def start_requests(self):
        url = self.base_url + str(self.page)
        yield scrapy.Request(url, headers=self.headers, callback=self.parse)

    def parse(self, response):
        for item in response.css('ul.note-list li'):
            print publishTimeText = item.css('.author .name > .time ::attr(data-shared-at)').extract_first()

Scrapy基本工作原理

scrapy提供了Spider类,该类通过start_requests接口被scrapy执行器调用,运行scrapy执行器,就会从入口点start_requests开始执行爬虫的代码;使用过javascript的es2015应该会比较容易理解yield,感觉是js也借鉴了很多python的理念。

在Spider执行过程中,任何时候都可以通过调用scrapy.Request来发起一个爬虫抓取操作,callback参数是抓取的网络请求成功之后的回调函数,url是请求的链接地址,headers是http协议的头部,可以根据需要设置。

简书页面的相关结构

查看简书列表页面的document结构,很容易找到#list-container下面的ul列表就是包含我们要统计的信息的节点,因此可以直接使用scrapy提供的css选择器来获取。执行回调函数response.css('ul.note-list li')就获取到了一个列表,对列表做循环处理,取出每一个需要的元素。

#发表时间
publishTimeText = item.css('.author .name > .time ::attr(data-shared-at)').extract_first()
# 摘要
abstractText = item.css('p.abstract ::text').extract_first()
# 文章标题
titleText = item.css('a.title ::text').extract_first()
# 文章的链接
articleLink = item.css('a.title ::attr(href)').extract_first()

#统计信息
metaList = item.css('.meta > a ::text').re(r' ([0-9]*)\n')

最后的metaList返回的是一个数组,下标0-2分别是阅读、评论和点赞的数目。

在实际获取到的列表页面中,页面的文章是通过异步加载,每次获取一页数据的,所以在抓取过程中,需要多次抓取每次抓取一页,直到没有更多文章为止。

生成的表格

简书实际上提供了分页的文章列表页,可以分页获取数据,页面中页可以找到是否还有更多文章的标记。为了不破坏读者探索的乐趣,文章里就不详细介绍了。

    </div>

yarn 和 npm 都换成 淘宝镜像,就飞起来了 收藏!

如果觉得安装速度慢,安装源和原来 npm 是一样的,可以通用,修改方法如下:

yarn config get registry
# -> https://registry.yarnpkg.com

可以改成 taobao 的源:

yarn config set registry 'https://registry.npm.taobao.org'
# -> yarn config v0.15.0
# -> success Set "registry" to "https://registry.npm.taobao.org".
# -> Done in 0.04s.

然后 yarn install 的速度就快多了

只需要把 yarn 改成npm,同理可以修改npm的