backend

如何导出 Docker 镜像

可以使用 docker save 和 docker export 导出 docker 镜像。那么两者有什么区别呢?

  • export 是用来导出一个容器的,也就是运行中的镜像。
  • save 是用来导出镜像的,也就是还没有运行的镜像。

这里我们需要用的显然是 docker save。

语法是:

docker save [OPTIONS] IMAGE [IMAGE...]

其中的 options 也就一个参数 -o 文件名。如果不指定 -o 的话直接输出到 stdout,方便使用管道串联。

如果需要压缩的话还可以这样

docker save myimage:latest | gzip > myimage_latest.tar.gz

导出之后,可以使用 docker load 导入镜像。不使用 -i 的话直接从 stdin 读取。

docker load -i FILE

kubernetes 初探——在 Master 节点部署 Pod

虽然 K8S 本身不建议在 Master 节点中部署 Pod,但是实际上也是可以的。

kubectl taint nodes --all node-role.kubernetes.io/master-

这行命令的意思是移除所有节点的 master taint,这样就可以在 master 节点部署 pod 啦~

原理解释——taint 和 toleration

  1. https://www.ibm.com/support/knowledgecenter/en/SSCKRH1.0.1/platform/installpod_scheduling.html
  2. https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/

kubernetes 初探——服务治理

服务治理有两种方式:

  • 一种是直接在服务中集成熔断降级等操作
  • 一种是使用 sidecar 模式,有公共组件来处理

两种模式的区别如图:

服务

相关概念

Service. 如果一个 Deployment 对外(pod 外)提供服务的话,可以暴露为 Service。它是服务的抽象, 通过 kube-proxy 和 DNS 等提供负载均衡给后端 RC 定义的 Pod。服务一共有三种类型:

  • clusterIP. 服务暴露在集群内部的一个虚拟 IP,生命周期和服务相同
  • nodePort. 暴露在所有 Node 上的服务端口,不建议在生产环境使用。
  • LoadBalancer,通过外部的LB,暴露对应的服务。

另外还可以使用 Ingress Controller. Service 只是对集群内部暴露了服务,ingress controller 用于把 Service 再对外暴露。就相当于一个虚拟主机。

如果一个 deployment 需要对集群内部或者是外部提供服务的话,可以使用 service。

这时将创建一个 clusterIP,需要特别注意的是,这个 clusterIP 也是虚拟的,并没有和任何 pod 绑定,而是绑定到了服务上,可以理解为绑定到了这个服务对应的内部负载均衡上,并且是不变的。即使你的 Deployment 中指定了多个副本,那么也只有这一个 clusterIP,pod 的创建和销毁也都不会影响到 clusterIP。

参考资料

  1. Service Mesh 的本质、价值和应用探索
  2. Istio, K8S 的微服务支持
  3. 微服务之熔断、降级、限流
  4. 微服务化之服务拆分与服务发现

kubernetes 初探——使用 helm 部署服务

在 k8s 上部署一个应用还是有些复杂的, 自己的应用当然需要自己一步一步部署, 但是对于一些通用的应用, 比如说 mysql/grafana 这种就没必要自己手工一步一步部署了. 这时候就有了 helm, 通俗的来说他就是 kubernetes 上的 AppStore 或者是 apt-get, 常见的应用都已经在了, 而且你也可以按照他的格式打包自己的应用部署.

Helm 是 Kubernetes 的一个包管理器,你可以把他理解为 apt-get 或者 App Store。Helm 中的一个包称为一个 Chart,每次安装后称为一个 Release, Release 还有 revision,可以升级或者回滚到之前的 revision。 Helm 中还可以添加不同的 repo,repos 中有不同的 Chart。

安装

在 helm 的 release 页面下载, 然后拷贝到本地的 /usr/local/bin/ 目录就好了. helm 运行的时候会使用 ~/.kube/config 文件, 所以本地 kubectl 可以使用就好了.

使用

添加仓库

helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts  # 国内镜像

安装包(Chart)

helm repo update  # 更新仓库
helm install stable/mysql --generate-name  # 安装一个包

列出值

helm list  # 列出当前的 release
helm status RELEASE # 查看状态

自定义安装

helm show values stable/mysql
helm install -f config.yaml stable/mysql --generate-name

升级和回滚

helm upgrade
helm rollback

卸载

helm uninstall

