标题写出来后发现覆盖面有点大,其实要说的只是字面意义上的一点学习小结:

数据库优化:
水平分库,水平分表,使各个库/表的结构相同,但内容不同
垂直分库,垂直分表,使各个库/表的结构不同,且内容不同
库的结构可以理解为包含了哪些表
表的结构可以理解为包含了哪些字段
在垂直拆分的基础上,可以进一步水平拆分

分布式优化:
水平扩展,增加更多节点以达到整体性能增强
垂直扩展,增强单机配置以达到单点性能增强,进而达到整体性能增强
水平扩展优点更多,使用得当的话,对整个系统的可用性,负载均衡都有益处

部分摘录自官方中文文档,python 版本 3.7.4

注意概念区分:生成器函数,生成器,协程函数,协程,异步生成器函数,异步生成器

主要是学习笔记,没有进行过多整理

  • 使用 async def 语法定义的函数总是为协程函数,即使它们不包含 await 或 async 关键字,另外 await,async for 以及 async with 只能在协程函数体中使用(注:以普通函数调用方式调用协程函数时,将返回协程对象,而不是运行协程)

  • 在一个函数体内使用 yield 表达式会使这个函数变成一个生成器,并且在一个 async def 定义的函数体(注:协程函数)内使用 yield 表达式会让协程函数变成异步的生成器(注:以普通函数调用方式调用生成器函数时,将返回生成器对象,而不是运行生成器;以普通函数调用方式调用异步生成器函数时,将返回异步生成器对象,而不是运行异步生成器)

  • 生成器函数与协程(注:函数)非常相似,它们 yield 多次,它们具有多个入口点,并且它们的执行可以被挂起。唯一的区别是生成器函数不能控制在它在 yield 后交给哪里继续执行,控制权总是转移到生成器的调用者

  • 当使用 yield from 时,它会将所提供的表达式视为一个子迭代器,这个子迭代器产生的所有值都直接被传递给当前生成器方法的调用者

  • 启动一个生成器的方法有两种,注意,这两种调用都有返回值,返回的是生成器 yield 的值:

    • 使用内建的 next() 函数,继续使用 next() 函数将继续运行生成器
    • 使用生成器的 send() 方法,但启动时必须传参 None,继续调用 send() 方法将继续运行生成器,此时可以向生成器传入任意值
  • 启动一个协程的方法:导入 asyncio 包,使用 asyncio.run() 函数执行一个协程,注意,需要传入协程对象作为参数,而不是协程函数

  • 注意,await 语句返回指定协程 return 的值(与生成器的 yeild 有区别)

  • 如果只有一个协程在运行的话,代码执行流程与普通函数一样,因为协程函数中的 await <指定协程> 语句将会挂起(阻塞)当前协程,去执行 await 语句指定的协程,直到指定协程执行结束返回后才恢复当前协程

  • 可以使用 asyncio.gather() 函数并发执行多个协程

如题,解决方法:

  1. 安装 sof-firmware
    1
    sudo pacman -S sof-firmware
  2. 创建两个文件:
    1
    2
    sudo touch /etc/alsa/state-daemon.conf
    sudo touch /var/lib/alsa/asound.state
  3. 重启之后应该就能识别到声卡了
  4. 如果没有声音,执行 alsamixer,将声卡取消静音,具体方法可以看: https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture#Unmuting_the_channels

前段时间给两台机器装了 Manjaro,公司台式主机和 Redmi G 笔记本,使用的桌面环境是 KDE 发现两台机器都不能正常识别声音设备,笔记本是因为直接识别不到声卡,这个问题下一篇文章说一下解决方法,这里先说台式主机的问题。

使用的扬声器其实就是个 3.5 毫米的耳机,在给这台机器重装之前使用的是 deepin 系统,这个耳机是可以正常工作的(虽然不常用,但印象里是可以工作的),但是在 Manjaro 里 KDE 提示找不到声音设备,经过测试当把耳机插入主机后面的插口时是可以工作的,这也说明系统是可以识别到声卡的,谷歌了一圈发现可以给声卡驱动添加启动参数针对一些设备的兼容。这台机器的声卡是 ALC887,可以通过执行一下命令查看开机日志,并搜索 audio 来找出声卡型号:

1
sudo journalctl -xb

然后执行以下命令可以查看内核为这个声卡加载的驱动:

