Digest | DB备份方案,2分钟神经网络

323 阅读8分钟

一份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

    • 关于备份 Backup
      • 完全备份 Full Backup:将数据库群集的全部内容复制到备份中。数据库群集的第一次备份始终是完整备份。pgBackRest总是能够直接还原完整备份。
      • 差别备份 Differential Backup:只复制自上次完整备份以来发生变化的数据库群集文件。差分备份和完整备份必须同时有效才能恢复差分备份。
      • 增量备份 Incremental Backup:只复制自上次备份以来发生变化的数据库群集文件。由于增量备份只包括自上次备份以来的文件,因此要执行增量备份的还原,所有之前的增量备份、之前的差分备份和之前的完整备份都必须有效。
  • 还原 Restore: 将备份复制到系统中,并在该系统中作为实时数据库群集启动的行为。

  • 利用Ansible playbook来安装pgbackrest

  • 为了实现服务器之间的通信,pgBackRest需要无密码SSH登录。

    - 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程序设计——数据容器

数组

  • 声明数组需要同时指定长度和数据类型。
  • 可以对数组进行写入、读取、删除、遍历等操作。
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],左闭右开区间。
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)的时间复杂度。
  • 映射必须初始化之后才能使用。
// 使用make初始化映射
var a = make(map[string]int)
// 使用值初始化映射
var b = map[string]int{
  "zhangsan": 18,
  "lisi":     28,
}

每天学点前端

关于Svelte与Vue

原文:我对 Svelte 的看法

Vue实现 Reactivity 的原理:使用 defineProperty 或者 Proxy, 在 setter 这一层,当对象的某个成员被赋值的时候,执行更新逻辑。

const reactive = {}
Object.defineProperty(reactive, 'a', {
  set(value) { console.log('a was updated') }
})
reactive.a = 'changed' //=> a was updated

这是一种「运行时」的手段,它需要在运行时改变了赋值行为,所以在用 Vue 的时候,你必需把需要 Reactivity 的对象包在 data 里,上文的例子用 Vue 需要这么写:

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 里) 。

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) 虎嗅 | 什么是神经网络? (2) 什么是卷积神经网络(CNN)? (3) 两分钟看懂什么是决策树?

人脑中有约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)

每天学点bash

27个简单的给新手的bash建议

原文:27 Simple Bash Scripting Tips for Beginners

代码片段参考附录。

  • 清晰的结构

  • 给编辑器安装ShellCheck

  • 提供Usage方法

  • 错误消息,Google shell style guide 推荐使用方法打印出消息和状态信息

  • 方法注释(描述,全局变量,参数,输出,返回)

  • 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

    # 括号会使命令在一个SubShell中运行
    no_func1 || (
        echo "there is nothing"
        exit 1
    )
    echo $?
    
    # 大括号不创建子SubShell,exit退出主shell进程,所以它永远不会达到运行echo $?
    no_func2 || {
        echo "there is nothing"
        exit 1
    }
    echo $?
    

其他值得阅读

今日收获

  • owner意识 。所谓 owner 意识,其实就是主动去兜底。 v2ex | 对程序员的晋升之路有疑问

    • 所有技术岗都是极其容易被替代的,管理岗的人是很难做改动的。
  • 成长心态 growth mindset

    "相信自己的才能可以发展(通过努力工作、良好的策略和他人的投入)的人具有成长的心态。他们往往比那些思维方式比较固定的人(那些认为自己的才能是与生俱来的天赋的人)取得更大的成就"。 -- Carol Dweck

附录:snippets

  • bash scripting tips
# 清晰的结构

#!/usr/bin/env bash
#####################################
# Author: Your name
# Version: v1.0.0
# Date: 2021-02-20
# Description: This script does this and that.
# Usage: myscript <directory_name> <file_name>
###########################
# 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 <<EOF
my_script_name
Description: Your description.
Usage: movies [flag] or movies [movieToSearch]  
    -u  Update  
    -h  Show the help  
    -v  Get the tool version  
    -d  Show detailed information
Examples:  
    my_script_name something 
    my_script_name anything
EOF
}
while getopts "f:d:t:?h" opt; do
  case $opt in
  f) FROM_DIR=$OPTARG ;;
  d) DAYS=$OPTARG ;;
  t) TO_DIR=$OPTARG ;;
  h | *) usage ;;
  esac
done

# Error Message
err() {
  echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&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

个人博客发布地址:Digest 2021.03.10 | DB备份方案,2分钟神经网络