概念

  • Chart, 大概相当于 package 的意思
  • Repository, Helm 的中心仓库
  • Release, 每次运行一个 Chart 都会生成一个 Release, 每个 release 之间是独立的. Chart/Release 的关系就好比 Docker 的 Image/Container 一样.
  • Revision, 每次更新 Release 都会产生一个新的版本, 可以回滚

基础命令

helm search 查找相关的软件包(chart), 现在 stable 仓库中大概有 200 多个包可以安装.

helm install –name NAME PACKAGE 会安装对应的 chart. 如果不指定 name, 会自动生成一个.

helm status NAME 可以查看对应的包的信息, 一般包括了如何连接使用这个包等信息, 可以当做帮助来用.

在安装包之前更改配置

每个 helm chart 都定义了一些默认的配置, 可以在安装之前查看并修改这些值.

helm inspect values stable/mysql 查看 mysql 的默认值. 或者去 GitHub 上看这个仓库的 readme.

把需要覆盖的变量写到 OVERRIDE.yml 文件中, helm install -f OVERRIDE.yml stable/mysql 就可以使用自己的配置了

更新 release

如果需要更新一个 release, 可以使用 helm upgrade -f OVERRIDE.yml RELEASE_NAME 命令更新相关的配置. 这时就会创建一个新的版本.

使用 helm list 可以查看当前部署的 release, 这时候我们可以看到部署的版本变成了 2 (最初是1).

-> % helm ls
NAME    REVISION        UPDATED                         STATUS          CHART           NAMESPACE
mysql   1               Sat Oct  6 15:44:25 2018        DEPLOYED        mysql-0.3.0     default

如果当前的更新有误, 可以回退到之前的版本, 语法是 helm rollback [RELEASE] [REVISION]

管理 repo

helm repo list 列出当前添加的 repo

$ helm repo list
NAME            URL
stable          https://kubernetes-charts.storage.googleapis.com
local           http://localhost:8879/charts
mumoshu         https://mumoshu.github.io/charts

添加新的 repo

$ helm repo add dev https://example.com/dev-charts

基本使用

参考

  1. https://docs.helm.sh/
  2. https://ezmo.me/2017/09/24/helm-quick-toturial/
  3. https://help.aliyun.com/document_detail/58587.html
  4. https://johng.cn/helm-brief/
  5. https://www.lixf.io/2019/06/13/k8s-docker-images-mirrors/

kubernetes 初探——部署有状态服务

为了部署我们自己的应用, 首先需要把基础设施部署上去, 其中数据库就占了大头. 有人说数据库等应用不是和容器化部署, 但是也有人认为所有的应用都适合容器化部署. 在这里我们不讨论这些观点,仅以部署 MySQL 为例说明一下如何在 K8S 上部署有状态服务。

相关概念

  • PersistentVolume(PV) 是集群之中的一块网络存储。跟 Node 一样,也是集群的资源。PV 跟 Volume 类似,不过会有独立于 Pod 的生命周期。这一 API 对象包含了存储的实现细节,例如 NFS、iSCSI 或者其他的云提供商的存储系统。
  • PersistentVolumeClaim (PVC) 是用户的一个请求。他跟 Pod 类似。Pod 消费 Node 的资源,PVC 消费 PV 的资源。Pod 能够申请特定的资源(CPU 和 内存);Claim 能够请求特定的尺寸和访问模式(例如可以加载一个读写,以及多个只读实例)
  • Stateful Set. Deployment 是无状态的服务,而 StatefulSets 旨在与有状态的应用及分布式系统一起使用。
  • ConfigMap 用来保存非密码的配置. configmap 可以以配置文件或者环境变量等方式挂在到 pod 中
  • Secret 用来保存密码等私密数据
  • Init Container 用于初始化的容器. 有点类似于 docker build 的过程

动态 PV vs 静态 PV

使用 Deployment PVC 还是 Stateful Set

可以看出我们即可以使用普通的 Deployment + PVC 来部署 MySQL, 也可以使用 Stateful Set 来部署, 那么哪种方式更好呢?

个人理解:

  • 对于需要使用挂载一定资源的,使用 PVC 就好了,甚至只需要只读挂载就好。
  • 对于强状态依赖的服务,比如数据库,肯定要使用 PVC

Stack Overflow 上的一个问题[2]也很值得参考.

MySQL 主从集群

