Shawn's Blog

MySQL 慢查询初步

0X00 IO总是比运算慢 众所周知计算机的IO都要比计算慢很多很多,即时是目前民用的高级SSD:三星970PRO,它的读写速度都要比内存慢上几个数量级,更不要说CPU了。所以软件的IO通常都是瓶颈,很多时候都是CPU等内存,内存等磁盘,磁盘等网络。 那么如何才能提升自己web服务的响应速度呢?通常来说简单的操作有如下两种:换硬盘或者改SQL。 0X01 换硬盘 “这难道不是废话吗?”对呀,这就是废话。当瓶颈出现在数据库的查询上了,那么把正在用的机械硬盘换成固态硬盘当然会提升效率,稍微想想就呢能明白的事情。事实上也是这样的,之前我把同样量级的数据从我们的测试环境搞到我本地,测试环境是企业级HDD,而我本地是三星970EVOPlus的SSD,会发现查询同一个内容就快了好多好多。 那其实这个换硬盘并不是好办法,毕竟不能指望全都用上SSD。而且即使用上SSD了,在查询更复杂或者数据量更多的情况下还是会出现瓶颈。那首先想到的方式就是优化SQL了。 0X02 慢查询…

在 Linux 桌面下活得舒服

0X00 前言 这篇博客的目标读者:正在使用Linux桌面,打算长期继续使用下去的同学(这也就意味着熟悉Linux下的基础操作,理解Linux下的常见概念)。 这里有一个我之前写的“在Linux桌面下存活”可以参考一下。 0X01 颜值就是战斗力 Linux也不都是黑色背景白色字的命令行。 首先要换的就是一套主题和图标,不论是KDE、Gnome还是Xfce都可以在对应的网站找到大量的主题,简单换过图标和主题之后再配合一张好看的壁纸,整个观感立马就好了不少。 KDE: <https://store.kde.org/> Gnome: <https://www.gnome-look.org/> Xfce: <https://www.xfce-look.org/> 然后要换的就是字体了,等宽字体我推荐这几个Hack、Source Code Pro、Cascadia Code都很好看,适合在终端、IDE和编辑器里使用。 最后就是zsh主题,如果使用的是zsh的话推荐使用powerlevel10k这个主题,是由powerlevel9k发展而来的,但是速度比powerlevel9k快好多。…

在 Linux 桌面下存活

0X00 前言 这篇博客的目标读者:有Linux使用基础,打算使用Linux作为桌面系统的人(这也就意味着熟悉Linux下的基础操作,理解Linux下的常见概念)。 注:这篇博客不讨论不对比Linux/Windows/MacOS等不同的操作系统。 0X01 首先选择一个发行版本 众所周知Linux是一个内核,在这个内核基础上有很多发行版本例如:Archlinux、Manjaro、Ubuntu、Deepin、Debian、openSUSE、Fedora等等。那我们首先要选择一个来安装到自己电脑上。 基于我自己的使用体验比较推荐使用的是:Manjaro、Ubuntu、Deepin这三个,他们共同的优点是:适合初次使用Linux桌面的人。 Manjaro 基于Archlinux,滚动更新。该发行版本最大的特点是软件版本紧跟最新,而且由于是滚动更新所以不用像多数系统一样隔一段时间来一次大版本更新。只要按照系统提示进行常规系统升级就可以将整个系统一直保持在最新的状态。…

Dockerfile 中的 COPY 与 ADD 指令

0X00 就算只有一节我也要写标题 众所周知Dockerfile是构建Docker镜像的优良方式,而使用Dockerfile构建镜像最重要的就是为数不多的几个命令,而本次的主题COPY和ADD就是其中两个。我们知道这两个命令都是将文件搞到Docker镜像里用的,那究竟有没有区别,有什么区别呢? 首先我们看一下当前这个目录: 我们有着么一个Dockerfile,可以看到是基于fedora的一个镜像,并且将目录下的excited.tar放进了创建好的shawn目录中 我们可以看到工作目录下已经存在了一个excited.tar了,也就意味着我们成功将这个文件搞进去了。 如果同样的操作用ADD呢?看上去是类似的操作实际上并不是 我们进到容器里可以看到打包文件被拆解了(压缩文件也会被解压) 其实不止这样,ADD 命令还能下载文件:ADD https://too.young/too/simple.pdf /hello就能将文件下载下来并且命名为hello;如果是ADD https://too.young/too/simple.pdf…