1
2
3
4
5
6
7
8
# lspci -v
00:1b.0 Audio device: Intel Corporation 8 Series/C220 Series Chipset High Definition Audio Controller (rev 05)
Subsystem: Gigabyte Technology Co., Ltd Device a182
Flags: bus master, fast devsel, latency 0, IRQ 31
Memory at f7d10000 (64-bit, non-prefetchable) [size=16K]
Capabilities: <access denied>
Kernel driver in use: snd_hda_intel
Kernel modules: snd_hda_intel

可以发现使用的驱动是 snd_hda_intel,在内核 alsa 相关文档中可以找到有哪些选项:

https://www.kernel.org/doc/html/v5.7/sound/hd-audio/models.html

按照声卡型号搜索,找到对应的选项:

https://www.kernel.org/doc/html/v5.7/sound/hd-audio/models.html#alc88x-898-1150-1220

之后编辑 /etc/modprobe.d/alsa-base.conf 文件(没有则创建),添加以下内容:

阅读全文 »

mysql 索引

学习了《MySQL 是怎样运行的:从根儿上理解 MySQL》中的索引一节,收获颇丰,总结如下。

innodb 索引(组织结构 b+ 树)

用户记录 -> 用户记录数据页-> 目录项记录 -> 目录项记录数据页 -> 更大范围目录项记录 -> 更大范围目录项记录数据页 -> 更大范围…

  1. 用户记录数据页 中包含针对 用户记录 的目录,称为 页目录,用来使用二分法快速查找 用户记录
  2. 目录项记录数据页 是针对 用户记录数据页 的目录,也包含一个 页目录,但用来使用二分法快速查找 目录项记录
  3. 一个 用户记录数据页 对应多个 用户记录
  4. 一个 用户记录数据页 对应一个 目录项记录
  5. 一个 目录项记录数据页 对应多个 目录项记录
  6. 一个 目录项记录数据页 对应一个 更大范围目录项记录

聚簇索引

以上述结构组织数据,且存储了所有 完整 用户记录的索引,一般是主键索引

二级索引

以上述结构组织数据,但数据不存储完整用户记录,仅存储索引列 + 主键列的值,一般是用户自己建立的索引。这里存储主键的原因是用来使用这个主键进行 回表,去聚簇索引中取出该索引列对应的完整用户记录,因为会查询两次索引,所以二级索引命名由此而来,除聚簇索引外都是二级索引,联合(多列)索引也属于二级索引的一种

MyISAM:

阅读全文 »

获取建表语句:

1
SHOW CREATE TABLE table_name

获取表结构:

1
2
3
# DESC 是 DESCRIBE 的缩写
DESC table_name
SHOW COLUMNS FROM table_name

筛选字段:

1
2
3
# field_name 可以包括通配符
DESC table_name "field_name"
SHOW COLUMNS FROM table_name LIKE "field_name"

另外,经过测试,SHOW COLUMNS FROM 语句除了可以使用 LIKE 关键字,还可以使用 WHERE 子句,但 DESCRIBE 语句不支持。

这个问题网上众说纷纭,有的答案不完全正确,有的答案没有解释清楚。

这里先说我认为正确的答案:

如果学习过 cpp 的话,说传值或者传引用都不准确,直接理解为传地址(指针)就好了,不管可变对象还是不可变对象都是传地址。

详细解释,在函数内:

  • 对传入参数的赋值操作,是创建新的对象,可以理解为声明新的变量,自然不会影响到函数外变量
  • 对传入参数所指对象的修改操作,如 list 的 append,由于是指针,因此修改了函数外变量,注意在 python 中不可变对象类型是不包含可以修改对象的接口的,即便有些接口看起来像修改了,也是返回了新的对象,而不是对原对象的修改,即不是原地修改
  • 这也解释了当传递复杂类型参数:a = tuple(b = list(), 1, 2, 3) 这种数据时,虽然 a 是不可变类型,但通过 a[0].append() 依然可以成功修改 b,也意味着修改了 a,且函数外变量会也会被修改的原因

综上所述,也可以理解为传引用,但要注意,这里的“引用”二字是广义的,不要狭义得理解为是 cpp 中的引用,两者是不同的,在 cpp 中对函数内传入的引用参数执行赋值操作,将会影响到函数外的变量。

先说环境:
两节点 k8s 集群,一台 master,k8s 版本为 1.18.1,所使用的 dashboard 版本为 v2.0.0-rc7

dashboard 安装方法直接按照官网所说的执行即可:

1
2
kubectl delete ns kubernetes-dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc7/aio/deploy/recommended.yaml

现在 dashboard 已经部署好了,问题是如何访问 dashboard 服务,首先新版的 dashboard 将默认权限控制到了最小,只够 dashboard 部署,要想正常访问 dashboard 服务需要按照下面这个官方文档对其进行授权和创建管理员账户:
https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md