本文中我们要部署一个一主多从的 MySQL 集群. 关于一主多从的优点不是本文的重点, 这里就不多说了, 可以参考下面:

  1. 扩容解决方案:在多个slave之间扩展负载以提高性能。在这种模式下,所有的写入和更新操作都必须在主服务器上进行。然而,读取操作通过slave镜像。该模型可以提高写入操作的性能,同时,也能够通过增加slave的节点数量,从而显著地提升读取速度。
  2. 数据安全:数据从master被复制到slave,并且slave可以暂停复制过程。因此,可以在不损坏master的情况下,在slave上运行备份服务。
  3. 分析:现场数据可以在master上创建,而对信息的分析可以在slave进行,而不影响master的性能。
  4. 远程数据分发:可以使用复制为远程站点创建本地数据的副本,而不必一直通过访问master。

参考

  1. 使用 PVC 和 Deployment 部署单实例 MySQL 集群
  2. https://stackoverflow.com/questions/41732819/why-statefulsets-cant-a-stateless-pod-use-persistent-volumes
  3. 使用普通 Deployment 部署单节点 mysql
  4. https://kubernetes.io/cn/docs/tutorials/stateful-application/basic-stateful-set/
  5. 如何使用 ConfigMap
  6. Secret 文档
  7. https://stackoverflow.com/questions/41583672/kubernetes-deployments-vs-statefulsets
  8. 阿里云挂载 OSS Volume
  9. https://jimmysong.io/posts/kubernetes-persistent-volume/
  10. https://kubernetes.io/docs/concepts/storage/volumes/

kubernetes 初探——部署无状态应用

kubernetes 架构图

  • Master. 用于控制整个集群部署的机器,为了高可用,可以使用多台,一般至少三台为宜。
  • Node. 工作节点,用于部署服务。一台机器可以既是 Master 也是 Worker,当然最好 Master 不要做 Worker。
  • Pod. k8s 部署的最小单元,一个 Pod 中可能包含多个 container. Pod 随时可能挂掉,也可能被替换。
  • Label. Pod 的标签,可以通过这些标签(组合)来选择对应的 Pod。
  • Replica Set. 作为一个高可用的系统,每个服务一般来说可能有多个 Pod. Replication Set 用来创建并保证有足够的 Pod 副本。RS 的名字总是 <Deployment 的名字>-<pod template 的 hash 值> 格式的。
  • Deployment. 用户一般来说不会直接创建 Pod, 而是创建一个 Deployment 来部署服务。(在老版本中是创建 RC)
  • Namespace. 命名空间,默认情况下会有 kube-system 和 default 两个命名空间,kube-system 存放的是 k8s 系统的 pod 等资源,而用户部署的资源会在 default 命名空间中。
  • PersistendVolume. 如果把 Node 理解为抽象的 CPU 和内存资源,那么 PV 就可以理解为抽象的硬盘资源。我们通过 Pod 来使用 Node,因此我们也不直接使用 PV,而是通过 PersistentVolumeClaim 来使用 PV。
  • PersistentVolumeClaim. 存储声明,用来声明需要使用的存储资源。
  • Stateful Set. Deployment 对应的部署语义上没有状态的,而 StatefulSet 会充分运用 PV 和 PVC 实现 Pod 重启之间的状态保持。典型应用场景是数据库。
  • Label 和 Selector. K8S 中的资源全部都通过 Label 来标识的选择。

Deployment

deployment 是使用 k8s 部署服务直接操作的概念。其他的概念往往都是通过 deployment 来间接使用的,因此理解 deployment 至关重要。

一个典型的 deployment 配置文件如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

deployment 的配置可以发生改变,如果只是 replica 的数目发生了改变,那么这只是一个简单的扩容或者缩容操作,k8s 只会简单的打开或者杀死新的 Pod。如果镜像、命令等参数发生了改变,那么 K8S 会把这次操作视为升级,也就是开始一个 RollOut 操作,创建新的 ReplicaSet。在这个过程中,如果 deployment 中的 spec 指定了保留历史 revision 的次数大于零,那么原有的 ReplicaSet 不会被删除,只是会被 Scale 到 0 而已,方便回滚。

文档:

Note: a Deployment’s rollout is triggered if and only if the Deployment’s pod template (i.e. .spec.template) is changed, e.g. updating labels or container images of the template. Other updates, such as scaling the Deployment, will not trigger a rollout.

