Mysql删除操作卡死

mysql中使用int类型来查询string字段,会进行隐式转换。
如果 该字段存在索引,则会无法使用到 该string类型的索引导致操作超时缓慢。
且如果该字段存在索引则会导致delete操作会进行锁表。其他客户端也无法使用delete操作。导致卡死。

解决问题

此时需要 查看当前有哪些卡住的进程

1
SHOW FULL PROCESSLIST ;

然后kill当前进程
1
kill 574611;

1.MySQL 隐式转换问题,隐藏的深,不容易被发现,在进行 delete , update 等操作时,一不小心很容易大问题,从而造成事故。

2.对于 delete , update 等操作时,建议先使用 select 语句,看看获取的结果和预期的是否一致,再进行操作,相对会更安全一些。

如果是清空表数据建议直接用 truncate,效率上 truncate 远高于 delete,
应为 truncate 不走事务,不会锁表,也不会生产大量日志写入日志文件;
truncate table table_name 后立刻释放磁盘空间,并重置 auto_increment 的值。
delete 删除不释放磁盘空间,但后续 insert 会覆盖在之前删除的数据上

1.降低写错 SQL 的代价,就算删错了,比如 limit 500, 那也就丢了 500 条数据,并不致命,通过 binlog 也可以很快恢复数据。
2。避免了长事务,delete 执行时 MySQL 会将所有涉及的行加写锁和 Gap 锁(间隙锁),所有 DML 语句执行相关行会被锁住,如果删除数量大,会直接影响相关业务无法使用。
3.delete 数据量大时,不加 limit 容易把 cpu 打满,导致越删越慢。

注: 针对上述第二点,前提是 sex 上加了索引,大家都知道,加锁都是基于索引的,如果 sex 字段没索引,就会扫描到主键索引上,那么就算 sex = 1 的只有一条记录,也会锁表。

对于 delete limit 的使用,MySQL 大佬丁奇有一道题:
如果你要删除一个表里面的前 10000 行数据,有以下三种方法可以做到:
第一种,直接执行 delete from T limit 10000;
第二种,在一个连接中循环执行 20 次 delete from T limit 500;
第三种,在 20 个连接中同时执行 delete from T limit 500。
方案一、事务相对较长,则占用锁的时间较长,会导致其他客户端等待资源时间较长。
方案二、串行化执行,将相对长的事务分成多次相对短的事务,则每次事务占用锁的时间相对较短,其他客户端在等待相应资源的时间也较短。这样的操作,同时也意味着将资源分片使用(每次执行使用不同片段的资源),可以提高并发性。
方案三、人为自己制造锁竞争,加剧并发量。
注: 方案二相对比较好,具体还要结合实际业务场景。

参考: https://blog.csdn.net/weixin_39939530/article/details/110506783

children_join_sql

SELECT “id”, “subs”, “name”, “sort”, “level”, “state”,
(SELECT cast(COUNT(*) as integer) AS “count” FROM “goods” AS “goods” WHERE “goods”.”deletedAt” IS NULL AND “goods”.”state” = 1 AND “goods”.”classes” && ARRAY[“class”.”id”]::INTEGER[]) AS “goods_count”
FROM “classes” AS “class”
WHERE ((“class”.”deletedAt” > ‘2020-06-08 15:55:25.728 +08:00’ OR “class”.”deletedAt” IS NULL) AND (“class”.”level” = 1 AND “class”.”state” = 1 AND “goods_count”>0)) ORDER BY “class”.”sort” ASC, “class”.”id” DESC;

【AND “goods_count”>0】
上面查询sql语句想查询出class表中信息并且查询出其与goods数据表关联字段的信息
上述查询会出现报错,因为 子查询中使用了父查询中的检索信息,使得父查询的生命周期高于子查询,此时父查询中无法查询子查询的字段数据。

改为下列请求

