0%

数据库

索引是什么

索引(在MySQL中也叫键(key))是存储引擎用于快速查找记录的一种数据结构。索引对于性能拥有至关重要的地位。尤其是当表中的数据量越来越大,索引对于性能的影响愈发重要。反之不恰当的索引对于性能也会急剧下降。

索引是一把双刃剑

索引的优与劣

索引的优点

索引提高数据检索的效率

  • 降低数据库的I/O 成本(将随机IO变为顺序I/O

  • 减少扫描行数

通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

索引的缺点

时间方面

创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加

空间方面

索引需要占物理空间,如果要建立聚簇索引,那么需要的空间就会更大

当对表中的数据进行增加、删除、修改的时索引也要动态的维护,这样就降低了数据的维护速度。

应用方面

锁竞争

索引的类型

索引有很多种类,可以为不同场景提供更好的性能。索引在存储引擎层实现的,故并没有统一的索引标准

不同的存储引擎的索引工作方式也不尽相同

索引分类

按照不同的维度可以区分索引类型

按照物理村粗可以划分为:聚簇索引与二级索引(辅助索引)

按照数据结构可以划分为: B+ Tree、Hash、Full-Text、Geographic Information System等

按照字段个数可以划分为:单列索引和联合索引

按照字段特效可以划分为:主键索引、唯一索引、普通索引、前缀索引

物理顺序与键值的索引逻辑顺序关系

聚集索引:数据行的物理顺序与列值(一般为主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引

非聚集索引(辅助索引):逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引

聚簇索引与非聚簇索引异同

在 InnoDB 里,索引B+ Tree的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引,即将数据存储与索引放到了一块,找到索引也就找到了数据。

而索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引、二级索引。

聚簇索引与非聚簇索引的区别:

  • 非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键(行号)
  • 对于InnoDB来说,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表
    。第一次索引一般是顺序IO,回表的操作属于随机IO。需要回表的次数越多,即随机IO次数越多,我们就越倾向于使用全表扫描 。
  • 通常情况下, 主键索引(聚簇索引)查询只会查一次,而非主键索引(非聚簇索引)需要回表查询多次。当然,如果是覆盖索引的话,查一次即可

注意:

MyISAM无论主键索引还是二级索引都是非聚簇索引

InnoDB的主键索引是聚簇索引,二级索引是非聚簇索引。

存储结构

这里所描述的是索引存储时保存的形式

  • B Tree索引(B-Tree或B+Tree索引)BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是
    MySQL里默认和最常用的索引类型。

  • Hash索引,HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高

  • full index 全文索引,其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引

  • R-Tree索引。RTREE在MySQL很少使用,仅支持geometry数据类型,相对于BTREE,RTREE的优势在于范围查找。

B + Tree 索引

通常意味着所有的值都是顺序存储的,并且每个叶子页到根的距离相同

适用范围

全键值、键值范围、前缀查找

应用场景

全值匹配、匹配最左前缀、匹配列前缀、匹配范围值、精确匹配某一列并范围匹配另一列、值访问索引的查询

限制

  • 必须为最左开始(最左前缀原则),否则不使用索引
  • 无法跳跃查询索引中的列
  • 范围查询影响,右边的无法使用索引

Hash 索引

基于Hash表实现,只有精确匹配索引所有列的查询才有效

对于每一行数据存储引擎都会对所有的索引计算一个hash code。hash code 较小的值,并且不同键值的行计算出来的hash code页不一样。hash索引将所有的hash code存储在索引中,同时在hash
table中保存指向每个数据的指针

hash索引查询步骤

  1. 先计算数据的hashcode,并使用该值查找对应的记录指针
  2. 查找在hash table中的指向
  3. 值比较确认

特点

因为索引自身只需要存储对应的hash code,所有索引结构非常紧凑,这也让hash索引查找速度非常快

限制

  • hash index 只包含hash值和行指针,而不存储字段值,所以不能使用hash index来避免读取行。同时访问内存中的数据速度非常快,所以对于大部分情况下这一点对于性能影响并不明显

  • hash index数据并不是按照索引顺序存储的,所以无法用于排序

  • hash index 也不支持部分索引列匹配查找
  • hash index 只支持等值比较查询,包括=、IN、<=、=>。也不支持任何范围查询
  • hash index访问数据非常快,除非有很多hash冲突。同时hash冲突很多,索引维护代价较高昂

R Tree索引

空间数据索引

这类索引无需前缀查询,空间索引将会从所有的维度来进行索引数据

Full index

全文索引

全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而非比较索引中的值

全文搜索和其他几种类型的索引的匹配方式完全不同,如停用词、词干、复数、布尔搜索等

全文索引更类似于搜索引擎所做的事情,而不是简单的where条件匹配,而是MATCH AGAINST操作。支持Char、VARCHAR、TEXT类型、自然语言搜索、bool搜索

GIS

Geographic Information System

应用层次

  • 主键索引: 加速查询 + 列值唯一(不可以有null)+ 单表中只有一个主键索引(主键索引可以是多个字段)
  • 普通索引: 仅加速查询
  • 唯一索引: 加速查询 + 列值唯一(建立在UNIQUE上的索引,字段可以为null)
  • 复合索引: 多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
  • 全文索引: 对文本的内容进行分词,进行搜索
  • 覆盖索引: query 的索引字段在二级索引中就能找到(不需回表
  • 前缀索引:仅加速查询(对字符类型的前几个字段或二进制类型字段的前几个bytes建立的索引而不是在整个字段上建立索引)

索引合并,使用多个单列索引组合搜索

索引创建

正确的创建索引是实现高性能查询的基础

其核心的选择因素是 特征 , 借助索引实现尽可能少的行扫描(最多业务场景

索引设计原则

为了使索引的使用效率更高,在创建索引时,必须考虑

  • 什么时候创建索引
  • 在哪个(些)字段上创建索引
  • 创建什么类型的索引
  • 索引设计原则
  1. 必须要有主键,如果没有可以做为主键条件的列,创建无关列
  2. 经常做为where条件列 order by group by join on, distinct 的条件(业务:产品功能+用户行为)
  3. 最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引
  4. 列值长度较长的索引列,建议使用前缀索引.
  5. 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit(xxxxx)
  6. 索引维护要避开业务繁忙期

CREATE TABLE创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE IF NOT EXISTS `ch_people_msg`
(
`p_id` SERIAL NOT NULL AUTO_INCREMENT COMMENT '用户id',
`p_uic` CHAR(18) NOT NULL COMMENT '用户身份证',
`p_nickname` VARCHAR(50) NOT NULL COMMENT '用户昵称',
`p_gender` ENUM ('m','f', 'n') NOT NULL DEFAULT 'n' COMMENT '用户性别',
`p_age` TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户年龄',
`p_pnum` CHAR(11) NOT NULL COMMENT '用户电话',
`p_address` VARCHAR(100) NOT NULL COMMENT '用户地址',
`p_email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
`p_add_time` TIMESTAMP NOT NULL DEFAULT NOW() COMMENT '统计用户时间',
PRIMARY KEY (`p_id`),
UNIQUE KEY `p_uic` (`p_uic`)
) ENGINE = InnoDB
CHARSET = utf8mb4
COLLATE utf8mb4_general_ci COMMENT = '中国成员信息表';

增加索引

1
2
3
ALTER TABLE table_name
ADD INDEX index_name (column_list);
CREATE INDEX (index_type) index_name ON TABEL_NAME(COLUMN_NAME)

创建索引时注意点

  • 非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值;
  • 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count() 函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;
  • 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

索引命名规范

  • 按照列组合命名:Idx_id_name_sex
  • 按照功能命名:ldx_check_user_info
  • 按照列和功能组合命名:ldx_id_name_sex_checklist

但是需要注意,索引名称长度限制64,单个表最大索引数16,超过的话就创建失败。

索引失效

函数导致的索引失效

1
2
3
SELECT *
FROM `user`
WHERE DATE(create_time) = '2012-11-03';

运算符导致的索引失效

1
2
3
4
# 如果对列进行了(+,-,*,/,!)运算, 那么都将不会走索引。
select p_id
from xxx
where p_id + 10 = 12

OR引起的索引失效

OR导致索引是在特定情况下的,并不是所有的OR都是使索引失效

如果OR连接的是同一个字段,那么索引不会失效,反之索引失效。

1
2
3
4
SELECT *
FROM `xxx`
WHERE `name` = 'xxx'
OR age = 20;

模糊搜索导致的索引失效

当模糊查询%在匹配字段前缀不走索引,放在后面才会走索引。

使用!= 或者 <> 导致索引失效

类型不一致导致的索引失效

NOT IN、NOT EXISTS导致索引失效

避免索引失效总结

  1. 尽量采用确认的、顺序的、逐步的
  2. 模糊查询%不在前
  3. 索引列不运算

索引下推

自5.6引入了索引下推优化。默认开启

可使用SET optimizer_switch = ‘index_condition_pushdown=off;将其关闭。

  • 有了索引下推优化,可以在减少回表次数
  • 在InnoDB中只针对二级索引有效

官方文档中给的例子和解释如下:

在 people_table中有一个二级索引(zipcode,lastname,firstname),查询是SELECT * FROM people WHERE zipcode=’95054′ AND lastname LIKE
‘%etrunia%’ AND address LIKE ‘%Main Street%’;

  • 如果没有使用索引下推技术,则MySQL会通过zipcode=’95054’从存储引擎中查询对应的数据,返回到MySQL服务端,然后MySQL服务端基于lastname LIKE ‘%etrunia%’ and address LIKE
    ‘%Main Street%’来判断数据是否符合条件
  • 如果使用了索引下推技术,则MYSQL首先会返回符合zipcode=’95054’的索引,然后根据lastname LIKE ‘%etrunia%’ and address LIKE ‘%Main
    Street%’来判断索引是否符合条件。如果符合条件,则根据该索引来定位对应的数据,如果不符合,则直接reject掉。

默认使用B+Tree的优势

为什么索引结构默认使用B+Tree,而不是B-Tree,Hash,二叉树,红黑树?

B-tree:

  • B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B(B-)
    树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
  • 由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询
    的情况,所以通常B+树用于数据库索引。

Hash:

  • 虽然可以快速定位,但是没有顺序,IO复杂度高;

  • 基于Hash表实现,只有Memory存储引擎显式支持哈希索引 ;

  • 适合等值查询,如=、in()、<=>,不支持范围查询 ;
  • 因为不是按照索引值顺序存储的,就不能像B+Tree索引一样利用索引完成排序 ;
  • Hash索引在查询等值时非常快 ;
  • 因为Hash索引始终索引的所有列的全部内容,所以不支持部分索引列的匹配查找 ;
  • 如果有大量重复键值得情况下,哈希索引的效率会很低,因为存在哈希碰撞问题 。

二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。

红黑树:树的高度随着数据量增加而增加,IO代价高。

Referer

《高性能MySQL》

image-20220323224244082

数据库

Linux平台下MySQL的安装

LSB Version: :core-4.1-amd64:core-4.1-noarch

Distributor ID: CentOS

Description: CentOS Linux release 7.9.2009 (Core)

Release: 7.9.2009

Codename: Core

ldd (GNU libc) :2.17

前置工作

删除mariadb

1
yum remove -y mariadb-libs.x86_64

yum

安装rpm

进入MySQL的yum仓库,如下图所示

image-20210904233814767

官方rpm包: https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm

清华镜像rpm包: https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql80-community-el7/mysql80-community-release-el7-3.noarch.rpm

1
wget -c rpm地址

安装yum仓库文件

可使用rpm -ivh或是yum localinstall 去安装,两者实质是一样的

1
rpm -ivh mysql80-community-release-el7-3.noarch.rpm

安装

1
yum install -y  mysql-community-server

二进制

https://downloads.mysql.com/archives/community/

image-20210905113818649

1
2
3
# 下
wget -c https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz
tar zf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz

建立用户与授权

1
2
useradd mysql && usermod -s /sbin/nologin mysql
mkdir -p /opt/databases/mysql && chown -R mysql. /opt/databases/mysql

配置

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# vim /etc/my.cnf

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

default-storage-engine=INNODB
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
skip-character-set-client-handshake
secure_file_priv=''
user = mysql
port=8916

[client]
default-character-set=utf8mb4


[mysql]
default-character-set=utf8mb4

获取初始root密码

1
grep 'temporary password' /var/log/mysqld.log

创建用户与授权

根据业务、公司情况创建管理员,若公司成员较少,管理员管全局。反之管单库

  1. root不允许远程连接
  2. 修改root密码

远程连接

授权

1
2
3
4
远程登录还需要授权远程登录Mysql默认不允许远程登录,我们需要设置关闭selinux或者防火墙,不关防火墙就开放3306端口;
#放开3306端口
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload

blog

本博客采用github page实现部署,但由于github的性质无法有效的进行分离快速部署。

必须博客展示页,必须以username.github.io结尾,这样感觉不是很方便

部署前基本流程为,部署github page -> 手动上传源码到对应仓库。

那么我们是否可以直接push到私有源码仓库,出发二段部署从实现自动的博客部署,此时我们只需要关心与维护自己的博客源码,再也不用刻意的关注部署了

说干就干

前置条件

ssh部署

1
ssh-keygen -t rsa -C "your email"

若配置了全局的git email 可使用ssh-keygen -t rsa -C "$(git config user.email)" -f gh-pages -N ""

完成后将在本地$HOME/.ssh中生成私钥id_rsa,与公钥,id_rsa.pub,将公钥上传到github上,进入https://github.com/settings/keys ,登陆自己的github账号。如下所示

image-20210904121559885

New SSH Key

image-20210904121643113

其中title为自定义,key为id_rsa.pub中内容。完成后点击Add SSH key即可

建立私有博客源码仓库

github上创建一个私有仓库即可,详细流程不在过多赘述

创建Actions

配置Actions secrets

Settings -> Deploy keys -> New repository secrets,如下所示

image-20210904110320916

image-20210904110617453

将上面生成的id_rsa,复制到私钥中。

image-20210904122401191

将workflow增加到源码文件中,拉取到本地。

deploy.yml如下

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# This is a basic workflow to help you get started with Actions

name: Deploy to Github Pages

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ master ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2

- name: Env setup
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_rsa # DEPLOY_KEY 为secret name
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
# setup deploy git account
git config --global user.name "your user name"
git config --global user.email "your email"

- name: Hexo Build and Deploy
run: |
find . -type f -name *.log -delete
npm install
npm run clean
npm run build
npm run deploy

总结

以上便是github page 源码保护分析详细过程,其基本原理就是将ssh部署的工作交给自动构建的Actions。

数据库

mysql优化老生常谈了,但却也离不开业务。脱离业务来讲mysql可以从两个方面进行优化

  • 安全优化(业务持续性)

  • 性能优化(业务高效性)

所谓优化,个人认为有两大需要提前知道的稳定性和业务可持续性通常比性能更重要优化是由业务需要驱使的

通常优化也与操作系统、运行环境等息息相关,结合业务适合自己才是最好的。

安全优化

足够强度的安全是保证业务正常运行的基石,安全优化通常可以以系统安全,应用程序安全,与sql安全。

系统安全

具体详情请参考Linux系统安全

物理安全

物理环境安全,小微企业一般使用云服务器,大型企业一般有多个机房,实现异地多活

防火墙策略、关闭或切换不必要的端口

  1. 修改常见应用默认端口,22、3306、27017、6379等

账户安全

用户连接权限、用户权限

  1. 禁止root远程
  2. 账号管理(密码强度、用户权限)

源代码文件目录权限管理

备份

MySQL安全

https://www.cnblogs.com/doublexi/p/9732274.html

MySQL版本的选择

MySQL的命名机制使用由3个数字和一个后缀组成的版本号。例如,像mysql-5.0.9-beta的版本号这样解释:

数字(5)是主版本号,描述了文件格式。所有版本5的发行都有相同的文件格式。

数字(0)是发行级别。主版本号和发行级别组合到一起便构成了发行序列号。

数字(9)是在此发行系列的版本号,随每个新分发版递增。通常你需要已经选择的发行(release)的最新版本(版本)。

每次更新后,版本字符串的最后一个数字递增。如果相对于前一个版本增加了新功能或有微小的不兼容性,字符串的第二个数字递增。如果文件格式改变,第一个数字递增。

后缀显示发行的稳定性级别。通过一系列后缀显示如何改进稳定性。可能的后缀有:

·alpha表明发行包含大量未被彻底测试的新代码。已知的缺陷应该在新闻小节被记录。请参见附录D:MySQL变更史。在大多数alpha版本中也有新的命令和扩展。alpha版本也可能有主要代码更改等开发。但我们在发布前一定对其进行测试。

·beta意味着该版本功能是完整的
,并且所有的新代码被测试了,没有增加重要的新特征,应该没有已知的缺陷。当alpha版本至少一个月没有出现报导的致命漏洞,并且没有计划增加导致已经实施的功能不稳定的新功能时,版本则从alpha版变为beta版。

在以后的beta版、发布版或产品发布中,所有API、外部可视结构和SQL命令列均不再更改。

·rc是发布代表;是一个发行了一段时间的beta版本,看起来应该运行正常。只增加了很小的修复。(发布代表即以前所称的gamma版)

·如果没有后缀,这意味着该版本已经在很多地方运行一段时间了,而且没有非平台特定的缺陷报告。只增加了关键漏洞修复修复。这就是我们称为一个产品(稳定)或“通用”版本的东西。

MySQL的命名机制于其它产品稍有不同。一般情况,我们可以很放心地使用已经投放市场两周而没有被相同发布系列的新版本所代替的版本。

  • 稳定不要最新:最新GA版超过10个月或比最新GA版晚3、4个版本的GA版。
  • 前后无大BUG:要选择前后几个月没有大的BUG修复的版本,而不是大量修复BUG的集中版本
  • 向后少更新:最好向后较长时间没有更新发布的版本,若目标版本修复的BUG巨多,向前推进一个版本号。
  • 兼容开发:验证功能瓶颈、性能瓶颈,要考虑开发人员开发程序使用的版本是否兼容你选的版本
  • 测试先行:作为内部开发测试数据库环境,跑大概3-6个月的时间。
  • 非核心先行:优先企业非核心业务采用新版本的数据库GA版本软件。

用户安全

禁止root账户远程访问

root权限太高,拥有安全隐患,root只允许本地登陆

mysql用户登录shell为nologin

1
usermod -s /sbin/nologin mysql

对MySQL运行用户降权,以普通用户身份运行MySQL

1
2
3
# /etc/my.cnf
[mysqld]
user=mysql

删除匿名账号和空口令账号

1
2
# 删除空密码用户
delete from mysql.user where user is NULL or Password IS NULL;

用户与权限管理

遵循权限最小化原则。

连接安全

修改默认端口

1
2
3
# /etc/my.cnf
[mysqld]
port=8912

容灾

在误删除数据的情况下,可以通过二进制日志恢复到某个时间点

二进制日志

1
2
# 查看bin log(sql)
show variables like '%log_bin%'

image-20210905193857001

修改MySQL配置文件my.cnf,加入如下两行

1
2
server-id = 1
log_bin = /data/mysql/mysql-bin

重启服务

性能优化

1
2
效果 sql与索引优化>Schema设计>数据库实例优化>文件系统>操作系统>硬件优化
成本 硬件优化>操作系统>文件系统>数据库实例优化>Schema设计>sql与索引优化

硬件优化

主机

1
2
3
真实的硬件(PC Server): DELL  R系列 ,华为,浪潮,HP,联想
云产品:ECS、数据库RDS、DRDS
IBM 小型机 P6 570 595 P7 720 750 780 P8

CPU

根据业务场景选择

OLTP \ OLAP IO密集型:线上系统,OLTP主要是IO密集型的业务,高并发 CPU密集型:数据分析数据处理,OLAP,cpu密集型的,需要CPU高计算能力(i系列,IBM power系列) CPU密集型: I
系列的,主频很高,核心少 IO密集型: E系列(至强),主频相对低,核心数量多

内存

建议2-3倍cpu核心数量 (ECC)

磁盘选择

SATA-III SAS Fc SSD(sata) pci-e ssd Flash 主机 RAID卡的BBU(Battery Backup Unit)关闭

存储

根据存储数据种类的不同,选择不同的存储设备 配置合理的RAID级别(raid5、raid10、热备盘)
r0 :条带化 ,性能高 r1 :镜像,安全 r5 :校验+条带化,安全较高+性能较高(读),写性能较低 (适合于读多写少) r10:安全+性能都很高,最少四块盘,浪费一半的空间(高IO要求)

网络

1、硬件买好的(单卡单口)

2、网卡绑定(bonding),交换机堆叠 以上问题,提前规避掉。

操作系统优化

Swap调整

1
2
3
4
echo 0 >/proc/sys/vm/swappiness的内容改成0(临时),
/etc/sysctl.conf
上添加vm.swappiness=0(永久)
sysctl -p

此参数决定了Linux是倾向于使用swap,还是倾向于释放文件系统cache。在内存紧张的情况下,数值越低越倾向于释放文件系统cache。 当然,这个参数只能减少使用swap的概率,并不能避免Linux使用swap。

修改MySQL的配置参数innodb_flush_method,开启O_DIRECT模式 这种情况下,InnoDB的buffer pool会直接绕过文件系统cache来访问磁盘,但是redo
log依旧会使用文件系统cache。值得注意的是,Redo log是覆写模式的,即使使用了文件系统的cache,也不会占用太多

IO调度策略

raid、no lvm、ext4或xfs、ssd、IO调度策略

数据库实例优化

查看系统配置

1
show variables like “xxx”

查看状态

1
show status like

连接

max_connect_errors

max_connect_errors是一个mysql中与安全有关的计数器值,它负责阻止过多尝试失败的客户端以防止暴力破解密码等情况,当超过指定次数,mysql服务器将禁连接请求,

直到mysql服务器重启或通过flush hosts命令清空此host的相关信息 max_connect_errors的值与性能并无太大关系。

1
2
修改/etc/my.cnf文件,在[mysqld]下面添加如下内容
max_connect_errors=1000
Max_connections

Mysql的最大连接数,如果服务器的并发请求量比较大,可以调高这个值,当然这是要建立在机器能够支撑的情况下,因为如果连接数越来越多,mysql会为每个连接提供缓冲区,就会开销的越多的内存,所以需要适当的调整该值,不能随便去提高设值

开启数据库时,临时设置一个比较大的测试值, 观察show status like ‘Max_used_connections’;变化
如果max_used_connections跟max_connections相同,那么就是max_connections设置过低或者超过服务器的负载上限了,低于10%则设置过大.

back_log

mysql能暂存的连接数量,当主要mysql线程在一个很短时间内得到非常多的连接请求时候它就会起作用,如果mysql的连接数据达到max_connections时候,新来的请求将会被存在堆栈中,等待某一连接释放资源,该推栈的数量及back_log,如果等待连接的数量超过back_log,将不被授予连接资源。
back_log值指出在mysql暂时停止回答新请求之前的短时间内有多少个请求可以被存在推栈中,只有如果期望在一个短时间内有很多连接的时候需要增加它

判断依据

1
show full processlist

发现大量的待连接进程时,就需要加大back_log或者加大max_connections的值

1
2
# vim /etc/my.cnf 
back_log=xxx
wait_timeout

wait_timeout:指的是mysql在关闭一个非交互的连接之前所要等待的秒数,如果设置太小,那么连接关闭的就很快,从而使一些持久的连接不起作用。长连接的应用,为了不去反复的回收和分配资源,降低额外的开销。

如果设置太大,容易造成连接打开时间过长,在show processlist时候,能看到很多的连接 ,一般希望wait_timeout尽可能低

interactive_timeout

如果设置太大,容易造成连接打开时间过长造成资源损耗,在show processlist时候,能看到很多的连接 ,一般希望wait_timeout尽可能低

关闭一个交互的连接之前所需要等待的秒数,比如我们在终端上进行mysql管理,使用的即使交互的连接,这时候,如果没有操作的时间超过了interactive_time设置的时间就会自动的断开,默认的是28800,可调优为7200

key_buffer_size

key_buffer_size指定索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度

1
2
3
4
5
6
临时表的创建有关(多表链接、子查询中、union)
在有以上查询语句出现的时候,需要创建临时表,用完之后会被丢弃
临时表有两种创建方式:
内存中------->key_buffer_size
磁盘上------->ibdata1(5.6)
ibtmp1 (5.7

处理

sort_buffer_size

每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速

1
2
3
4
ORDER BY 
GROUP BY
distinct
union

Sort_Buffer_Size并不是越大越好,由于是connection级的参数,过大的设置+高并发可能会耗尽系统内存资源。 列如:500个连接将会消耗500*sort_buffer_size(2M)=1G内存

配置方法
修改/etc/my.cnf文件,在[mysqld]下面添加如下: sort_buffer_size=1M

max_allowed_packet

mysql根据配置文件会限制,server接受的数据包大小

有时候大的插入和更新会受max_allowed_packet参数限制,导致写入或者更新失败,更大值是1GB,必须设置1024的倍数

1
max_allowed_packet=32M
join_buffer_size

用于表间关联缓存的大小,和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。 尽量在SQL与方面进行优化,效果较为明显。 优化的方法:在on条件列加索引,至少应当是有MUL索引

thread_cache_size

服务器线程缓存,这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时,那么客户端的线程将被放到缓存中以响应下一个客户而不是销毁(前提是缓存数未达上限),如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能

通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。 设置规则如下:1GB 内存配置为8,2GB配置为16,3GB配置为32,4GB或更高内存,可配置更大。
服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)

Variable_name Value
Threads_cached 178 当前此时此刻线程缓存中有多少空闲线程
Threads_connected 78 当前已建立连接的数量,因为一个连接就需要一个线程,所以也可以看成当前被使用的线程数
Threads_created 479 从最近一次服务启动,已创建线程的数量,如果发现Threads_created值过大的话,表明MySQL服务器一直在创建线程,这也是比较耗cpu SYS资源,可以适当增加配置文件中thread_cache_size值
Threads_running 2 当前激活的(非睡眠状态)线程数。并不是代表正在使用的线程数,有时候连接已建立,但是连接处于sleep状态

Threads_created :一般在架构设计阶段,会设置一个测试值,做压力测试。 结合zabbix监控,看一段时间内此状态的变化。 如果在一段时间内,Threads_created趋于平稳,说明对应参数设定是OK。
如果一直陡峭的增长,或者出现大量峰值,那么继续增加此值的大小,在系统资源够用的情况下(内存)

innodb_buffer_pool_size

对于InnoDB表来说,innodb_buffer_pool_size的作用就相当于key_buffer_size对于MyISAM表的作用一样。

配置依据

InnoDB使用该参数指定大小的内存来缓冲数据和索引。

对于单独的MySQL数据库服务器,最大可以把该值设置成物理内存的80%,一般我们建议不要超过物理内存的70%。

配置方法

innodb_buffer_pool_size=2048M

innodb_flush_log_at_trx_commit

主要控制了innodb将log buffer中的数据写入日志文件并flush磁盘的时间点,取值分别为0、1、2三个。 0,表示当事务提交时,不做日志写入操作,而是每秒钟将log buffer中的数据写入日志文件并flush磁盘一次;
1,每次事务的提交都会引起redo日志文件写入、flush磁盘的操作,确保了事务的ACID; 2,每次事务提交引起写入日志文件的动作,但每秒钟完成一次flush磁盘操作。

配置依据
实际测试发现,该值对插入数据的速度影响非常大,设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。因此,MySQL手册也建议尽量将插入操作合并成一个事务,这样可以大幅提高速度。
根据MySQL官方文档,在允许丢失最近部分事务的危险的前提下,可以把该值设为0或2。

配置方法

innodb_flush_log_at_trx_commit=1 双1标准中的一个1

innodb_thread_concurrency

此参数用来设置innodb线程的并发数量,默认值为0表示不限制。

在官方文档上,对于innodb_thread_concurrency的使用,也给出了一些建议,如下:

  • 如果一个工作负载中,并发用户线程的数量小于64,建议设置innodb_thread_concurrency=0;
  • 如果工作负载一直较为严重甚至偶尔达到顶峰,建议先设置innodb_thread_concurrency=128, 并通过不断的降低这个参数,96, 80, 64等等,直到发现能够提供最佳性能的线程数,

假设系统通常有40到50个用户,但定期的数量增加至60,70,甚至200。你会发现, 性能在80个并发用户设置时表现稳定,如果高于这个数,性能反而下降。在这种情况下,
建议设置innodb_thread_concurrency参数为80,以避免影响性能。

如果你不希望InnoDB使用的虚拟CPU数量比用户线程使用的虚拟CPU更多(比如20个虚拟CPU), 建议通过设置innodb_thread_concurrency 参数为这个值(也可能更低,这取决于性能体现),

如果你的目标是将MySQL与其他应用隔离,你可以l考虑绑定mysqld进程到专有的虚拟CPU。 但是需 要注意的是,这种绑定,在myslqd进程一直不是很忙的情况下,可能会导致非最优的硬件使用率。在这种情况下,
你可能会设置mysqld进程绑定的虚拟 CPU,允许其他应用程序使用虚拟CPU的一部分或全部。 在某些情况下,最佳的innodb_thread_concurrency参数设置可以比虚拟CPU的数量小。
定期检测和分析系统,负载量、用户数或者工作环境的改变可能都需要对innodb_thread_concurrency参数的设置进行调整

128 ——-> top cpu
设置标准
1、当前系统cpu使用情况,均不均匀 top

2、当前的连接数,有没有达到顶峰 show status like ‘threads_%’; show processlist; (3)配置方法: innodb_thread_concurrency=8 方法:

1
2
3
看top ,观察每个cpu的各自的负载情况
发现不平均,先设置参数为cpu个数,然后不断增加(一倍)这个数值
一直观察top状态,直到达到比较均匀时,说明已经到位了.
innodb_log_buffer_size
1
2
3
4
5
此参数确定些日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,对于较大的事务,可以增大缓存大小。
innodb_log_buffer_size=128M
设定依据:
1、大事务: 存储过程调用 CALL
2、多事务
innodb_log_file_size = 100M
1
2
3
设置 ib_logfile0  ib_logfile1 
此参数确定数据日志文件的大小,以M为单位,更大的设置可以提高性能.
innodb_log_file_size = 100M
innodb_log_files_in_group = 3
1
为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3
read_buffer_size = 1M
1
MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。和 sort_buffer_size一样,该参数对应的分配内存也是每个连接独享
read_rnd_buffer_size = 1M
1
2
MySql的随机读(查询操作)缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。
注:顺序读是指根据索引的叶节点数据就能顺序地读取所需要的行数据。随机读是指一般需要根据辅助索引叶节点中的主键寻找实际行数据,而辅助索引和主键所在的数据段不同,因此访问方式是随机的。
bulk_insert_buffer_size = 8M
1
2
3
4
5
6
批量插入数据缓存大小,可以有效提高插入效率,默认为8M
tokuDB percona
myrocks
RocksDB
TiDB
MongoDB
binary log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
log-bin = /data/mysql-bin
binlog_cache_size = 2M //为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存, 提高记录bin-log的效率。没有什么大事务,dml也不是很频繁的情况下可以设置小一点,如果事务大而且多,dml操作也频繁,则可以适当的调大一点。前者建议是--1M,后者建议是:即 2--4M
max_binlog_cache_size = 8M //表示的是binlog 能够使用的最大cache 内存大小
max_binlog_size = 512M //指定binlog日志文件的大小,如果当前的日志大小达到max_binlog_size,还会自动创建新的二进制日志。你不能将该变量设置为大于1GB或小于4096字节。默认值是1GB。在导入大容量的sql文件时,建议关闭sql_log_bin,否则硬盘扛不住,而且建议定期做删除。
expire_logs_days = 7 //定义了mysql清除过期日志的时间。
二进制日志自动删除的天数。默认值为0,表示“没有自动删除”。
log-bin = /mysql-bin
binlog_format = row
sync_binlog = 1
双1标准(基于安全的控制):
sync_binlog = 1 // 什么时候刷新binlog到磁盘,每次事务commit
innodb_flush_log_at_trx_commit = 1
set sql_log_bin = 0;
show status like 'com_%';
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[mysqld]
basedir = /data/mysql
datadir = /data/mysql/data
socket = /tmp/mysql.sock
log-error = /var/log/mysql.log
log_bin = /data/binlog/mysql-bin
binlog_format = row
skip-name-resolve
server-id = 52
gtid-mode = on
enforce-gtid-consistency = true
log-slave-updates = 1
relay_log_purge = 0
max_connections = 1024
back_log = 128
wait_timeout = 60
interactive_timeout = 7200
key_buffer_size = 16M
query_cache_size = 64M
query_cache_type = 1
query_cache_limit = 50M
max_connect_errors = 20
sort_buffer_size = 2M
max_allowed_packet = 32M
join_buffer_size = 2M
thread_cache_size = 200
innodb_buffer_pool_size = 1024M
innodb_flush_log_at_trx_commit = 1
innodb_log_buffer_size = 32M
innodb_log_file_size = 128M
innodb_log_files_in_group = 3
binlog_cache_size = 2M
max_binlog_cache_size = 8M
max_binlog_size = 512M
expire_logs_days = 7
read_buffer_size = 2M
read_rnd_buffer_size = 2M
bulk_insert_buffer_size = 8M
[client]
socket = /tmp/mysql.sock

sql与索引优化

sql使用建议

  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

  2. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

1
2
3
4
5
6
select id
from t
where num is null # 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id
from t
where num = 0
  1. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

  2. 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

1
2
3
4
5
6
7
8
9
10
11
select id
from t
where num = 10
or num = 20 # 可以这样查询:
select id
from t
where num = 10
union all
select id
from t
where num = 20
  1. in 和 not in 也要慎用,否则会导致全表扫描,如:
1
2
3
4
5
6
select id
from t
where num in (1, 2, 3) # 对于连续的数值,能用 between 就不要用 in 了:
select id
from t
where num between 1 and 3
  1. 下面的查询也将导致全表扫描:
1
2
3
select id
from t
where name like '%abc%'
  1. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
1
2
3
4
5
6
select id
from t
where num / 2 = 100 # 应改为:
select id
from t
where num = 100 * 2
  1. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
1
2
3
4
5
6
7
select id
from t
where substring(name, 1, 3) = 'abc'--name以abc开头的id
# 应改为:
select id
from t
where name like 'abc%'
  1. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

  2. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

  3. 不要写一些没有意义的查询,如需要生成一个空表结构

  4. 很多时候用 exists 代替 in 是一个好的选择:

1
2
3
4
5
6
select num
from a
where num in (select num from b) # 用下面的语句替换:
select num
from a
where exists(select 1 from b where num = a.num)
  1. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

  2. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率, 因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
    一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

  3. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。 这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

  4. 尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,
    其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

  5. 任何地方都不要使用 select from t ,用具体的字段列表代替“”,不要返回用不到的任何字段。

  6. 避免频繁创建和删除临时表,以减少系统表资源的消耗。

  7. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

  8. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,
    以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

  9. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

  10. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

  11. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

  12. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。

在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

  1. 尽量避免大事务操作,提高系统并发能力。

  2. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

sql调优思路

  1. slow_query_log 收集慢日志 结合explain分析索引命中与进行索引优化
  2. 减少索引扫描行数,对于慢sql进行优化
  3. 建立联合索引,由于联合索引的每个叶子节点都包含检索字段信息,按最左原则匹配,按照其他条件过滤,减少回表的数据量
  4. 使用虚拟列和联合索引来提升复杂查询执行效率

索引失效

  1. 联合索引不遵循最左匹配原则
  2. SELECT *使用不当
  3. 索引列参与计算—查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)
  4. 错误的使用lIKE, 进行模糊查询
  5. 查询条件与索引列类型不一致,造成类型转换
  6. WHERE 子查询中OR 使用不当
  7. < >IS NOT NULLNOT INNOT EXISTS
  8. ORDER BY 多个字段时不走索引
  9. 优化器判断失误不走索引

Kubernetes

NFS实践

安装NFS

1
2
3
4
5
6
7
8
9
# 下载nfs相关软件(全成员)
yum install -y nfs-common nfs-utils rpcbind
# 创建NFS共享文件夹,以及授权(需要root)
mkdir /nfs && chmod 766 /nfs && chown nfsnobody /nfs/
# 声明共享文件权限(NFS主服务器)
echo "/nfs *(rw,no_root_squash,no_all_squash,sync)" >> /etc/exports
#
exportfs -r
systemctl restart rpcbind && systemctl restart nfs && systemctl status rpcbind && systemctl status nfs

验证

IP: 主机地址

1
2
3
4
5
6
7
8
9
# 查看共享目录
showmount -e IP
mkdir /test
# 将本机目录(test)挂载至目标目录(nfs)
mount -t nfs IP:/nfs /test
cd /test
echo "asdsadsa" >> a.txt
cd /
umount /test && rm -rf /test

部署PV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfspv-master
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nfs
server: 192.168.0.27 # 节点ip

PVC

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx
ports:
- port: 80
name: web
clusterIP: None

---

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: wangyanglinux/myapp:v2
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs"
resources:
requests:
storage: 1Gi

验证

1
2
kubectl get pv
kubectl desc

image-20210903233505574

1
2
3
# 192.168.0.27 /nfs
echo "asds" > index.html
kubectl get pod -o wid

image-20210903234426686

1
2
curl 10.244.1.53
# asds

数据库

mysql用户管理

DCL(Data Control Language,数据控制语言):用于定义数据库的访问权限和安全级别,主要包含GRANT、REVOKE、COMMIT和ROLLBACK等语句。

mysql用户管理主要涉及到用户的增删改查与权限管理

mysql中存在4个控制权限的表,分别为user表,db表,tables_priv表,columns_priv表

权限表的验证过程

  1. 先从user表中的Host,User,Password这3个字段中判断连接的ip、用户名、密码是否存在,存在则通过验证。
  2. 通过身份认证后,进行权限分配,按照user,db,tables_priv,columns_priv的顺序进行验证。即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db,
    tables_priv,columns_priv;如果为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限;如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。

MySQL 权限级别
全局性的管理权限: 作用于整个MySQL实例级别 数据库级别的权限: 作用于某个指定的数据库上或者所有的数据库上 数据库对象级别的权限:作用于指定的数据库对象上(表、视图等)或者所有的数据库对象上

用户操作

1
2
3
4
# 创建用户
create user user_name@'host' identified by 'password';
# example:
# create user acs@'10.0.0.%' identified by '123123';
1
2
3
4
5
# 删除用户
drop user user_name@'host';
# example:
# drop user acs@'10.0.0.%'
# DELETE FROM `user` WHERE `user`.`Host` = '10.0.0.%' AND `user`.`User` = 'acs'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 修改用户
alter user user_name@'host' identified by 'password';
# example
## 修改密码
alter user acs@'10.0.0.%' identified by '321312312123';
## 修改 host
UPDATE `user`
SET `Host` = '%'
WHERE `user`.`Host` = '10.0.0.%'
AND `user`.`User` = 'acs'
## 修改权限
UPDATE `user`
SET `Select_priv` = 'Y'
WHERE `user`.`Host` = '%'
AND `user`.`User` = 'acs'
UPDATE `user`
SET `Select_priv` = 'Y',
`Delete_priv` = 'Y'
WHERE `user`.`Host` = '%'
AND `user`.`User` = 'acs'
1
2
3
4
5
6
7
8
# 删除用户
drop user user_name@'host';
# example
drop user acs@'%'
DELETE
FROM `user`
WHERE `user`.`Host` = '10.0.0.%'
AND `user`.`User` = 'acs'

user_name:用户名

host :可允许连接ip(Localhost代表本机, 127.0.0.1代表ipv4本机地址, ::1代表ipv6的本机地址,)

password:用户密码

权限管理

权限可细分为操作权限与操作范围

常用权限介绍

1
2
3
ALL:	SELECT,INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE
ALL : 所有权限,一般是普通管理员拥有的
with grant option:给别的用户授权的功能

权限作用范围

1
2
3
*.*               ---->所有:管理员用户
dbname.* ---->指定库下所有:开发和应用用户
dbname.t1 ---->指定表

开发人员用户授权流程

  1. 你从哪来
  2. 对谁操作
  3. 权限
  4. 密码要求

权限

可以使用GRANT给用户添加权限,权限会自动叠加,不会覆盖之前授予的权限,比如你先给用户添加一个SELECT权限,后来又给用户添加了一个INSERT权限,那么该用户就同时拥有了SELECT和INSERT权限

1
2
3
4
5
# 查看MYSQL有哪些用户
select user, host
from mysql.user;
# 查看权限
show grants for user_name@'host';
1
2
# 授权
grant 权限 on 权限范围 to 用户 identified by 密码 with grant option;

all privileges:表示将所有权限授予给用户。也可指定具体的权限,如:SELECT、CREATE、DROP等。
on:表示这些权限对哪些数据库和表生效,格式:数据库名.表名,这里写“”表示所有数据库,所有表。如果我要指定将权限应用到test库的user表中,可以这么写:test.user
to:将权限授予哪个用户。格式:”用户名”@”登录IP或域名”。%表示没有限制,在任何主机都可以登录。比如:”payne”@”192.168.0%”,表示yangxin这个用户只能在192.168.0IP段登录
•identified by:指定用户的登录密码
*•with grant option:
表示允许用户将自己的权限授权给其它用户

1
2
3
# 收回权限
revoke delete on 权限范围 from 用户@‘host’
revoke delete on app.* from app@'10.0.0.%';

如何授权

用户的权限一定是与业务分离不开的,但通常普通用户会

  • 禁用删除权限
  • 规定范围

如何做好用户管理

  • 密码系数足够高
  • root禁用远程登录
  • 分级别,类似于公司管理。

注意

1
2
3
4
8.0在grant命令添加新特性
建用户和授权分开了
grant 不再支持自动创建用户了,不支持改密码
授权之前,必须要提前创建用户。
  • 执行Grant,revoke,set password,rename user命令修改权限之后, MySQL会自动将修改后的权限信息同步加载到系统内存中
  • 如果执行insert/update/delete操作上述的系统权限表之后,则必须再执行刷新权限命令才能同步到系统内存中,刷新权限命令包括: flush privileges/mysqladmin flush-privileges /
    mysqladmin reload
  • 如果是修改tables和columns级别的权限,则客户端的下次操作新权限就会生效
  • 如果是修改database级别的权限,则新权限在客户端执行use database命令后生效
  • 如果是修改global级别的权限,则需要重新创建连接新权限才能生效
  • 如果是修改global级别的权限,则需要重新创建连接新权限才能生效 (例如修改密码)

mysql user表

名字 类型 Null 主键 默认
Host char(255) NO PRI
User char(32) NO PRI
Select_priv enum(‘N’,’Y’) NO N
Insert_priv enum(‘N’,’Y’) NO N
Update_priv enum(‘N’,’Y’) NO N
Delete_priv enum(‘N’,’Y’) NO N
Create_priv enum(‘N’,’Y’) NO N
Drop_priv enum(‘N’,’Y’) NO N
Reload_priv enum(‘N’,’Y’) NO N
Shutdown_priv enum(‘N’,’Y’) NO N
Process_priv enum(‘N’,’Y’) NO N
File_priv enum(‘N’,’Y’) NO N
Grant_priv enum(‘N’,’Y’) NO N
References_priv enum(‘N’,’Y’) NO N
Index_priv enum(‘N’,’Y’) NO N
Alter_priv enum(‘N’,’Y’) NO N
Show_db_priv enum(‘N’,’Y’) NO N
Super_priv enum(‘N’,’Y’) NO N
Create_tmp_table_priv enum(‘N’,’Y’) NO N
Lock_tables_priv enum(‘N’,’Y’) NO N
Execute_priv enum(‘N’,’Y’) NO N
Repl_slave_priv enum(‘N’,’Y’) NO N
Repl_client_priv enum(‘N’,’Y’) NO N
Create_view_priv enum(‘N’,’Y’) NO N
Show_view_priv enum(‘N’,’Y’) NO N
Create_routine_priv enum(‘N’,’Y’) NO N
Alter_routine_priv enum(‘N’,’Y’) NO N
Create_user_priv enum(‘N’,’Y’) NO N
Event_priv enum(‘N’,’Y’) NO N
Trigger_priv enum(‘N’,’Y’) NO N
Create_tablespace_priv enum(‘N’,’Y’) NO N
ssl_type enum(‘’,’ANY’,’X509’,’SPECIFIED’) NO
ssl_cipher blob NO NULL
x509_issuer blob NO NULL
x509_subject blob NO NULL
max_questions int unsigned NO 0
max_updates int unsigned NO 0
max_connections int unsigned NO 0
max_user_connections int unsigned NO 0
plugin char(64) NO caching_sha2_password
authentication_string text YES NULL
password_expired enum(‘N’,’Y’) NO N
password_last_changed timestamp YES NULL
password_lifetime smallint unsigned YES NULL
account_locked enum(‘N’,’Y’) NO N
Create_role_priv enum(‘N’,’Y’) NO N
Drop_role_priv enum(‘N’,’Y’) NO N
Password_reuse_history smallint unsigned YES NULL
Password_reuse_time smallint unsigned YES NULL
Password_require_current enum(‘N’,’Y’) YES NULL
User_attributes json YES NULL

容器编排

引子

在构建、部署、测试等情景中下不知你也是否遇到过这么几个问题,构建慢、依赖安装慢、重复性构建。 以至于每一次采用docker来构建时,都需要等上那么几分钟。

有时候是非常的浪费时间, 那么是否有方法进行一次分离构建呢。当然正如docker口号所说的那般”
Build once,Run anywher“,

那么该如何解决“构建慢、依赖安装慢、重复性构建”的问题呢, 看似三个或者更多问题,其实归根结底是一个问题——分层构建

分层构建

想深层理解docker的分层构建,不得不从docker的设计特性出发。虚拟机与docker结构,如下图所示。

image-20210902182150947

一层一层的分层结构,那么所谓分层构建只需要将环境依赖业务代码分开构建即可。实现如下

  • 短时间内环境依赖构建一次且仅构建一次

  • 业务代码触发构建

例子

python

1
2
3
4
5
6
7
8
9
10
11
12
#构建环境依赖
## 拉取pythoo镜像
FROM python:3.9
## 设置环境变量,相当于linux的export
ENV PATH /usr/local/bin:$PATH
## 在容器中进入根目录code(如果没有code目录则创建)相当于cd
WORKDIR /code
## 将执行docker build 路径下的所有文件copy到容器内所在的目录
COPY requirements.txt .
## 执行shell命令
RUN python3 -m pip install -U pip && \
python3 -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
1
2
3
4
# 构建
docker build -t user/img_name:version .
# 发布
docker push user/img_name:version
1
2
3
4
5
#项目构建
FROM user/img_name:version
WORKDIR /app
COPY . .
CMD ["supervisord","-c", "supervisord.conf"]

golang

两层: 1.依赖构建 2.编译与项目构建

三层: 1.依赖构建 2.编译构建 3.运行文件构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
FROM golang:1.16 as builder
# Setting environment variables
ENV GOPROXY="https://goproxy.cn,direct" \
GO111MODULE="on" \
CGO_ENABLED="0" \
GOOS="linux" \
GOARCH="amd64"

# Switch to workspace
WORKDIR /go/src/github.com/gowebspider/goproxies/

# Load file
COPY . .

## add rely
go mod tidy

# Build and place the results in /tmp/goproxies
RUN go build -o /tmp/goproxies .

FROM alpine:latest
WORKDIR /root/
COPY --from=builder /tmp/goproxies .
CMD ["./goproxies"]

Error Set

错误如下

cni already has an IP address different from …

如图所示

1421630332579_.pic_hd

缘由

node之前反复添加

解决方案

1
2
# 找到对应的节点
kubectl get pod --all-namespace -o wide

在对应node上执行如下命令

1
2
3
4
5
6
7
8
9
# 重置Kubernetes集群
kubeadm reset && systemctl stop kubelet && systemctl stop docker
# 删除残留
rm -rf /var/lib/cni/ && rm -rf /var/lib/kubelet/* && rm -rf /etc/cni/
# 删除旧网络
ifconfig cni0 down && ifconfig flannel.1 down && ifconfig docker0 down
ip link delete cni0 && ip link delete flannel.1
# 重启服务
systemctl restart docker && systemctl start kubelet

在master上获取join token

1
kubeadm token create --print-join-command

重新加入节点

Reference

https://www.cnblogs.com/wangxu01/articles/11803547.html

Kubernetes

当部署完Kubernetes集群之后,为了便于管理Web UI或许是一种新型且快捷的部署方式。本节将以部署工具helm搭建Kubernetes Dashboard。以及拍坑

helm相关文档:

helm初始化

在这里推荐使用Kubernetes dashboard官方的仓库。在helm初始化完成后可使用如下命令进行helm repo初始化

1
2
# add repo
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/

为避免加入的repo非最新,可使用如下命令进行更新

1
helm repo update

效果如下所示

image-20210830201834557

helm安装Kubernetes dashboard

笔者建议使用新的namespace

1
2
3
4
# create namespace
Kubernetes create ns monitor
# helm install kubernetes dashboard
helm install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard -n monitor

输出如下所示

image-20210830210303410

等待部署完成,查看如下图所示

image-20210830221157231

修改端口暴露类型

1
kubectl edit -n monitor service kubernetes-dashboard

将type:ClusterIP修改为NodePort类型暴露端口,如下所示

image-20210830221749368

修改完成后,就可以获得暴露的端口啦,如下

image-20210830221701538

若在云服务器上请开启对应端口,笔者这里为32623

此时访问服务器ip+端口,即可进入登陆页面。如下图所示

  1. 必须为https://ip:port

  2. 建议使用火狐浏览器

image-20210830222235151

至此部署部分已经完成

获取token与授权访问

获取token

1
2
3
4
# 查看token名称
kubectl get secrets -n monitor | grep kubernetes-dashboard-token
# 查看token详情
kubectl describe secrets -n monitor | grep kubernetes-dashboard-token-你自己的后缀名

image-20210830222534534

授权

此时我们刚进去界面,发现什么资源都显示不了,是因为dashboard默认的serviceaccount并没有权限,所以我们需要给予它授权。

注意:这里直接赋予的是超级管理员权限,如果需要更加细颗粒度的授权,请参照官方的说明

https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/README.md

image-20210830222709899

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

将以上的yaml文件copy到master服务器上创建即可,当然若您也是使用的monitor 的namespace可直接使用如下命令

1
kubectl apply -f https://raw.githubusercontent.com/KubernetersDeployExample/script/main/dashboard/authorization.yaml

数据库

DML的使用

对表中的数据行进行增、删、改

向数据表内插入数据

1
2
3
4
5
6
7
8
9
# INSERT语法
INSERT [INTO] table_name [(field_name_1, field_name_2...)]
VALUES (value1, value2...),[(value1, value2...)...]
# 常见示例
## 插入
INSERT INTO ch_people_msg(`p_uic`, `p_nickname`, `p_gender`, `p_age`, `p_pnum`, `p_address`, `p_email`)
VALUES ("431122200008868162", "payne", "m", 22, 17672655132, "湖南省xx市xx区雨花a世界", "127xxxx261"),
("431122200002148162", "tom", "m", 25, 17672655132, "湖南省xx市xx区雨花a世界", "127xxxx221"),
("431122200002168163", "tom", "m", 25, 17672655132, "湖南省xx市xx区雨花a世界", "127xxxx221")
1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE IF NOT EXISTS `ch_people_msg` ( 
`p_id` SERIAL NOT NULL AUTO_INCREMENT COMMENT '用户id' ,
`p_uic` CHAR(18) NOT NULL COMMENT '用户身份证',
`p_nickname` VARCHAR(50) NOT NULL COMMENT '用户昵称',
`p_gender` ENUM('m','f', 'n') NOT NULL DEFAULT 'n' COMMENT '用户性别',
`p_age` TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户年龄',
`p_pnum` CHAR(11) NOT NULL COMMENT '用户电话',
`p_address` VARCHAR(100) NOT NULL COMMENT '用户地址',
`p_email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
`p_add_time` TIMESTAMP NOT NULL DEFAULT NOW() COMMENT '统计用户时间',
PRIMARY KEY (`p_id`),
UNIQUE KEY `p_uic`(`p_uic`)
) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE utf8mb4_general_ci COMMENT = '中国成员信息表';

1
2
3
4
5
6
DELETE FROM table_name
truncate table table_name;
DROP table table_name

delete: DML操作, 是逻辑性质删除,逐行进行删除,速度慢.
truncate: DDL操作,对与表段中的数据页进行清空,速度快.

当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小,

DELETE操作不会减少表或索引所占用的空间。

drop语句将表所占用的空间全释放掉。

释放空间与速度:drop > truncate > delete

delete

-

delete是DML,执行delete操作时,每次从表中删除一行,并且同时将该行的的删除操作记录在redo和undo表空间中以便进行回滚(rollback)和重做操作,但要注意表空间要足够大,需要手动提交(commit)操作才能生效,可以通过rollback撤消操作。

  • delete可根据条件删除表中满足条件的数据,如果不指定where子句,那么删除表中所有记录。

  • delete语句不影响表所占用的extent,高水线(high watermark)保持原位置不变。

truncate

  • truncate是DDL,会隐式提交,所以,不能回滚,不会触发触发器。
  • truncate会删除表中所有记录,并且将重新设置高水线和所有的索引,缺省情况下将空间释放到minextents个extent,除非使用reuse
    storage,。不会记录日志,所以执行速度很快,但不能通过rollback撤消操作(如果一不小心把一个表truncate掉,也是可以恢复的,只是不能通过rollback来恢复)。

  • 对于外键(foreignkey )约束引用的表,不能使用 truncate table,而应使用不带 where 子句的 delete 语句。

  • truncatetable不能用于参与了索引视图的表。

drop

  • drop是DDL,会隐式提交,所以,不能回滚,不会触发触发器。
  • drop语句删除表结构及所有数据,并将表所占用的空间全部释放。

  • drop语句将删除表的结构所依赖的约束,触发器,索引,依赖于该表的存储过程/函数将保留,但是变为invalid状态。

  • 如果想删除表,当然用drop;

  • 如果想保留表而将所有数据删除,如果和事务无关,用truncate即可;

  • 如果和事务有关,或者想触发trigger,还是用delete;

  • 如果是整理表内部的碎片,可以用truncate跟上reuse stroage,再重新导入/插入数据。

伪删除:用update来替代delete,最终保证业务中查不到(select)即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.添加状态列
ALTER TABLE ch_people_msg
ADD state TINYINT NOT NULL DEFAULT 1;
SELECT *
FROM ch_people_msg;
2.
UPDATE 替代
DELETE
UPDATE ch_people_msg
SET state=0
WHERE id = 6;
3. 业务语句查询
SELECT *
FROM ch_people_msg
WHERE state = 1;

1
UPDATE ch_people_msg SET p_nickname='zero' WHERE id=2;

1
2
# 基本语法
select--from--[where]--[group by]--[having]--[order by]

FROM:对FROM子句中的前两个表执行笛卡尔积(Cartesian product)(交叉联接),生成虚拟表VT1 ON:对VT1应用ON筛选器。只有那些使为真的行才被插入VT2
OUTER(JOIN):如果指定了OUTER JOIN(相对于CROSS JOIN 或(INNER JOIN),保留表(preserved table:左外部联接把左表标记为保留表,右外部联接把右表标记为保留表,完全外部联接把两个表都标记为保留表)中未找到匹配的行将作为外部行添加到 VT2,生成VT3.如果FROM子句包含两个以上的表,则对上一个联接生成的结果表和下一个表重复执行步骤1到步骤3,直到处理完所有的表为止。
WHERE:对VT3应用WHERE筛选器。只有使为true的行才被插入VT4.
GROUP BY:按GROUP BY子句中的列列表对VT4中的行分组,生成VT5.
CUBE|ROLLUP:把超组(Suppergroups)插入VT5,生成VT6.
HAVING:对VT6应用HAVING筛选器。只有使为true的组才会被插入VT7.
SELECT:处理SELECT列表,产生VT8.
DISTINCT:将重复的行从VT8中移除,产生VT9.
ORDER BY:将VT9中的行按ORDER BY 子句中的列列表排序,生成游标(VC10).
TOP:从VC10的开始处选择指定数量或比例的行,生成表VT11,并返回调用者。

1
2
3
# 单表子句-from
SELECT 列1,列2 FROM 表
SELECT * FROM 表

where

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 等值查询
SELECT * FROM 表 where 列 = 值
SELECT 列1,列2 FROM 表 where 列 = 值

# 比较运算符
>、<、>=、<=、!=、=
SELECT * FROM 表 where 列 >= 值
SELECT 列,... FROM 表 where 列 <= 值

# 模糊查询
%代表任何个数的任何字符 _:它代表一个任何字符
注意:%不能放在前面,因为不走索引,要找%或_,转义就行了\%和\_

# or、and
SELECT * FROM 表 where 列 >= 值 or 列 < 值

# where配合in语句
SELECT * FROM 表 WHERE 列 IN (VALUES, VALUES);

# where配合between and
SELECT * FROM city WHERE population >1000000 AND population <2000000;
SELECT * FROM city WHERE population BETWEEN 1000000 AND 2000000;

group by

根据 by后面的条件进行分组,方便统计,by后面跟一个列或多个列

max() :最大值
min() :最小值
avg() :平均值
sum() :总和
count() :个数
group_concat() : 列转行

having

​ having语句是分组后过滤的条件,在group by之后使用,也就是如果要用having语句,必须要先有group by语句。

order by

实现先排序,by后添加条件列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# distinct:去重复查询
SELECTFROM ;
SELECT DISTINCT(列) FROM city ;



# 联合查询- union all
SELECT * FROM city
WHERE countrycode IN ('CHN' ,'USA');

SELECT * FROM city WHERE countrycode='CHN'
UNION ALL
SELECT * FROM city WHERE countrycode='USA'

说明:一般情况下,我们会将 IN 或者 OR 语句 改写成 UNION ALL,来提高性能
UNION 去重复
UNION ALL 不去重复

ssh

如何优雅的从Linux服务器上进行文件“上传”与“下载”

不知你是否也遇到以下几种情形:

  • 本地电脑上传文件至Linux服务器
  • Linux服务器之间文件传递

那么如何有效、且优雅的的进行呢。特意为了此下载xshell、finalshell等软件?其实也大可不必,隐患太多也并不方便。只需要学会使用Linux中scp命令即可

scp

scp在网络上的主机之间复制文件。它使用ssh进行数据传输,并使用与ssh相同的身份验证和提供相同的安全性。scp如果身份验证需要密码或密码短语,则会询问密码或密码。

scp 是加密的,rcp 是不加密的,scp 是 rcp 的加强版。

文件名可能包含用户和主机规范,以指示将文件复制到该主机或从该主机复制文件。本地文件名可以使用绝对或相对路径名

基本使用

1
2
3
4
5
6
# 下载
scp [options] remote_ip:remote_folder(remote_file) local_folder(local_file)
scp [options] remote_user@remote_ip:remote_folder(remote_file) local_folder(local_file)
# 上传
scp [options] local_folder(local_file) remote_ip:remote_folder(remote_file)
scp [options] local_folder(local_file) remote_user@remote_ip:remote_folder(remote_file)

记忆

remote_ip 在前即下载,在后即上传

进阶使用

  • -1: 强制scp命令使用协议ssh1
  • -2: 强制scp命令使用协议ssh2
  • -4: 强制scp命令只使用IPv4寻址
  • -6: 强制scp命令只使用IPv6寻址
  • -B: 使用批处理模式(传输过程中不询问传输口令或短语)
  • -C: 允许压缩(将-C标志传递给ssh,从而打开压缩功能)
  • -q: 不显示传输进度条。
  • -r: 递归复制整个目录。
  • -v:详细方式显示输出。scp和ssh(1)会显示出整个过程的调试信息。这些信息用于调试连接,验证和配置问题。
  • -c cipher: 以cipher将数据传输进行加密,这个选项将直接传递给ssh。
  • -F ssh_config: 指定一个替代的ssh配置文件,此参数直接传递给ssh。
  • -i identity_file: 从指定文件中读取传输时使用的密钥文件,此参数直接传递给ssh。
  • -l limit: 限定用户所能使用的带宽,以Kbit/s为单位。
  • -o ssh_option: 如果习惯于使用ssh_config中的参数传递方式,
  • -P port:注意是大写的P, port是指定数据传输用到的端口号
  • -S program: 指定加密传输时所使用的程序。此程序必须能够理解ssh(1)的选项。

注意

使用scp命令要确保使用的用户具有可读取远程服务器相应文件的权限,否则scp命令是无法起作用的。

如果远程服务器防火墙有为scp命令设置了指定的端口,我们需要使用 -P 参数来设置命令的端口号,命令格式如下:

1
2
# scp 命令使用端口号 4526
scp -P 4526 remote@s2:/usr/local/checkNetwokr.sh ~/

实例脚本

使用scp实现文件(夹)分发上传到服务器

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env bash
## 远程地址列表 remote hosts List
rhs_list=(s1 s2)
## 本地文件路径
local_file=~/c.txt
## 目的文件路径
target_path=~/

for host in ${rhs_list[@]}; do
scp -C ${local_file} root@${host}:~/
done

反之也可下载

小技巧

配合ssh免密登陆与host解析scp更加丝滑哦

具体可参考基于ssh-key实现服务器免密登陆

个人随笔

自我介绍

​ 介,古代传递宾主之言的人。绍,绍继、接续。介绍指相继传话;为人引进或带入新的事物。自我介绍是向别人展示你,认识你。

​ 自我介绍好不好,重要性不言而喻其直接关系到你给别人的第一印象的好坏及以后交往的顺利与否。同时,也是认识自我的手段。

如何做好自我介绍

自我介绍一是为了更好的破冰,让别人记住你、了解你等,那么如何做自我介绍自然也从这几点切入。

自嘲式

适用场景:演讲

关键词:破冰

有趣的自嘲可以快速吸引注意力,让人对你记忆犹新。

例如:你(大家)好,我叫xxx。原本想做一名x x x,可能是xxx不太好。所以目前做了xxx

八卦式

适用场景:非正式场合

关键词:好奇

在远古社会,智人凭借八卦,使整个群体更趋于稳定和学会更多的协作,而协作就是智人强大起来的秘诀,但是为什么八卦可以使一个族群稳定和协作呢?因为信任,因为八卦这种社交行为可以让智人相互信任,而信任的基础就是相互了解,八卦就是智人相互了解的过程。
——《人类简史》

例如:大家好,我叫xxx,来自xxx,(合理热点)结果xxx。我xxx

自荐式

适用场景:商务场合、聚会,面试

关键词:自我推荐

我是xxx,他人最需要自我价值面。

切记避免多次,尽量全面

爬虫

知己知彼,百战不殆 ——《孙子兵法》。

本文仅总结鄙人所知的反爬虫方式,不涉猎任何具体的分析与绕过方案。

反爬虫

反爬虫,即应对爬虫进行反制的统称,主要区分“正常用户”与“机器人”的一种策略统称

认识反爬虫

​ 正所谓知其然,知其所以然。对于反爬虫的措施有所了解与认知,一方面便于快捷定位防护点实现分析或绕过,另一方面组成爬虫攻防体系。万变自不离其宗,应对反爬虫措施游刃有余。一般常在如下几大部分设伏

以下便不考虑第三方测试工具的校验

请求前校验

抓包拦截

​ 做过爬虫的小伙伴,一定知道在分析加密、执行爬虫项目之前。首先第一步一定是先抓包,定位到对应数据包,然后继续才进行分析或规律。那么在此无疑是最为有效
的反抓,捕获不到流量包URL未知,除了使用自动化测试工具、RPC等通常可能都毫无办法。

抓包拦截又可细分为控制台检测、端口转移、证书校验,私有协议总而言之就是让你抓不到包,其方法无所不用其极。

控制台检测抓包绕过策略:

  • 替代法: 采用中间人抓包(Charles、mitmproxy、firdler等)

  • 分析绕过法:定位到检测处,分析绕过

端口转移绕过策略:

  • 强制端口
  • 流量转发

证书锁定与公钥锁定

​ 为了防止中间人攻击,采用SSL-Pinning的技术来反抓包。 中间人抓包要点是伪造了一个假的证书实现拦截与转发,从而在中间获取的过路数据包实现抓包。
反抓思路就是,客户端也预置一份服务端的证书,比较一下就知道真假了。SSL-pinning有两种方式证书锁定(Certificate Pinning)与公钥锁定(Public Key Pinning)

证书锁定

​ 证书锁定是SSL/TLS加密的额外保证手段。它会将服务器的证书公钥预先保存在客户端。在建立安全连接的过程中,客户端会将预置的公钥和接受的证书做比较。
如果一致,就建立连接,否则就拒绝连接。在客户端设置证书只允许设置指定域名的证书,而不接受操作系统或浏览器内置的CA根证书对应的任何证书。

公钥锁定

HTTP公钥锁定是HTTPS网站防止攻击者CA机构错误签发的证书进行中间人攻击的一种安全机制,用于预防CA遭受入侵或其他会造成CA签发未授权证书的情况。
采用公钥锁定时,网站会提供已授权公钥的哈希列表,指示客户端在后续通讯中只接受列表上的公钥。提取证书中的公钥并内置到客户端中,通过与服务器对比公钥值来验证连接的正确性。

绕过:Hook到证书校验,无论如何返回正确的即可

私有协议通讯

一线大厂自定义通讯协议,自然考虑到了抓包。那么自然而然也设置了反抓包

绕过:Hook、沙箱

运行环境检测

CDN网络分发加验证:经典产品5秒盾

其核心为 请求 -> cdn -> 返回关键参数 -> 通过 -> 数据(可能为假)

请求校验

当抓到包之后,便是模拟用户请求了。那么这里的常见的反抓措施有哪些呢

请求校验,即在发送请求时即对网络请求时进行校验,实现区分。通过则返回数据,未通过不返回或返回假数据常有如下几种方式

协议校验

常见通用的协议有HTTP1.0、 HTTP1.1、HTTP2.0 ,若强行只允许HTTP2.0协议来完成请求与响应。那么平常使用其他

TSL指纹

每个请求库其实是有自己的库指纹,若只允许某段或某规则指纹通过,那么自然而言实现了反抓的效果。

header校验

header校验又可分为两种。其一是字段校验,其二是header字段顺序校验

header各字段校验,如ua、sign、cookie、token、safe等

绕过方案或思想:
通过JS解密或逆向获取关键参数缺啥补啥,完成模拟即可

header字段顺序:当我们打开一个网页其实是一个新的会话那么在未断开或重新连接的时候那么这个顺序就是固定的。而字典格式中位置其实是随机分配的,自定义客户端刷新,对header取指纹或字段顺序检测即可实现鉴别

绕过方案或思想:保持会话一致

参数校验

通常字段不仅在header中校验还经常在请求参数中,如sgin、token、safe等。

参数不可无缘无故来,主要来源JS 生成、服务器下发(不限于文件、JS、wasm等)。又可进行多次中间操作

前后端分离技术Ajax

严格来说并不算反扒而是前后端分离技术,但常常结合反抓共同出现

Ajax(异步JavaScript和XML)也叫不刷新页面请求。

RPC防护

采用RPC及加密或编码方式实现前后端分离、微服务架构等。

rpc结合反抓基本步骤,客户端请求(中间极有可能涉猎加密)RPC服务端,RPC客户端(原服务端)再次(中间极有可能涉猎加密)请求(一次或多次)。实现“分端”请求,多端加密。

逆写rpc进行调用,模拟“第一次”客户端请求rpc无差别,绕过

请求校验小结

通常设置参数有两种情况,

  1. 二次或多次请求:
    1. RPC:客户端请求,服务端使用RPC等再请求。
    2. AJax
  2. JS设置关键参数(含二次刷新删除源文件跳转页面

验证码

  • 识别点选或输入型
  • 滑轨、滑块型
  • 计算型
  • 空值补齐型
  • 空间推理型
  • 短信或语音验证型

风控

范围极大极广,简而言之,用户行为、运行环境等是否合理。从而实现区分

IP封禁

代码运行环境检测

数据保护

在不改变原有展示的情况下实现“隐藏”

通常数据保护有以下种方式:

  1. 动态字体
  2. CSS偏移
  3. 内容加密映射
  4. SVG映射等
  5. 内容图片化

代码防护

JS代码混淆

在遇见需要逆向的参数时候,往往不像表面一个参数那般平静。一查看各种混淆、防护又来了。怎么办怎么办,肝啊!当然也可以使用渲染工具模拟,此方案在此便不在过多赘述。

代码混淆是增加分析难度而牺牲部分性能的一种方案,此方案大部分是体现在通过逻辑转换换等方式将代码转化为难以分析的代码。难以分析是混淆的目的,等价转换是需要确保混淆前后的代码需不影响运行的功能。对于混淆可以又分为如下四种:布局混淆、数据混淆、控制混淆、预防混淆

布局混淆

布局混淆指在源代码中删除原有无用代码,处理常量名、变量名函数名等标识符,增加对于代码的阅读与分析。

无用代码:注释、调试信息、缩进、换行、无用函数与数据等

处理常量名、变量名函数名等标识符:

  • 标识重命名:将原有代码重命名为无具体意义的字符,例如 将name 重命名为a

注意点:作用域内标识符碰撞情况

小结:布局混淆并不会影响执行的过程、内存开销,甚至代码体积反而减少了。

数据混淆

JS拥有常见的7种数据类型,number、string、boolean、unfined、null、Object

数字混淆

数据混淆有常见:进制转换、数字分治、其他

  • 进制转换:将十进制转化为二进制、八进制、十六进制等,从而达到“混淆”的目的

  • 数学分治:简而言之就是将数拆开,例如 2 = 1 + 1,也等于2 - 1 - 1 + 2再辅以数学公式等

  • 其他:重新赋值等

字符串混淆

字符串混淆常见的有编码转换编译、加密。常见的有hash、base64、md5等

boolean

我们都知道Boolean值为True、False。根据对boolean的处理,变成难以显示阅读的代码。

1
2
3
4
5
6
7
8
9
10
11
!0,!1
![], !![]
!{},!!{}
!NaN,!!NaN
!"", !!""
!undefined, !!undefined
!null, !!null
!Object, !!Object
!void(0),!!void(1)

|,||, &, &&, Boolean()

控制混淆

控制混淆是指对程序的控制流进行转换变化,常见的方式有插入僵尸代码、控制流平坦化

插入僵尸代码:插入僵尸代码即插入无用的代码,增强调试难度

控制流平坦化:控制流平坦化,将原本的的执行流程平坦化。具体可自行搜索

预防混淆

主要体现在 提高反混淆的难度或检测现有混淆器中的漏洞设计

JS虚拟机

自定义或定制JavaScript虚拟机,基于给予二进制文件获取结果

Android/iOS SDK 加固保护

代码混淆

具体可参考JS混淆部分,殊归同途

Dex 加固与抽取

​ Dex 加固即将需要保护的代码单独生成Dex,在so加载时解密jar并通过DexClassLoader加载到内存里。该方案的主要问题在于解密后的Dex会以文件形式存储在手机内存中,而且通过内存dump 的方式能够获取解密后的jar
包,而没有生成文件加载的方式存在很多兼容性的问题

​ 在实际对抗环境下,Dex 无论如何保护,都有方法还原至原始的Dex,进而反编译得到Java 代码。而C 代码相对而言较难逆向。Java2c 是指将原有的Java 代码抽取出来,通过jni 在native 层反射实现。

流程如下:Dex→smali→抽取+native 化→生成so

抽取后的原始Java 函数,反编译出来是native 函数,在运行过程中也不会还原。Java2c 配合C 语言的代码混淆技术和字符串混淆技术,可以对Android 的Java 代码起到很好的保护效果。同时也不需要对原始Java 代码进行重写

LLVM

LLVM 是Low Level Virtual Machine 的缩写,其定位是一个比较底层的虚拟机。然而LLVM 本身并不是一个完整的编译器,LLVM
是一个编译器基础架构,把很多编译器需要的功能以可调用的模块形式实现出来并包装成库,其他编译器实现者可以根据自己的需要使用或扩展,主要聚焦于编译器后端功能,如代码生成、代码优化、JIT 等。

代码虚拟化

​ 代码虚拟化保护技术是一种比Dex 文件保护、Java2c 技术更强的安全防护技术,可以更有效地对抗逆向工程或破解,避免造成核心技术和风控逻辑被泄密的问题。

总结

1
2
graph LR
A(已有)==无数次的中间转换==> B1(所需)

以上便是本人对于所见所知所想的反爬虫,各种加密、编译、混淆等。中间围绕无数种可能。一起加油吧!!!

好像什么都说了,什么都没说。望君参考却不限于此。

总体来说就是抓包、请求前校验、请求校验、数据保护。以及风控、验证码、及对于代码进行保护。

数据库

SQL介绍

结构化查询语言,5.7 以后符合SQL92严格模式,通过sql_mode参数来控制

DDL(Data Definition Language,数据定义语言):用于定义数据库、数据表和列,可以用来创建、删除、修改数据库和数据表的结构,包含CREATE、DROP和ALTER等语句。

DML(Data Manipulation Language,数据操作语言):用于操作数据记录,可以对数据库中数据表的数据记录进行增加、删除和修改等操作,包含INSERT、DELETE和UPDATE等语句。

DCL(Data Control Language,数据控制语言):用于定义数据库的访问权限和安全级别,主要包含GRANT、REVOKE、COMMIT和ROLLBACK等语句。

DQL(Data Query Language,数据查询语言):用于查询数据表中的数据记录,主要包含SELECT语句。

阅读全文 »

数据库

MySQL数据类型

MySQL支持丰富的数据类型,总体上可以分为数值类型、日期和时间类型、字符串类型。

数值类型包括整数类型、浮点数类型和定点数类型;字符串类型包括文本字符串类型和二进制字符串类型;

具体入下所示

主要包括以下几大类: 数值类型:

  • BIT、BOOL、TINYINT、SMALLINT、MEDIUM INT、 INT、 BIG INT、

  • FLOAT、DOUBLE、DECIMAL(浮点数类型)

字符串类型:CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、TINY BLOB、BLOB、MEDIUM BLOB、LONG BLOB、ENUM、SET

日期类型:Date、DateTime、TimeStamp、Time、Year

空间类型:Geometry、Point、LineString、MultiPoint、MultiLineString、MultiPolyGon、Polygon、GeometryCollection

其他类型:JSON

阅读全文 »

数据库

MySQL体系结构

C/S(Client/Server)模型

​ C/S结构是一种软件系统体系结构,

​ C是英文单词“Client”的首字母,即客户端的意思,C/S就是“Client/Server”的缩写,即“客户端/服务器”模式。MySQL C/S 可如下图所示

MySQL 连接

实现MySQL连接的方式主要有两种,

  • 基于TCP/IP的连接,适用于远程、本地
  • 基于Socket方式连接,仅限于本地连接
1
2
3
4
5
# TCP/IP方式(远程、本地)
mysql -h 192.168.0.51 -P 3306 -u root -p paynepasswd

# Socket方式(仅本地)
mysql -S /tmp/mysql.sock -u root -p paynepasswd

阅读全文 »

数据库

MySQL数据库一些概念

数据库的定义


数据库的定义在某种程度上,数据库代表着一种存储技术,并不局限于某种存储形式。一个简单的数据库可以将数据只存储在某台特定的计算机上,供某个特定的用户使用,而一个复杂的数据库可以将数据分散存储到多台计算机上,能够供成千上万的用户同时使用。从存储容量上来说,一个数据库的存储容量可以小到只能够存储几KB的数据,也可以大到存储TB甚至是PB级别的数据。

数据库


数据库(DataBase,DB)从本质上讲就是一个文件系统,它能够将数据有组织地集合在一起,按照一定的规则长期存储到计算机的磁盘中,并且能够供多个用户共享和使用,同时,用户能够对数据库中的数据进行插入、删除、修改和查询操作。数据库将数据进行集中存储和管理,有效地分离了应用程序和业务数据,降低了应用程序和业务数据之间的耦合性,大大简化了数据的存储和管理工作。同时,数据库提供了对存储数据的统一控制功能。数据除了能够被存储在计算机的磁盘中,还能够被存储在计算机的内存中,所以在某种程度上,可以将数据库分为永久型数据库和内存型数据库。

数据表


对于关系型数据库来说,数据表是以一个二维数组的形式来存储和管理数据的,它能够存储和管理数据并操作数据的逻辑结构。通常,一个数据表由行和列组成,一行数据能够表示一条完整的基础信息,所以行在关系型数据库中是组织数据的基本单位;列也被称为字段,它能够表示行的一个属性,同时,每一列都有相应的数据类型和数据长度的定义。

数据类型


关系型数据库中的数据类型表示数据在数据库中的存储格式,其反映了数据在计算机中的存储格式。计算机根据不同的数据类型来组织和存储数据,并为不同数据类型的数据分配不同的存储空间。数据类型在大的分类上可以分为数值类型、日期和时间类型、字符串类型。在关系型数据库中,表中的每个字段都会被指定一种数据类型。例如,表1-1中,将商品编号、商品名称和商品类型定义为字符串类型,将商品价格定义为数值类型(定点数类型),将上架时间定义为日期和时间类型。

阅读全文 »

密码学

作为一名优秀的新时代农民工,加密解密、编码算法自然逃不了。为了更安全、更隐蔽 数字签名,信息加密在开发过程中一定少不了,例如用户密码、关键消息等等,所以密码学至关重要。

作为爬虫工程师,逆向工程师见到目标的加密后的结果,而又无法有效的获取与定位到关键函数。那岂不是抓瞎,那么如果对于常见的加密、编码算法算法有足够的了解,那么是可以便捷很多,例如

  • 根据特征结果,直接Hook对应函数。通常有奇效
  • 根据特征结果,与所知的参数进行尝试碰撞。也可大幅度减少分析时间

等等,书到用时方恨少,知识与见识自然也是。

阅读全文 »

爬虫

调试与反调试

相信各位如果从事爬虫开发、反爬虫开发、逆向工程师及相关岗位的开发,一定逃不开调试、反调试。那调试与反调是什么呢?以下为浏览器为例

调试:自然就是为了分析获取某关键加密参数,便对于目标网站的JS进行分析。

反调试:为了参数更加安全,更加难以破解。在合适处增加障碍增强调试难度

简单来说调试就是为了获取对应的加密参数,而反调试是为了不那么容易调试,增加调试难度。

反调试可以分为调试检测、调试陷阱,而反反调试是伪装,是绕过。

阅读全文 »

ssh

远程连接Linux服务器,通常有两种方式, 第一种就是ssh直接远程连接, 第二种就是采用第三方的工具进行连接。 那么我本人是十分习惯以及喜欢终端(terminal)直接连接的。
一是因为快捷键更熟悉,另一方面是相对更安全。但采用ssh直接连接难免是有很多不便, 例如每次输入密码,例如每次输入远程ip地址。
密码我个人是喜欢设置成非常难以记忆的密码,保存在本地一个记事本或者文档里面,ip更不用说。记自然是不可能记的。那么如何实现ssh免密登陆以及ip的代号呢

阅读全文 »