https://stackoverflow.com/questions/42561791/right-way-to-update-deployments-on-kubernetes

  1. deployment 和 pod 的区别
  2. Kubernetes 基础概念
  3. 客户端和服务端服务发现
  4. kubernetes 命令表
  5. Kubernetes 之 kubectl 常用命令使用指南:1: 创建和删除
  6. Kubernetes 之 kubectl 常用命令
  7. Kubernetes 基本概念以及术语
  8. kubectl create 和 apply 的区别
  9. https://stackoverflow.com/questions/42561791/right-way-to-update-deployments-on-kubernetes
  10. https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
  11. K8S YAML 文件基础
  12. NodePort/LB/Ingress 三种方式的对比
  13. https://kubernetes.io/docs/tasks/access-application-cluster/service-access-application-cluster/

kubernetes 初探——日志收集

在 K8S 中,默认情况下,日志分散在每个不同的 Pod, 可以使用 kubectl logs 命令查看,但是当 Pod 被删除之后,就无法查看该 Pod 的日志了,所以需要一种永久性的保存方式。

Grafana 公司推出的 Loki 看起来不错,完全为 Kubernetes 设计,直接和 grafana 集成。

kubernetes 初探——部署集群

随着 docker cloud 的关闭,容器的编排工具之争似乎已经结束了,Docker Swarm 算是完了,Kubernetes 笑到了最后。然而 k8s 的组件众多,因此部署起来也很麻烦。为此,网上有不少的网上有不少的部署教程和脚本,包括但不限于:

  • kubesaz
  • minikube
  • kubespray
  • rke
  • kubernetes: the hard way

本文基于 ubuntu 18.04. CentOS 上好多默认设置都需要修改,因此建议大家基于 Ubuntu 部署 k8s。

使用 kubespray 安装 k8s

(零) 假设我们要在三台机器上安装,另外一台机器作为控制节点。其中每台都作为工作节点,两台作为 master 节点。

IP | 角色
————|———————–
10.4.17.165 | 控制节点,不参与 k8s 集群
10.4.17.167 | master, node
10.4.17.168 | master, node
10.4.17.169 | node

(一) 下载 kubespray 安装包,这里我们使用最新版 (2018.10), 可能需要安装 python3, 如果没有安装的话

VERSION=2.7.0

# download kubespray
wget https://github.com/kubernetes-incubator/kubespray/archive/v${VERSION}.tar.gz
tar xzf v${VERSION}.tar.gz

# install dependencies
pip3 install -r kubespray-${VERSION}/requirements.txt

(二) 生成部署的 hosts.ini

kubespray 中有一个脚本叫做 inventory_builder 用来生成部署的 hosts.ini

cd kubespray-v${VERSION}
cp -r inventory/sample inventory/mycluster
declare -a IPS=(10.4.17.167 10.4.17.168 10.4.17.169)
CONFIG_FILE=inventory/mycluster/hosts.ini python3 contrib/inventory_builder/inventory.py ${IPS[@]}

生成之后,可以查看生成的文件

cat inventory/mycluster/host.ini

[k8s-cluster:children]
kube-master·▸   ·
kube-node·▸ ·

[all]
node1 ▸  ansible_host=10.4.17.167 ip=10.4.17.167
node2 ▸  ansible_host=10.4.17.168 ip=10.4.17.168
node3 ▸  ansible_host=10.4.17.169 ip=10.4.17.169

[kube-master]
node1·▸ ·
node2·▸ ·

[kube-node]
node1·▸ ·
node2·▸ ·
node3·▸ ·

[etcd]
node1·▸ ·
node2·▸ ·
node3·▸ ·

[calico-rr]

[vault]
node1·▸ ·
node2·▸ ·
node3·▸ ·

(三) 修改一些配置

代理:

由于众所周知的原因,k8s 依赖的 gcr.io 在中国大陆范围内无法访问,我们可以使用代理访问,关于如何搭建代理超出了本文的范围。
假设我们的代理是 http://proxy.com:10086, 修改 inventory/mycluster/group_vars/all/all.yml 文件,设置 httpproxy 和 httpsproxy 两个变量。

下载 kubectl 到本机:

设置 kubectllocalhost 和 kubeconfiglocalhost 两个变量为 true. 安装完成后会在本机安装 kubectl, 并且可以使用 inventory/mycluster/artifacts/admin.conf 使用 kubectl.

(四) 部署

这里我们需要使用 tiger 用户,这个用户需要满足如下条件:

  1. 可以无密码远程登录
  2. 在远程主机上具有无密码 sudo 权限
ansible-playbook -i inventory/mycluster/hosts.ini cluster.yml --become --user tiger -v

大概过十几分钟就部署好了