SELECT “class”.”id”, “class”.”subs”, “class”.”name”, “class”.”sort”, “class”.”level”, “class”.”state”, cast(COUNT(“goods”.”id”) as integer) AS “count”
FROM “classes” AS “class” RIGHT OUTER JOIN goods on (“goods”.”deletedAt” IS NULL AND “goods”.”state” = 1 AND “goods”.”classes” && ARRAY[“class”.”id”]::INTEGER[])
WHERE ((“class”.”deletedAt” > ‘2020-06-08 15:55:25.728 +08:00’ OR “class”.”deletedAt” IS NULL) AND (“class”.”level” = 1 AND “class”.”state” = 1))
GROUP BY “class”.”id”
ORDER BY “class”.”sort” ASC, “class”.”id” DESC ;

或者在父查询中再次使用联合检索数据

SELECT “id”, “subs”, “name”, “sort”, “level”, “state”,
(SELECT cast(COUNT() as integer) AS “count” FROM “goods” AS “goods” WHERE “goods”.”deletedAt” IS NULL AND “goods”.”state” = 1 AND “goods”.”classes” && ARRAY[“class”.”id”]::INTEGER[]) AS “goods_count”
FROM “classes” AS “class”
WHERE ((“class”.”deletedAt” > ‘2020-06-08 15:55:25.728 +08:00’ OR “class”.”deletedAt” IS NULL) AND (“class”.”level” = 1 AND “class”.”state” = 1 AND (SELECT cast(COUNT(
) as integer) AS “count” FROM “goods” AS “goods” WHERE “goods”.”deletedAt” IS NULL AND “goods”.”state” = 1 AND “goods”.”classes” && ARRAY[“class”.”id”]::INTEGER[])>0)) ORDER BY “class”.”sort” ASC, “class”.”id” DESC;

buckup

#!/bin/bash

/Applications/pgAdmin 4.app/Contents/SharedSupport/pg_dump

–file “/Users/wqiong/buttons.sql”

–host “127.0.0.1”

–port “52260”

–username “postgres”

–no-password –verbose –format=c

–blobs “auth_dev_old”

/Applications/pgAdmin\ 4.app/Contents/SharedSupport/pg_dump \

–file “/Users/wqiong/buttons.sql” \

–host “dev.guaishoubobo.com” \

–port “5432” \

–username “postgres” \

–no-password –verbose –format=c \

–blobs “race_dev” “auth_dev”

pg_dump –file “/data/www/buttons.sql” –host “dev.guaishoubobo.com” –port “5432” –username “postgres” –no-password –verbose –format=c –blobs “race_dev”;

/Applications/pgAdmin 4.app/Contents/SharedSupport/pg_dump

–file “/Users/wqiong/buttons.sql”

–host “dev.guaishoubobo.com”

–port “5432”

–username “postgres”

–no-password –verbose –format=c

–blobs –table “public.uniques” “auth_dev”

dir=”/data/www/DatabasesBackup/“

echo “cd ${dir}”

cd $dir

echo ‘DATE=date +%Y%m%d-%H%M

BACK_DATA=xxapp-data-${DATE}.out # 这里设置备份文件的名字, 加入日期是为了防止重复

docker exec pg-db pg_dumpall -U postgres > ${BACK_DATA} # pg-db 是数据库的 docker 名称’

docker exec pg-db pg_dumpall -U postgres > ${BACK_DATA}

docker exec postgres pg_dump \

–file “buttons.sql” \

–host “dev.guaishoubobo.com” \

–port “5432” \

–username “postgres” \

–no-password –verbose –format=c \

–blobs “race_dev” -U “postgres” -W

O8MxsIhH

docker exec postgres pg_dump -U “postgres” –blobs “race_dev” –no-password –verbose –format=c –file “buttons.sql”

/Applications/pgAdmin\ 4.app/Contents/SharedSupport/pg_dump –file /root/gresql.sql\

–username “postgres” \

