0%

0X00 就算只有一节我也要写标题

众所周知Dockerfile是构建Docker镜像的优良方式,而使用Dockerfile构建镜像最重要的就是为数不多的几个命令,而本次的主题COPYADD就是其中两个。我们知道这两个命令都是将文件搞到Docker镜像里用的,那究竟有没有区别,有什么区别呢?

首先我们看一下当前这个目录:

1
2
λ  ~/Workstadion/learn_docker  ls
Dockerfile excited.tar

我们有着么一个Dockerfile,可以看到是基于fedora的一个镜像,并且将目录下的excited.tar放进了创建好的shawn目录中

1
2
3
4
FROM fedora
RUN mkdir shawn
WORKDIR shawn
COPY excited.tar .

我们可以看到工作目录下已经存在了一个excited.tar了,也就意味着我们成功将这个文件搞进去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
λ  ~/Workstadion/learn_docker  docker build . -t wtf ; docker rm learn_docker; docker run --name learn_docker -it wtf bash
Sending build context to Docker daemon 23.04kB
Step 1/4 : FROM fedora
---> e9ed59d2baf7
Step 2/4 : RUN mkdir shawn
---> Using cache
---> 5014855b8533
Step 3/4 : WORKDIR shawn
---> Using cache
---> 82f9d06a4d3c
Step 4/4 : COPY excited.tar .
---> 1bc293d81b33
Successfully built 1bc293d81b33
Successfully tagged wtf:latest
learn_docker
[root@f6a4f34ed504 shawn]# ls -l
total 20
-rw-r--r-- 1 root root 20480 Sep 25 14:15 excited.tar

阅读全文 »

0X00 Redis的分库

使用过MySQL或者类似的数据库都应该知道,一个数据库内部是可以分成多个库的。比如MySQL从上到下是MySQL service -> database -> table -> field,但是一开始使用redis的时候好像是没有database这一层的呢?其实是存在这么一层的,redis默认是存在编号0到15这总共16个库的,每个库除了命名空间不同以外都是相同的。也就是说在编号为0的库里set name shawn之后跑到编号为1的库里get name是拿不到的。

那这么说来这个分库究竟有什么用呢?其实很少用的到,甚至就连redis设计者自己都说搞这个是较蠢的操作。我们日常用到的唯一一处地方就是在测试服务器上,因为一台机器部署了太多服务,而且每个服务又都要用redis所以就每个服务分开使用0~15这些数据库。

因为开一个完整redis实例的资源消耗本身就很小,所以分库这个操作就更显的不太用的到了,毕竟我们完全可以在一台机器上开多个redis实例从而实现相同的效果,而且又方便管理。

不过也还是简单介绍一下好了:/etc/redis.conf文件中的databases参数是设置redis实例具有多少个数据库的,如果真的需要的话可以修改这个参数然后重启redis从而生效。

阅读全文 »

0X00 最常见的两种构建方式

构建Docker镜像的方式并不多,最常用的也就只有:编写Dockerfile和使用docker commit这两种。既然方式分为两种那么肯定是有区别的(废话),那我们来看看吧。

首先来介绍一下这两种构建方式,假设打算使用docker部署我们的服务,那么我们来使用两种方式来构建一下这个镜像吧。

0X01 docker commit

像我们这种新手平时用的比较多的应该就是docker commit xxxxx hub.xxx.xxx/xxx:xxx这种方式了,我们称之为docker commit。这种方式比较好操作,比较好理解,操作也比较容易。如果掌握了git的工作流程,那么使用docker commit方式来构建镜像简直是小菜一碟。

  1. 我们搞一个基础镜像比如fedora,那我们把它搞下来:docker pull fedora
  2. 运行并进入到容器里docker run --name our_container -it fedora /bin/bash,此时shell已经接入到容器里了
  3. 我们来安装吧 dnf install python3然后pip3 install Django 这样就装好了,可以退出docker里的shell了
  4. docker commit -m "安装了Python和Django" our_container our_image:latest这样就将刚刚的容器打包成名为our_image的镜像了
  5. 现在使用docker images就可以看到刚刚打包的our_image
  6. 后面如果还需要更新这个镜像那么就可以继续运行这个docker run --name our_container -it our_image:latest然后更新完了再docker commit -m "balabalabala" our_container our_image:latest打包一层新的上去就好了
阅读全文 »

0X00 前言

不论多初级的后端程序员,只要认可自己是“后端程序员”那最起码也是听过“数据库索引”这个东西的,应该也直到这东西能让数据库变快。但是具体“数据库索引”是个什么东西,怎么用,为什么能让数据库变快可能就不一定清楚了。

这篇博客仅仅是简述了“数据库索引”的最基础内容,不涉及内部原理(其实我也还没搞懂)。阅读了本篇博客可以(也许)搞清楚怎么给一张表添加索引,索引加在哪儿,以及为什么不能给所有字段加索引。

0X01 一个业务场景

假设我们搞了一个电商平台“并夕夕”,现在有超多用户大概几百万,很多人都在我们系统里买了东西,大概下了1000W单。那么我们用来存储订单的表就有大概1000W条数据了,那么我们这个没有进行过任何优化的数据库就已经顶不住了,我们每次在后台查看订单列表的时候一个查询就要快20s,显然是一个接受不了的速度了。

那么我们来看一下这个列表都干了什么:“根据 订单状态(下单待支付/已支付/配送中/已收货/退货中/已完成),订单类型(直接购买/拼单购买/分享白拿)等状态筛选,并取出前20条展示出来”。后台SQL是这个样子的SELECT * FROM bxx_order WHERE order_status = xxx AND order_type = xxx ORDER BY -id LIMIT 20,我们可以看到真正会影响性能的主要就在WHERE子句里的查询条件。接下来我们给这两个字段分别加上索引,查询效率就会高非常非常多。

阅读全文 »

0X00 给一个方法计时

现在我们有一个需求,需要给程序中的一部分方法计时,以监控他们执行完具体用了多久。那么在没有装饰器的情况下我们会写出类似这样的代码:

1
2
3
4
5
6
7
8
9
10
import datetime

def foo():
pass # some code


start = datetime.datetime.now()
foo()
end = datetime.datetime.now()
print((end - start).seconds)

0X01 引入装饰器

如果只是临时给一个方法使用也不是不行,但是如果我们需要监控大量的方法呢?众所周知Python中function也是可以作为参数传递的,那来看一下下面这种写法呢

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
import datetime


def timer(func):
def run_func(): # 方法内部将之前计时的功能封装起来
start = datetime.datetime.now()
result = func() # 得到参数方法的返回值
end = datetime.datetime.now()
print((end - start).seconds)
return result # 将真正的结果返回给调用者

return run_func # 调用内部方法,进行计时


def foo():
pass # some code


def bar():
pass # some code


# 将方法作为参数发送给 timer()
timer(foo)()
timer(bar)()

因为上面timer(foo)返回的结果是一个func,所以后面需要再加一对括号来调用这个方法

这种方法只写了一次计时的逻辑,但是可以给任意一个方法使用,其实这时候def timer(func)已经是装饰器了,下面调用的方法timer(foo)/timer(bar)也是正确的装饰器使用方法。那是不是觉得和常见的装饰器使用不太一样呢?其实常见的@timer用法是Python中提供的一种语法糖。

阅读全文 »