(五) 验证

cd inventory/mycluster/artifacts
./kubectl.sh get nodes

NAME      STATUS    ROLES         AGE       VERSION
node1     Ready     master,node   1d        v1.11.3
node2     Ready     master,node   1d        v1.11.3
node3     Ready     node          1d        v1.11.3

参考

  1. HN 上关于 Docker Cloud 关闭的讨论
  2. 使用 Kubespray 部署生产可用的 Kubernetes 集群

rabbitmq 教程

更新:弃坑了,rabbitmq 在我这里总是崩溃,实在没法正常使用

评估了几款 Message Queue,发现还是 rabbitmq 比较简单一些,各种特性也支持地很好。网上好多教程说“rabbitmq 非常重量级,适合企业应用开发”,这些话可以说是人云亦云,瞎扯了。实际上 rabbitmq 采用 erlang 开发,不光性能强大,而且从操作和运维上来说都是非常轻量级的。

基础概念

rabbitmq 实现的是 AMQP 0.9.1 协议,其中重要概念有:

  • producer:生产者,生产消息
  • consumer:消费者,消费消息
  • routing-key: 每个消息中决定消息如何分发的参数
  • exchange:类似路由,消息实际发送给 exchange,可以指定几种不同的分发算法,然后用 routing-key 作为参数计算出该发送到哪个队列中,一个exchange 可以和一个或者多个 queue 绑定,exchange 有如下几种分发算法
    • direct,直接按照 routing-key 和 queue 名字匹配
    • fan-out,发送到所有绑定的 queue 中
    • topic,利用 routing-key 和 queue 的名字模式匹配
  • queue:缓冲消息,需要和 exchange 绑定
  • binding:指的是 exchange 和 queue 之间的绑定关系

安装

Ubuntu:

sudo apt-get install rabbitmq-server

Python 客户端 pika

pip install pika

基础使用

和其他一些队列不一样的是,rabbitmq 的队列需要显式创建,不能直接发消息过去生成。可以使用 sudo rabbitmqctl list_queues 命令查看已有的队列。

下面是实现一个生产者,多个消费者的关系,如图所示:

生产者

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
channel.queue_declare(queue="hello", durable=True)  # 声明一个队列,rabbitmq 中的队列必须首先创建才能使用

# 发送消息需要指明发送到的 exchange,留空表示默认 exchange
# 默认的 exchange 会根据 routing-key 把消息发到对应的队列中
channel.basic_publish(exchange="",
                      routing_key="hello",
                      body="Hello World!",  # 消息体
                      properties=pika.BasicProperties(
                         delivery_mode = 2,  # AMQP 定义的,其中 1 代表不要持久化,2 代表需要持久化
                      ))
print(" [x] Sent "Hello World!"")

# 最后关闭链接
connection.close()

消费者

消费者通过注册处理函数,来消费消息,可以同时使用多个消费者消费同一个队列。

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host="localhost"))
channel = connection.channel()


channel.queue_declare(queue="hello", durable=True)

def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    ch.basic_ack(delivery_tag = method.delivery_tag)

channel.basic_qos(prefetch_count=1)  # 最多有一个消息没有 ack
channel.basic_consume(callback,
                      queue="hello",
                      no_ack=False)  # 默认情况加就是 False,也就是需要 ack

print(" [*] Waiting for messages. To exit press CTRL+C")
channel.start_consuming()

可以直接使用多个消费者来消费同一个队列,默认情况下 rabbitmq 采用了 round robin 的算法,也就是消息会依次发送给每一个消费者。

如果没有 ack 的话,rabbitmq 的内存最终可能会占满

使用其他的 exchange

rabbitmq 中默认的 exchange 是 direct exchange,也就是直接把收到的消息放到 routing key 对应的队列中。rabbitmq 还支持不少其他的类型,可以看文章开始的讨论。

下面的例子通过使用一个 fanout 类型的 exchange 来实现消息发送给所有消费者。

#!/usr/bin/env python
import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters(host="localhost"))
channel = connection.channel()

# 声明一个 fanout 类型的 exchange,名字为 logs
channel.exchange_declare(exchange="logs",
                         exchange_type="fanout")

message = " ".join(sys.argv[1:]) or "info: Hello World!"
channel.basic_publish(exchange="logs",
                      routing_key="",
                      body=message)
print(" [x] Sent %r" % message)
connection.close()

消费者