–no-password –verbose –format=c \

–blobs “race3”

-U “postgres” -W

//压缩模式二进制模式

docker exec postgres pg_dump –username “postgres” –no-password –verbose –format=c –blobs “race_dev” -f /data/backup.sql

docker exec postgres pg_restore –username “postgres” –no-password -c –verbose -d “test” /data/backup.sql

# //非压缩模式 ,pgsql模式

docker exec postgres pg_dump –username “postgres” –no-password –verbose –blobs “race_dev” -f /data/backup.sql

docker exec postgres psql –username “postgres” -d test3 -f /data/backup.sql

docker exec postgres pg_dump -h db -f /shared/backup.sql

for(var i in maps){

console.log(222)

addMarker(maps[i]);

}

dir=”var/lib/postgresql/buckup”

echo “cd ${dir}”

cd $dir

进入docker bash

echo “docker exec -it postgres bash”

docker exec -it postgres bash

将用户置为 postgres

echo “su postgres”

su postgres

进入sql命令行

echo “psql”

psql

展示所有数据库列表

\list

redis_contenxt

Redis的基本类型
1.String字符串:
格式:set key value
string类型是二进制安全的。redis的string类型可以包含任何数据,例如图片或者序列化的对象。string类型是Redis的最基本的数据类型,一个键最大能存储512MB。
2.Hash哈希
格式:hmset name key value
redis的hash是一个键值对key value的集合。
redis的hash是一个string类型的field和value的映射表,hash适合用于存储对象。
hash = {
key1:value1,
key2:value2,
kay3:value3
}
3.List列表
Redis的列表是简单的字符串列表,按照插入顺序,你可以添加一个元素到列表的头部,或者尾部。
格式:lpush name value
在key对应list的头部添加字符串元素。
格式rpush name value
在key对应list的尾部添加字符串元素
格式lrem name index
4.Set集合
格式:sadd name value
Redis的Set是string类型的无序集合。
集合是通过hash表实现的所以添加删除查找的复杂都是O(1)
5.Zset 有序集合
格式 zadd name score value
Redis zset 和set 一样也是string类型元素的集合,且不允许重复的成员
不同的是每个元素都会关联一个double类型的分数,redis是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,分数是可以重复的。
其中分数score是double 16位超过位数 会转换成科学算法所以最好不要超过16位
Redis持久化
1.RDB
rdb是Redis DataBase缩写
功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数

2.AOF
    Aof是Append-only file缩写
    每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作
    aof写入保存:
        WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件
        SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。
比较:
1、aof文件比rdb更新频率高,优先使用aof还原数据。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果两个都配了优先加载AOF

搭建redis集群 (使用docker搭建redis-cluster环境)

1.下载redis镜像。
1
docker pull redis
2.创建docker的虚拟网卡
1
docker network create redis-net
查看docker的网卡信息
docker network ls
查看docker网络详情
docker network inspect redis-net

可以看到docker虚拟镜像分配的网关以及网络组

创建redis配置文件模板
本文例子在/home文件夹中操作
mkdir -p /home/redis-cluster
cd /home/redis-cluster
vim redis-cluster.tmpl
在redis-cluster.tmpl中输入以下内容
1
2
3
4
5
6
7
8
port ${PORT}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.168.131
cluster-announce-port ${PORT}
cluster-announce-bus-port 1${PORT}
appendonly yes

port:节点端口,即对外提供通信的端口
cluster-enabled:是否启用集群
cluster-config-file:集群配置文件
cluster-node-timeout:连接超时时间
cluster-announce-ip:集群各节点IP地址
cluster-announce-port:集群节点映射端口
cluster-announce-bus-port:集群总线端口
appendonly:持久化模式

cluster-announce-ip:这个IP需要特别注意一下,如果要对外提供访问功能,需要填写宿主机的IP,如果填写docker分配的IP(172.x.x.x),可能会导致部分集群节点在跳转时失败。