Redis入门使用:分库、认证与持久化

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实例从而实现相同的效果,而且又方便管理。…

正确构建 Docker 镜像

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…

关系型数据库索引初步使用

0X00 前言 不论多初级的后端程序员,只要认可自己是“后端程序员”那最起码也是听过“数据库索引”这个东西的,应该也直到这东西能让数据库变快。但是具体“数据库索引”是个什么东西,怎么用,为什么能让数据库变快可能就不一定清楚了。 这篇博客仅仅是简述了“数据库索引”的最基础内容,不涉及内部原理(其实我也还没搞懂)。阅读了本篇博客可以(也许)搞清楚怎么给一张表添加索引,索引加在哪儿,以及为什么不能给所有字段加索引。 0X01 一个业务场景 假设我们搞了一个电商平台“并夕夕”,现在有超多用户大概几百万,很多人都在我们系统里买了东西,大概下了1000W单。那么我们用来存储订单的表就有大概1000W条数据了,那么我们这个没有进行过任何优化的数据库就已经顶不住了,我们每次在后台查看订单列表的时候一个查询就要快20s,显然是一个接受不了的速度了。 那么我们来看一下这个列表都干了什么:“根据 订单状态(下单待支付/已支付/配送中/已收货/退货中/已完成),订单类型(直接购买/拼单购买/分享白拿)等状态筛选,并取出前20条展示出来”。后台SQL是这个样子的SELECT * FROM bxx_order…

Python 装饰器

0X00 给一个方法计时 现在我们有一个需求,需要给程序中的一部分方法计时,以监控他们执行完具体用了多久。那么在没有装饰器的情况下我们会写出类似这样的代码: 0X01 引入装饰器 如果只是临时给一个方法使用也不是不行,但是如果我们需要监控大量的方法呢?众所周知Python中function也是可以作为参数传递的,那来看一下下面这种写法呢 因为上面timer(foo)返回的结果是一个func,所以后面需要再加一对括号来调用这个方法 这种方法只写了一次计时的逻辑,但是可以给任意一个方法使用,其实这时候def timer(func)已经是装饰器了,下面调用的方法timer(foo)/timer(bar)也是正确的装饰器使用方法。那是不是觉得和常见的装饰器使用不太一样呢?其实常见的@timer用法是Python中提供的一种语法糖。 0X02 @语法糖 其实上面的代码就可以直接使用@语法糖了,具体用法是这样:…

Python 中的可迭代对象、迭代器与生成器

0X00 什么是可迭代对象 我们平时用到的list/set/tuples是最常见的可迭代对象,简单判断就是说当可以for item in this_obj的时候this_obj就是可迭代对象。所以不只是list/set/tuples,打开的文件或是Django中的queryset也都是可迭代对象。 使用iter()可以将列表变为一个迭代器,然后使用next方法访问下一个元素。实际上iter(this_obj)方法和next(this_obj)方法分别调用的是this_obj.__iter__()和this_obj.__next__(),所以我们如果想要自己实现迭代器的话就需要实现这两个方法。 0X01 迭代器 那我们来实现实现一个计算斐波纳契数列的迭代器吧。 运行起来: 这里没有中断的判定,如果需要中断的话就抛出一个StopIteration异常就好了,就像这样: 0X02 生成器 生成器是一类特殊的迭代器 ,将我们平时写的这种[i for i in range(100)]列表生成式的方括号换成小括号,就是将结果从列表变成生成器了(i for i in range(100))。…

使用 Django 中的 select_related 和 prefetch_related 优化查询

0X00 前言 没有什么前言,只有一个数据库模型,下面的代码使用这个模型拿来测试。 我们先假设Major表存在10条数据,而Student表存在1万条数据。 0X01 使用select_related 如果我们要得到所有的学生和他们所学专业的名字,那么我们可以轻松写出下面的代码 这样就能得到所有学生姓名和他们所学的专业名了,但是重点在于这次查询其实是一个很低效的查询,因为在Student.objects.all()的时候查询了一次数据库,而且每次访问student.selected_major.name的时候都会再查询一次数据库,基于上述条件这两行代码将会查询10001次数据库,是一个比较夸张的数字了。那么如何用select_related来优化这次查询呢? 其实就是在all()之后添加了select_related('major'),这次就只需要对数据库进行一次查询。在我本地的类似环境下测试结果是不使用select_related消耗的时间是优化后的400%左右。…