Exchange 需要和 queue 绑定才会发送消息,否则会直接丢掉。
queue 需要和 exchange 绑定之后才能够接收到消息,而所有的 queue 默认已经是和默认 exchange 绑定的,所以在上一个例子中并没有使用绑定。

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host="localhost"))
channel = connection.channel()

channel.exchange_declare(exchange="logs",
                         exchange_type="fanout")

# 声明一个临时的私有 queue
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

# 绑定 queue 到刚刚声明的 exchange
channel.queue_bind(exchange="logs",
                   queue=queue_name)

print(" [*] Waiting for logs. To exit press CTRL+C")

def callback(ch, method, properties, body):
    print(" [x] %r" % body)

channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=True)

channel.start_consuming()

常见问题

在一个循环中发送消息,为什么有时候会提示 Channel Closed?

使用 BlockingConnection 需要手动管理心跳,如果超过心跳时间就会被关闭链接。常见的错误包括使用了 time.sleep 导致长时间没有 publish 消息,从而链接被关闭。

可以通过单独开一个心跳线程的方法,或者使用 connction.sleep。当然使用 connction.sleep 无法避免本身操作时长超过了心跳时间的情况。

channel 和 connection 的区别?

Connection 表示的是到 rabbitmq broker 的一个物理连接,一般一个程序使用一个链接,或者使用一个连接池,可以使用心跳来维护一个链接,理论上应该在多个线程之间分享,很遗憾 python 的客户端 pika 并不是线程安全的。

而channel 则应该是短时效的,在每个线程内部创建,不是线程安全的。

  1. https://stackoverflow.com/questions/18418936/rabbitmq-and-relationship-between-channel-and-connection
  2. https://www.rabbitmq.com/tutorials/amqp-concepts.html

如果客户端重启,之前的匿名队列会被删除吗?如果没有别删除,还能连接上之前的匿名队列吗?如果连不上是不是消息就都丢了?

To be answered

UI管理工具

在向队列中发消息的过程中,尤其是在学习或者排查错误的时候,可以通过 rabbitmq 的管理工具来查看当前消息队列中的消息。

首先,激活管理工具插件:

rabbitmq-plugins enable rabbitmq_management

然后添加用户

rabbitmqctl add_user username password
rabbitmqctl set_user_tags username administrator
rabbitmqctl set_permissions -p / username ".*" ".*" ".*"

然后可以打开:http://server-name:15672/ 查看,使用刚刚设置的密码登录

参考:

  1. http://www.rabbitmq.com/management.html
  2. https://www.rabbitmq.com/tutorials/tutorial-three-python.html
  3. https://github.com/pika/pika/issues/196

技术选型的技巧

总结一下后端常用的工具和蕴含的算法,应该把 GitHub 5000 star 以上的项目都看一下,同类的工具只了解一个就够了,不要研究重复的知识。

不要魔改原系统

所以我们的建议是不要改动原系统,而是要开发辅助系统:监控,报警,负载均衡,管理等。以 Redis 为例,如果我们想增加集群功能,不要去改动 Redis 本身的实现,而是增加一个 proxy 层来实现,Twitter 的 Twemproxy 就是这样做的,而 Redis 到了 3.0 后本身提供了集群功能,原有的方案简单切换到 Redis3.0 即可。详细可参考 (http://www.cnblogs.com/gomysql/p/4413922.html)

如果实在想改到原有系统,怎么办呢?我们的建议是直接给开源项目提需求或者 bug,但弊端就是响应比较缓慢,这个就要看业务紧急程度了,如果实在太急那就只能自己改了,不过不是太急,建议做好备份或者应急手段即可。

所以,如果你有钱有人有时间,投入人力去重复发明完美符合自己业务特点的轮子也是很好的选择!毕竟,土豪们(BAT…… 等)很多都是这样做的,否则的话我们也就没有那么多好用的开源项目了 🙂

魔改系统的另一个不好是员工的不满。对于员工来说,自然希望能够在简历上写上一些通用的技能,而使用公司内部工具的化,对员工的发展也不利。

来源:https://book.douban.com/review/6456359/

突然想起来我们之前一个经验比较丰富的同事告诉我,他学习的方法就是一件事情先找到方法给干掉,先知道怎么用,再系统的看书学习,借此和大家分享。

不要选择过于小众的技术

如果你是你们新用户最大的用户,那么你遇到的问题将会是最大的

Maturity = (Blood + Sweat) / Complexity

Choose Boring Technology

同一类的技术不要引入重复组件。