4、创建节点配置文件
  在redis-cluser文件夹中执行以下命令
1
2
3
4
5
6
for port in $(seq 8010 8015); \
do \
mkdir -p ./${port}/conf \
&& PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redis.conf \
&& mkdir -p ./${port}/data; \
done

循环8010 - 8015这6个端口 在当前文件下(即redis-cluster)下创建 8010-8015这6个文件夹,在每个文件夹下面创建conf文件夹和data文件夹然后再在conf文件夹下面创建redis.conf文件。
将redis-cluster.tmpl文件拷贝到各个文件redis.conf配置文件中。

5.使用docker创建redis节点容器
for port in $(seq 8010 8015); \
do \
docker run -it -d -p ${port}:${port} -p 1${port}:1${port} \
–privileged=true -v /home/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \
–privileged=true -v /home/redis-cluster/${port}/data:/data \
–restart always –name redis-${port} –net redis-net \
–sysctl net.core.somaxconn=1024 -d redis:5 redis-server /usr/local/etc/redis/redis.conf; \
done
该命令即创建端口从8010到8015的redis容器并使用之前创建的配置文件

可查看docker给每个节点分配的ip信息

1
docker network inspect redis-net | grep -i -E ”name|ipv4address“

6.将以上redis容易创建成一个redis-cluster集群
随便进入一个容器
docker exec -it redis-8010 bash

1
2
3
4
cd /usr/local/bin/

redis-cli --cluster create 【之前的ip】:8010 【】:8011 【】:8012 【】:8013 【】:8014 【】:8015

测试是否成功
在其中一个容器内执行

1
redis-cli -c -h 【ip】 -p 8010

set a aaaa
get a 会输出aaaa

