> 一份2021年03月10日的信息流提炼 ### 每天学点运维 #### 完全/增量备份/还原PostgreSQL 原文:[Full/Incremental Backup/Restore PostgreSQL](Full/Incremental Backup/Restore PostgreSQL) ##### 构成 - pg-primary (master): 读写db服务器 - pg-standby (slave):只读db服务器 - 备份仓库 (repository) ##### pgBackRest - [pgBackRest User Guide](https://pgbackrest.org/user-guide.html#installation) - 关于备份 Backup - 完全备份 Full Backup:将数据库群集的全部内容复制到备份中。数据库群集的第一次备份始终是完整备份。pgBackRest总是能够直接还原完整备份。 - 差别备份 Differential Backup:只复制自上次完整备份以来发生变化的数据库群集文件。差分备份和完整备份必须同时有效才能恢复差分备份。 - 增量备份 Incremental Backup:只复制自上次备份以来发生变化的数据库群集文件。由于增量备份只包括自上次备份以来的文件,因此要执行增量备份的还原,所有之前的增量备份、之前的差分备份和之前的完整备份都必须有效。 - 还原 Restore: 将备份复制到系统中,并在该系统中作为实时数据库群集启动的行为。 - 利用**Ansible playbook**来安装`pgbackrest` - 为了实现服务器之间的通信,`pgBackRest`需要无密码SSH登录。 ```yaml - hosts: repository tasks: - name: Create repository host key pair - command: ssh-keygen -f /home/pgbackrest/.ssh/id_rsa -t rsa -b 4096 -N "" args: creates: /home/pgbackrest/.ssh/id_rsa - name: Copy repository public key to pg-primary and pg-standby command: cat /home/pgbackrest/.ssh/id_rsa.pub register: repo_ssh_keys ``` ### 每天学点Golang 原文:[Golang程序设计——数据容器](https://juejin.cn/post/6937570389732098055) #### 数组 - 声明数组需要同时指定长度和数据类型。 - 可以对数组进行写入、读取、删除、遍历等操作。 ```go var a [5]int // 初始化, 最后1个元素为int类型零值(0) var b = [5]int{1, 2, 3, 4} // 数组的遍历 for index, value := range c { fmt.Printf("c[%d]=%d\n", index, value) } ``` #### 切片 - Go语言的数组不支持自动扩容,不支持删除元素,数组是**值类型**,切片是**引用类型**,在向函数传参时切片拥有更好的性能。 - 切片支持取范围操作,新切片和原切片共享底层数组,因此对切片的修改会同时影响两个切片。 - 范围操作符语法如下:a[begin:end],左闭右开区间。 ```go var a = make([]int, 0) // 声明一个大小为0的int类型切片 a = append(a, 1, 2, 3) // 添加三个元素 // 声明一个大小为4的切片,并复制a的元素 var b = make([]int, 4) copy(b, a) // 直接使用值初始化切片并删除第2、3个元素 a = []int{1, 2, 3, 4, 5} a = append(a[:1], a[3:]...) ``` #### 映射 - 映射也叫字典、哈希表,数组和切片是通过数字索引访问的顺序集合,而映射是通过键来访问的**无序集合**。 - 映射在查找方面非常高效,有着O(1)的时间复杂度。 - 映射必须初始化之后才能使用。 ```go // 使用make初始化映射 var a = make(map[string]int) // 使用值初始化映射 var b = map[string]int{ "zhangsan": 18, "lisi": 28, } ``` ### 每天学点前端 #### 关于Svelte与Vue 原文:[我对 Svelte 的看法](https://www.v2ex.com/t/760112) Vue实现 Reactivity 的原理:使用 `defineProperty` 或者 `Proxy`, 在 setter 这一层,当对象的某个成员被赋值的时候,执行更新逻辑。 ```js const reactive = {} Object.defineProperty(reactive, 'a', { set(value) { console.log('a was updated') } }) reactive.a = 'changed' //=> a was updated ``` 这是一种「运行时」的手段,它需要在运行时改变了赋值行为,所以在用 Vue 的时候,你必需把需要 Reactivity 的对象包在 `data` 里,上文的例子用 Vue 需要这么写: ```js const yourData = { data() { return { a: 1, b: 2 } }, computed: { c() { return this.a + this.b } } } const reactive = new Vue(yourData) console.log(reactive.c) //=> 3 reactive.a = 2 console.log(reactive.c) //=> 4 ``` **Svelte**不用 `defineProperty`, 而是在编译时,每当遇到赋值语句,就让它在赋值语句的后面自动加一个调用更新的方法。实际上的实现要更加复杂一些(比如需要把更新放在同一个 microtask 里) 。 ```js let a = 1 let b = 2 let c = a + b function update() { c = a + b } console.log(c) //=> 3 a = 2; update() console.log(c) //=> 4 ``` - 实现 **Reactivity** 的原理都是依赖收集,但 Svelte 是在编译时完成了,Vue 在运行时收集。 - Vue 用了 Virtual DOM, Svelte 在编译时就知道它应该操作哪个 DOM ### 每天学点AI #### 什么是神经网络 原文:(1) [虎嗅 | 什么是神经网络?](https://www.huxiu.com/article/393277.html?f=member_article) (2) [什么是卷积神经网络(CNN)?](https://www.huxiu.com/article/393290.html?f=member_article) (3) [ 两分钟看懂什么是决策树?](https://www.huxiu.com/article/413870.html?) 人脑中有约860亿个神经元(Neural):神经细胞+神经突触。 神经网络中的神经元抽象为节点来存储数字,神经突触被抽象为有权重的连接。 ##### CNN(Convolutional Neural Network)卷积神经网络 在 CNN 的卷积层中,存在着数字矩阵,它们被称为卷积核(Kernel)。原始图片经过输入层后会变为灰度或是 RGB 数值填充的矩阵,将卷积核与图片矩阵对齐,对应格子中的数字相乘后再相加,再将得到的数字填入新矩阵,这就是卷积。 卷积核以一定的距离在图像上移动运算,这被称为步长(Stride),得到的新矩阵能反映图像的部分特征,因此被称为特征图(Feature Map)。它们既是这一层的输出,也是下一层的输入。 对于 CNN 来说,训练就是让网络根据已有的数据和它们的标签,自动确定卷积核中的数字。以拥有 5 个卷积层的 AlexNet 为例,边缘、纹理、组成……以人眼的角度观察,越靠后的卷积层提取出的特征越抽象。 除了卷积层, CNN 还有另外两个重要配件:池化层(Pooling)和全连接层。 池化层能选取图像的主要特征。常用的 Maxpooling 是保留窗口覆盖区域的最大数值,矩阵被池化后,参数会大量减少。 全连接层通常在网络的最后,能将提取到的特征集合在一起,给出图片可能是某种事物的概率。 ##### 决策树 (Decision Tree) 决策树模型非常经典,在机器学习中常被用来分类。构成它的元素是节点和边,节点会根据样本的特征做出判断,边则指示着方向。 - 构造树的基本思路:让熵 (Entropy) 快速降低 - 完美分类=过拟合的问题解决:预剪枝(Pre-Pruning), 后剪枝(Post-Pruning) - > 过拟合(Overfitting) : If we have too many features, the learned hypothesis may fit the training set vey well, but fail to generalize to new examples. > > 简单说就是预测值和样本标签值几乎完全一致的情况 > > [机器学习笔记:过拟合(Overfitting)](https://zhuanlan.zhihu.com/p/138044812) ### 每天学点bash #### 27个简单的给新手的bash建议 原文:[27 Simple Bash Scripting Tips for Beginners](https://betterprogramming.pub/27-simple-bash-scripting-tips-for-beginners-d6764c977546) 代码片段参考附录。 - 清晰的结构 - 给编辑器安装ShellCheck - 提供Usage方法 - 错误消息,Google[ shell style guide](https://google.github.io/styleguide/shellguide.html) 推荐使用方法打印出消息和状态信息 - 方法注释(描述,全局变量,参数,输出,返回) - `set -x` Debug模式 - 检查bash版本 - 用户输入转换大小写,e.g. y/Y → Y - 类三元表达式:`[ $foo -ge $bar ] && baz="Smile!" || baz="Sleep!"` - 字符和数组长度:`str_len=${#string}`, `arr_len=${#array[@]}` - 设置默认值:`${foo-$DEFAULT}`, `${foo=$DEFAULT}` - 获取OS类型,系统自带HTTP Get工具,Python版本 - 获取脚本名和目录:`basename "$0"` , `c=$0 && echo "${c%/*}"` - Bash中的类型提示可以利用`declare`来实现 - 利用变量保存Exit Status - 利用Trap来对应异常退出 - Subshell 和 Exit Status ```bash # 括号会使命令在一个SubShell中运行 no_func1 || ( echo "there is nothing" exit 1 ) echo $? # 大括号不创建子SubShell,exit退出主shell进程,所以它永远不会达到运行echo $? no_func2 || { echo "there is nothing" exit 1 } echo $? ``` ### 其他值得阅读 - 你可以学习所有领域吗?[Could you learn every subject?](https://www.scotthyoung.com/blog/2021/03/08/learn-every-subject/?ck_subscriber_id=739575748) - 知识树(Knowdege Tree)的概念。 - 对自己的知识树进行进度评估。 - 怎样学习 | 学习目的:知识掌握or技能学习?。线上课程(e.g. [MITOPENCOURSEWARE](https://ocw.mit.edu/?)) → 书籍 → 应用 - [虎嗅 | 知乎上市,Reddit换将,知识型社区出路在哪?](https://www.huxiu.com/article/413859.html?) ### 今日收获 - **owner意识** 。所谓 owner 意识,其实就是主动去兜底。 [v2ex | 对程序员的晋升之路有疑问](https://www.v2ex.com/t/759815) - 所有技术岗都是极其容易被替代的,管理岗的人是很难做改动的。 - 成长心态 **growth mindset** > "相信自己的才能可以发展(通过努力工作、良好的策略和他人的投入)的人具有成长的心态。他们往往比那些思维方式比较固定的人(那些认为自己的才能是与生俱来的天赋的人)取得更大的成就"。 -- Carol Dweck ### 附录:snippets - bash scripting tips ```bash # 清晰的结构 #!/usr/bin/env bash ##################################### # Author: Your name # Version: v1.0.0 # Date: 2021-02-20 # Description: This script does this and that. # Usage: myscript ########################### # Global variables ############## # Functions ##################### # Main body ##################### exit 0 # 提供Usage方法 usage(){ # Simple Message echo "Usage: $0 [ -d DAYS ] [ -f FROM_DIR ] [ -t TO_DIR ]" # Full Message with Heredoc cat <&2 } if ! do_something; then err "Unable to do_something" exit 1 fi # 检查用户的bash版本 if ((BASH_VERSINFO[0] < 4)); then printf '%s\n' "Error: This requires Bash v4.0 or higher. You have version $BASH_VERSION." 1>&2 exit 2 fi # 改变大小写 set -x echo -n "Can you say Hello in Japanese?" read -r answer answer=$(echo "$answer" | cut -c 1-1 | tr "[:lower:]" "[:upper:]") if [ "$answer" = Y ] then echo "Wow you are awesome." else echo "Neither can I." fi # 用变量保存 Exit Status test -d /tmp/tmp_dir test_es=$? if [[ ${test_es} -ne 0 ]]; then echo "No dir found. Exiting script!" exit 1 fi ```