如果不想细看,可以直接将如下代码保存至 dashboard-admin.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard

然后执行:

1
kubectl apply -f dashboard-admin.yaml

接着获取创建的 admin 账户的 token:

1
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
阅读全文 »

由于在 bashrc 中配置了自动 run/attach tmux,因此在 vscode 内启动终端时也会找 tmux,如果想避免这种情况或者类似的情况可以通过修改 vscode 的配置文件,添加自定义环境变量,然后在 bashrc 里进行判断,比如在 vscode 的配置文件中添加如下内容:

1
2
3
4
5
6
7
// NOTE: 在 deepin linux bash 下经过测试发现,不能使用 VSCODE_ 开头的名字作为变量,否则无效
"terminal.integrated.env.linux": {
"IS_VSCODE_INTEGRATED_TERMINAL": "1"
},
"terminal.integrated.env.osx": {
"IS_VSCODE_INTEGRATED_TERMINAL": "1"
},

表示在 linux/osx 下的 vscode 里,为终端设置值为 1 的环境变量: IS_VSCODE_INTEGRATED_TERMINAL

然后在 bashrc 文件中进行检测,如果存在此变量则不启动 tmux:

1
2
3
4
5
6
7
if [[ -z $IS_VSCODE_INTEGRATED_TERMINAL ]]; then
which tmux > /dev/null 2>&1\
&& [[ -z "$TMUX" ]]\
&& { if ! tmux a; then exec tmux; fi; }
else
echo "-> disabled tmux <-"
fi

首先:

1
2
3
4
5
6
# 官方仓库:
https://github.com/kubernetes/minikube
# 官方安装教程:
https://kubernetes.io/docs/tasks/tools/install-minikube/
# 官方使用教程:
https://kubernetes.io/zh/docs/setup/learning-environment/minikube/

安装过程比较省心,没出什么意外就成功了,在执行: minikube start 时一直报错,无法成功启动环境,主要原因自然还是因为 GFW 的问题。

可是我挂上代理(proxychains 命令无效,我用的 http_proxy && https_proxy)依然起不来,使用如下命令可以将日志打印到终端上:

1
minikube start --logtostderr

经过分析后发现失败原因是因为有一个 docker 镜像 gcr.io/k8s-minikube/kicbase:v0.0.8 pull 不下来:

1
2
3
4
5
6
7
8
9
10
11
Pulling base image ...
cache.go:104] Beginning downloading kic artifacts
preload.go:81] Checking if preload exists for k8s version v1.18.0 and runtime docker
preload.go:97] Found local preload: /home/ri/.minikube/cache/preloaded-tarball/preloaded-images-k8s-v2-v1.18.0-docker-overlay2-amd64.tar.lz4
cache.go:46] Caching tarball of preloaded images
preload.go:123] Found /home/ri/.minikube/cache/preloaded-tarball/preloaded-images-k8s-v2-v1.18.0-docker-overlay2-amd64.tar.lz4 in cache, skipping download
cache.go:49] Finished downloading the preloaded tar for v1.18.0 on docker
cache.go:106] Downloading gcr.io/k8s-minikube/kicbase:v0.0.8@sha256:2f3380ebf1bb0c75b0b47160fd4e61b7b8fef0f1f32f9def108d3eada50a7a81 to local daemon
image.go:84] Writing gcr.io/k8s-minikube/kicbase:v0.0.8@sha256:2f3380ebf1bb0c75b0b47160fd4e61b7b8fef0f1f32f9def108d3eada50a7a81 to local daemon
profile.go:138] Saving config to /home/ri/.minikube/profiles/minikube/config.json ...
lock.go:35] WriteFile acquiring /home/ri/.minikube/profiles/minikube/config.json: {Name:mk3e177ff84a9b80716918e458a1d55c30d5128d Clock:{} Delay:500ms Timeout:1m0s Cancel:<nil>}

后面还有一处报错:

1
output: Unable to find image 'gcr.io/k8s-minikube/kicbase:v0.0.8@sha256:2f3380ebf1bb0c75b0b47160fd4e61b7b8fef0f1f32f9def108d3eada50a7a81' locally

这就很奇怪,因为我执行 docker images 是可以看到这个镜像的:gcr.io/k8s-minikube/kicbase:v0.0.8,起初我以为是镜像 pull 的不完整,找了台境外机器按照同样的流程执行了下,一切正常,pull 下来的镜像的 image id 和大小跟我本地是一样的

阅读全文 »