在其他地方使用redis-cli测试集群是否可访问同上
转载于 使用docker搭建redis集群[https://www.jianshu.com/p/1fb5e651b053]

request

https原生
// let options = {
// ‘method’: ‘post’,
// ‘pfx’: pfx,
// ‘passphrase’: pay_conf.mchid,
// };
// // options.agent = new https.Agent(options);
// const req = https.request(url, options, res => {
// console.log(‘状态码:’, res.statusCode);
// console.log(‘请求头:’, res.headers);
// let data = ‘’;
// res.on(‘data’, d => {
// data += d;
// });
// res.on(‘end’, () => {
// console.log(data);
// });
// });
// req.on(‘error’, e => {
// console.error(e);
// });
// req.write(xmlOption);
// req.end();
superagent
// let options = {
// ‘method’: ‘post’,
// ‘pfx’: pfx,
// ‘passphrase’: pay_conf.mchid,
// };
// options.agent = new https.Agent(options);
// let result = await request.post(url)
// .send(xmlOption)
// .pfx({
// ‘pfx’: pfx,
// ‘passphrase’: pay_conf.mchid,
// })
// .key()
// // .set({
// // ‘agent’: options.agent,
// // })
// .type(‘xml’)
// .then(data => {
// console.log(data.text);
// })
// .catch(err => {
// console.log(err);
// });

已经不维护的request
        // require('request')({
//     'method': 'post',
//     'url': url,
//     'body': xmlOption,
//     'agentOptions': {
//         'pfx': pfx,
//         'passphrase': pay_conf.mchid,
//     },
// }, (err, res, body) => {
//     console.log(res);
// });

superagent 如何模拟html的表单上传文件
superagent
.post(‘/upload’)
.field(‘user[name]’, ‘Tobi’)
.field(‘user[email]’, 'tobi@learnboost.com‘)
.field(‘friends[]’, [‘loki’, ‘jane’])
.attach(‘image’, ‘path/to/tobi.png’,{
contentType: ‘mime/type’
})
.then(callback);

nginx配置介绍

1.静态文件配置
2.服务器代理配置
3.反向代理配置
4.socket升级协议配置
5.日志分组配置

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yun.x.com;

ssl_certificate "/etc/nginx/cert/_.x.com.pem";
ssl_certificate_key "/etc/nginx/cert/_.x.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

add_header Access-Control-Allow-Credentials true;

include /etc/nginx/default.d/*.conf;
#从系统时间中正则匹配出年月日
#if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") {
# set $date $1$2$3;
#}
# 日期记录日志
#access_log /var/log/nginx/$date-access.log;

if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") {
#set $date $1$2$3;
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
set $minutes $5;
}
#错误日志记录
location /error.gif {
default_type image/gif;
#此请求不缓存
add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";
add_header Pragma "no-cache";
add_header Cache-Control "no-cache, max-age=0, must-revalidate";
#返回一个1×1的空gif图片
empty_gif;
#if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") {
#if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") {
# #set $date $1$2$3;
# set $year $1;
# set $month $2;
# set $day $3;
# set $hour $4;
# set $minutes $5;
#}
# 日期记录日志
access_log /var/log/nginx/$year-$month-$day-$hour-error.log main;
}
location /log.gif {
#真实gif图片
log_subrequest on;
access_log /var/log/nginx/gif_access.log main;
#此请求不缓存
default_type image/gif;
add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";
add_header Pragma "no-cache";
add_header Cache-Control "no-cache, max-age=0, must-revalidate";
#返回一个1×1的空gif图片
empty_gif;
access_log /var/log/nginx/$year-$month-$day-$hour-access.log main;
}

git回滚操作

1.暴力重置
先gitreset 到该分支之前某个节点
git reset –hard HEAD
然后进行强制推送到远程处理
git push -u origin master -f
origin:远程仓库名 master:分支名称 -f:force,意为强制、强行

2.覆盖恢复
git revert -n branch 覆盖到之前某个节点
git commit -m “revert add text.txt” 提交信息
git push 推送到远程

docker_logstash

docker pull logstash:7.8.0

docker run -d –restart=always –log-driver json-file –log-opt max-size=100m –log-opt max-file=2 -p 5044:5044 –name logstash -v /data/logstash/logstash.yml:/usr/share/logstash/config/logstash.yml -v /var/log/nginx/gif_access.log:/var/log/gif_access.log -v /data/logstash/conf.d/:/usr/share/logstash/conf.d/ logstash:7.8.0

注意:Kafka 从 2.2 版本开始将 kafka-topic.sh 脚本中的 −−zookeeper 参数标注为 “过时”,推荐使用 −−bootstrap-server 参数。若读者依旧使用的是 2.1 及以下版本,请将下述的 –bootstrap-server 参数及其值手动替换为 –zookeeper zk1:2181,zk2:2181,zk:2181。一定要注意两者参数值所指向的集群地址是不同的。

————————————————
版权声明:本文为CSDN博主「Ernest.Wu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_29116427/java/article/details/80206125

docker_kafka

docker pull zookeeper
docker run -d –name zookeeper -p 2181:2181 -v /data/zookeeper/localtime:/etc/localtime wurstmeister/zookeeper
docker run –privileged=true -d –name zookeeper –publish 2181:2181 -v /data/zookeeper/localtime:/etc/localtime -d zookeeper:latest

/var/lib/docker/overlay2/8d703e1973c54e951f836471d40fab8741bf2aabb88e717d7c244bb2874abe09/merged/etc/localtime

docker pull wurstmeister/kafka

docker run -d –name kafka -p 9092:9092 -e KAFKA_BROKER_ID=0 -e KAFKA_ZOOKEEPER_CONNECT=172.19.112.8:2181/kafka -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://172.19.112.8:9092 -e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092 -v /data/kafka/localtime:/etc/localtime wurstmeister/kafka

https://www.jianshu.com/p/e8c29cba9fae

–zookeeper 172.19.112.8:2181
nginx-access-kafkaceshi