OMG_By

沉心、静气、学习、总结、进步


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

Redis文章学习记录

发表于 2222-07-06 | 分类于 Redis

这篇博文主用来记录读到的Redis相关的文章

实践案例

  • 近千节点的Redis Cluster高可用集群案例:优酷蓝鲸优化实战:详细的介绍了Redis Cluster下心跳信息对带宽的影响。
  • 干货 | 携程Redis海外机房数据同步实践:携程开源 Redis 多数据中心复制管理系统 X-Pipe
  • 优酷蓝鲸近千节点的Redis集群运维经验总结:Redis Cluster运维时遇到的一些问题(实用)
  • 同程旅游缓存系统设计:如何打造Redis时代的完美体系:携程Redis架构发展历程(推荐阅读)
  • Redis实战:如何构建类微博的亿级社交平台
  • 日请求量过亿,谈陌陌的Feed服务优化之路
  • Redis 应用实践:小红书海量 Redis 存储之道
  • 如何实现高可用的redis集群:客户端分片模式的Redis集群方案
  • 唯品会大规模 Redis Cluster 的生产实践
  • 这可能是最全的 Redis 集群方案介绍了
  • Redis 集群的合纵与连横
  • Redis时延问题分析及应对
  • 干货来袭!Redis技术盛宴——阿里云Redis交流会火热召开
  • 首发丨360开源的类Redis存储系统:Pika
  • The Endless Redis Replication Loop: What, Why and How to Solve It
  • Top Redis Headaches for Devops – Replication Buffer
  • 一次教科书级别的Redis高可用架构设计实践
  • 美团在Redis上踩过的一些坑-1.客户端周期性出现connect timeout
  • 美团点评万亿级 KV 存储架构演进
  • 牛逼!完美解密Redis与秒杀系统!!!
  • 浅谈redis超时(二):翻译官方的redis延迟排查步骤。学习到了新命令(latency)
  • 使用 redis_builder 管理 redis 集群:C++编写的redis cluster集群工具
  • Redis 容器与配置
  • Docker化高可用redis集群:docker搭建Redis主从+sentinel教程
  • 使用 Docker Compose 部署基于 Sentinel 的高可用 Redis 集群
  • Redis Sentinel 高可用实现说明 (要是早半个月看到这篇文章多好。自需求+正好遇到了文中提到的坑。PS:加一个坑:主从实例不能重命名config命令)
  • 怎样打造一个分布式数据库 | 数据库功能深度解析
  • 使用 RedisRaft 构建强一致的 Redis 集群

机制、源码

  • Redis压缩列表原理与应用分析
  • Random notes on improving the Redis LRU algorithm
  • Redis学习系列之八:Redis事务玩法:Redis事务介绍和源码分析
  • 源码分析redis的sentinel在master宕机时是如何选择新的master的
  • Redis主从同步失败案例的步步深入:redis主从同步的一个bug(已修复)
  • 深入浅出 Redis Cluster 原理,来自一次干货分享:Redis Cluster原理讲解
  • Redis和IO多路复用
  • Redis主从复制演变过程 (很好的讲解了Redis各版本中复制的演变)
  • Redis 缓存失效机制
  • Redis内部数据结构详解(5)——quicklist
  • Redis源码剖析 - Redis持久化之RDB
  • Redis源码学习——BIO
  • Redis短连接性能优化
  • Redis 多线程 IO 模型
  • Redis为什么用跳表而不用平衡树?
  • Redis短连接性能优化
  • 深入浅出 Redis client/server交互流程

版本特性

  • Redis 6.0 新特性概览
  • 客户端缓存功能
  • 带你100% 地了解 Redis 6.0 的客户端缓存
  • Redis 干货分享 | Redis 访问控制列表 (ACL)

Redis相关工具

  • 数据迁移工具-redisSheke
  • 数据对比工具-redisFullCheck
  • nredis-proxy 高性能Redis 服务中间件

https://toutiao.io/tags/Redis
https://github.com/huangz1990/redis-3.0-annotated

MySQL文章学习记录

发表于 2222-07-06 | 分类于 MyQL

这篇博文主用来记录读到的MySQL相关的文章

机制系列

  • MySQL 通讯协议:客户端与服务端连接过程中,密码怎样传输
  • 活久见,为什么SHOW TABLE STATUS总是不更新
  • 图解MySQL MySQL组提交(group commit)

故障及优化案例系列

  • 大规模多存储场景的数据库选型与服务平台建设
  • 引号错位引起的故障 (我才不会告诉你踩过的一个坑:update xx set a=’x’ and b=’x’ where …)
  • 一个事务中调整语句顺序 (MySQL45讲中也说过:一个事务中,只有需要锁的时候才会去申请锁,事务提交时才会释放锁。所以将锁资源较多的语句放在后面执行。)
  • 库表字符集修改后,老字段仍为原来字符集 (修改库表字符集后,只会改变新增的字符集)
  • 聊聊 隐式转换 (真实遇到过其中的字符串转换成浮点型比较,查询结果不准确的问题。实测当长度为17位时会有问题)
  • 一个特殊的隐式转换问题 (5.6版本IN中包括多个类型的话,会存在不能走索引的情况。相关阿里月报)
  • Strace 解决性能问题案例一则 (问题排查工具,用事实说话,DB不背锅)
  • 业务优化案例一则 (mysqlslap压测工具使用)
  • MySQL 案例一则 (explicit_defaults_for_timestamp参数解释)
    • explicit_defaults_for_timestamp
  • 再说 order by 优化 (很精髓的order by案例总结和优化建议。)
  • 一次大量删除导致 MySQL 慢查的分析 (由于MVCC特性,如果存在长时间未提交的事务,会导致简单查询也可能会变得很慢)
  • MySQL 大量sleeping before entering InnoDB 故障诊断 (很详细的一次问题排查步骤,里面有很多有用的命令)
  • 哪些因素会导致慢查询? (从应用到数据库,非常全面的列出了变慢的原因 加一个:limit 时匹配不到数据会一直扫描。)
  • 由MySQL复制延迟说起 (分析了复制延迟的主要原因和解决办法)
  • 为何COUNT很慢却不写SLOW LOG:slow log记录规则
  • 故障分析 | MySQL 优化案例 - select count(*)

SQL变慢的原因主要有:

  1. SQL执行过程走索引不合理,导致执行缓慢。
  2. 使用合理索引,但是获取数据量比较多。(排序,临时表等)
  3. 网络重传丢包导致SQL变慢。
  4. 并发比较高的场景,请求排队处理,等待时间长。

性能优化是一个老生常谈的问题,需要对相关流程和机制有很深入的研究才能对症下药。平时扩充、积累相关知识,在遇到问题后,才会有思路。经验很重要,但更多的是建立在平时的积累上。

死锁系列

  • 漫谈死锁 (1. RC级别下也会存在Next-key 2. RC级别下,获取到不符合记录时会释放锁)
    • innodb_print_all_deadlocks (将死锁信息记录到errorlog中参数)
    • innodb_status_output_locks (标准监控开关参数)
  • 如何阅读死锁日志 (锁组合)
  • MySQL 各种SQL语句加锁分析
    • innodb_locks_unsafe_for_binlog
  • 死锁案例一 (简单插入唯一索引插入意向锁案例)
  • 死锁案例二 (delete操作会有锁区间行为。PS:删除已有记录会导致锁范围变大)
  • 死锁案例三 (insert同一区间时,唯一索引的插入意向锁导致的死锁)
  • 死锁案例四 (并发插入时,插入意向锁不同阶段死锁。注意跟案例三的区别:本案例为X锁等待,案例三为S锁等待)
  • 死锁案例五 (repalce into插入死锁情况)
  • 死锁案例六 (不同事务加锁顺序不一样,导致锁资源交叉影响导致的死锁)
  • 死锁案例七 (RC级别下,update不存在记录会持有lock_S + GAP锁)
  • 死锁案例八 (多并发插入下的又一插入意向锁竞争导致的死锁案例)
  • 死锁案例九 (并发批量插入,导致的死锁)
  • 死锁案例十 (并发更新普通二级索引造成的死锁。PS:另一程度上说明索引不是随便加就行)
  • 死锁案例十一 (5.6升级到5.7后,INSERT INTO .. ON DUPLICATE KEY语句锁模式加强)
  • 死锁案例十二 (唯一索引,多插入,插入意向锁死锁情况)
  • 一个最不可思议的死锁分析 (并发delete语句造成的死锁情况,里面引用了很多好文章,需要细品)

分析死锁单从show engines innodb status中往往只能看到最后执行的语句,并不能很好的了解整个死锁形成过程。所以在分析死锁时,需要先了解两个死锁事务的具体逻辑和语句过程。
了解MySQL不同操作的加锁过程非常重要,这是对死锁形成过程分析的基础。

阅读全文 »

Redis 6.0新特性-客户端缓存

发表于 2020-07-29 | 分类于 Redis

你见过5点半的曼哈顿街头吗?一年前,当antirez在参加完纽约Redis大会后,5:30就在旅店中醒来了,面对曼哈顿街头的美丽景色,在芸芸众生中思索Redis的未来。包括客户端缓存。

简介

Redis实现的是一个服务端协助的客户端缓存,叫做tracking。用法是:
CLIENT TRACKING ON|OFF [REDIRECT client-id] [PREFIX prefix] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]
当tracking开启时,Redis客户端会“记住”每个请求过的key;当服务端key发生修改命令操作时,就会发送失效消息给客户端。失效消息可以通过RESP3协议发送给请求的客户端,或者转发给一个订阅频道__redis__:invalidate的连接。

  • REDIRECT:将失效消息转发给另外一个客户端。当我们使用的是老的RESP2和Redis通讯时,client本身不支持处理失效消息,所以可以开启一个Pub/Sub客户端处理失效消息。
  • BCAST:使用广播模式开始tracking,在这种模式下客户端需要设置将track的key前缀,这些key的失效消息会广播给所有参与的客户端,不管这些客户端是否请求/缓存了这些key。不开启广播模式的时候,Redis只会Track那些只读命令请求的key,并且只会报告一次失效消息。
  • PREFIX:只应用了广播模式,注册一个key的前缀。所有以这个前缀开始的key有修改时,都会发送失效消息。可以注册多个前缀,如果不设置前缀,那么广播模式会track每一个key。
  • OPTIN:当广播模式没有开启时,正常不会track只读命令的key,除非它们在CLIENT CACHING yes之后被调用。
  • OPTPUT:当广播模式没有开启时,正常会track只读命令的key,除非它们在CLIENT CACHING off之后被调用。
  • NOLOOP:不发送自身修改的key失效消息给自己。
阅读全文 »

Redis ACL从使用到实现

发表于 2020-07-20 | 分类于 Redis

简介

Redis ACL是6.0版本中推出的新功能。是一项可以限制用户连接可执行命令和键访问操作的功能。
客户端在连接服务器之后,客户端需要提供用户名和密码用于验证身份,如果验证成功,客户端连接会关联特定用户以及用户相应的权限。Redis可以配置新的客户端连接自动使用默认用户(default)进行验证(默认选项)。
此外,ACL功能对旧版客户端和应用都是向后兼容的,对于旧版配置用户密码的方式(requirepass)也是支持的。该命令设置的是default用户的密码,即auth password 等价于 auth default password。没有指定用户的客户端连接使用的都是default,可以通过控制defalut用户权限来兼容老版本。

ACL使用场景

  1. 你希望限制用户访问命令和键以提高安全性。不在信任列表中的用户没有权限访问,而在信任列表中的用户拥有完成工作的最小访问权限。例如一些客户端只可以执行只读的命令。
  2. 你希望提供运维安全。避免程序出错或者人为操作失误导致数据或者配置受到损坏。比如执行flush、keys等。在之前版本中都是通过命令重命令的方式来对使用者隐藏,但是这样可能会存在其他隐患。

ACL使用

ACL规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
on:启用用户
off:禁止用户
+:添加命令到用户允许执行命令列表
-:从用户允许执行命令列表删除命令
+@:允许用户执行定义在category类别中的命令
-@:删除用户拥有的category类别命令权限
+|subcommand:允许用户启用一个被禁止类别下的子命令。
allcommands:+@all 的别名.
nocommands:-@all 的别名。
~:添加一个键值模式的权限
allkeys:是 ~* 的别名
resetkeys:在键模式列表里面清空所有的键模式
>:添加密码到用户有效密码列表里
<:从用户有效密码列表中删除密码
#:添加 SHA-256 形式哈希值到用户有效密码列表里
!:从有效的密码列表中删除哈希值密码
nopass:删除所有与用户关联的密码
resetpass:清除用户所有密码
reset:用户将返回和它被默认创建时同样的状态。

ACL命令使用

1
2
3
4
5
6
7
8
9
10
11
12
/* ACL -- show and modify the configuration of ACL users.
* ACL HELP // 获取帮助信息
* ACL LOAD // 从外部ACL文件导入用户信息
* ACL LIST // 所有用户权限信息
* ACL USERS // 所有用户的列表
* ACL CAT [<category>] // 命令分类,及分类下的具体命令列表
* ACL SETUSER <username> ... acl rules ... // 添加用户、权限修改等操作
* ACL DELUSER <username> [...] // 删除用户
* ACL GETUSER <username> // 获取指定用户的信息
* ACL GENPASS // 生成一个密码
* ACL WHOAMI // 获取当前用户
*/
阅读全文 »

从Redis源码 acl.c->time_independent_strcmp() 实现谈到 定时攻击

发表于 2020-07-14 | 分类于 Redis

问题引出

在Redis阅读Redis源码的时候,发现acl.c中有个方法time_independent_strcmp。它的作用就是用来对比两个字符串是否相等,如果相等,那么就返回0,如果不相等,那么就返回非0值。
是不是很熟悉,没错!这跟C语言中的strcmp功能是一样的。那么为什么Redis的作者需要自己去实现一个呢?

我们来看一下这个函数的实现:

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
int time_independent_strcmp(char *a, char *b) {
char bufa[CONFIG_AUTHPASS_MAX_LEN], bufb[CONFIG_AUTHPASS_MAX_LEN];
/* The above two strlen perform len(a) + len(b) operations where either
* a or b are fixed (our password) length, and the difference is only
* relative to the length of the user provided string, so no information
* leak is possible in the following two lines of code. */
unsigned int alen = strlen(a);
unsigned int blen = strlen(b);
unsigned int j;
int diff = 0;

/* We can't compare strings longer than our static buffers.
* Note that this will never pass the first test in practical circumstances
* so there is no info leak. */
if (alen > sizeof(bufa) || blen > sizeof(bufb)) return 1;

memset(bufa,0,sizeof(bufa)); /* Constant time. */
memset(bufb,0,sizeof(bufb)); /* Constant time. */
/* Again the time of the following two copies is proportional to
* len(a) + len(b) so no info is leaked. */
memcpy(bufa,a,alen);
memcpy(bufb,b,blen);

/* Always compare all the chars in the two buffers without
* conditional expressions. */
for (j = 0; j < sizeof(bufa); j++) {
diff |= (bufa[j] ^ bufb[j]);
}
/* Length must be equal as well. */
diff |= alen ^ blen;
return diff; /* If zero strings are the same. */
}

可以看到,这个方法会先对比两个字符串的每一位,然后再判断两个字符串的长度是否相等。
看到这里,你是不是会想这样实现岂不是每次都会去对比所有字符,效率比strcmp还低!意义在哪呢?没错,我当时也是这么想的。于是去搜索了issue,于是有了意外的收获:https://github.com/redis/redis/issues/560。
Redis作者原来实现也的确使用的是strcmp,在这个issue中,有人提出了《定时攻击》这个安全问题,于是Redis作者就这个问题进行了修复,也就是time_independent_strcmp方法的由来。

定时攻击

简单来说,就是通过多次的密码攻击形式进行破解攻击,并根据目标服务返回的时间来确定当前字符是否正确。
在strcmp方法中,本质就是将两个字符串从头开始逐一比较,发现不同就立刻停止返回。假如输入的两个串开头有一部分相同,那么判断字符所耗费的时间就要变长一点。这好像就在告诉别人你输入的密码错误,但是前两个字符是正确的

解决这种攻击一般有几种方法:

  • 随机休眠时间
  • 估算执行时间,固定返回时间
  • 固定执行流程,返回时间不受具体字符影响。

在Redis这种高性能服务中,随机休眠以及将命令执行时间固定这两种方式会严重的影响执行效率。
所以Redis的作者通过在密码比较时,无论正确与否都正常执行下去,尽可能的返回相同时间,以避免这种攻击来破解密码。

https://github.com/redis/redis/issues/560
密码学中恒定时间设计(译文)

Redis2.8 Bug记录一则

发表于 2020-07-08 | 分类于 Redis

INCR命令递增字符串错误

1
2
3
4
5
6
7
8
9
过程:
127.0.0.1:6379> setrange string1 1 "Redis"
(integer) 6
127.0.0.1:6379> get string1
"\x00Redis"
127.0.0.1:6379> incr string1
(integer) 1
127.0.0.1:6379> get string1
"1"

经验证redis_version:4.0版本中,问题已经修复。
BUG修复PR:https://github.com/antirez/redis/commit/8b119999666f200685da61e4f0b1cfccc339f076

Xtrabackup 恢复失败记录一则

发表于 2020-06-29 | 分类于 MySQL

问题描述

最近基于MySQL自动恢复脚本做集群实例功能,发现在部分机器上触发时会存在扩展失败的情况。
具体表现为:

  1. 恢复失败机器为MySQL使用机器,此前是能够恢复成功。
  2. 通用备份机器仍然能够恢复成功。

通过查看恢复日志发现报以下错误:
/bin/sh: line 1: 362302 Segmentation fault (core dumped)

注:MySQL自动恢复脚本是本人开发的一套自动备份恢复体系中的恢复模块,主要是利用innobackupex工具+传入参数能够进行一键化进行MySQL实例恢复操作。能够只恢复指定库表数据、指定GTID位点等。

排查过程

根据报错描述,段异常。感觉是在MySQL实例恢复过程中,访问了非法地址,类似于内存溢出场景。

第一想法是innobackupex二进制文件损坏,于是通过对比不同机器上innobackupex工具的版本以及md5值,发现并没有区别。所以排除工具问题。

接着,怀疑是机器某些配置被修改导致的,于是询问组内伙伴和OPS团队。均得到未修改的回答。。。。此处陷入没有头绪的情况。

但是我还是肯定是机器层面的问题,于是就开始了瞎猫碰死耗子的试探之路。不断的对比成功机器和失败机器之间的系统参数区别。
在ulimit -a时发现存在多个配置不同,于是通过一个一个修改尝试,最终确定是以下参数导致的:
失败机器:stack size (kbytes, -s) 1024
成功机器:stack size (kbytes, -s) 8192

问题原因确定,于是拿着这个参数询问。得到老大的回答,为了使DB机器配置标椎化,最近对MySQL机器的此参数进行了批量修改的操作。(此前Mongo机器都是1024)

结论

这个参数有什么用?为什么会导致MySQL恢复失败呢?

百度对stack size的表述是:进程的栈的最大值
在程序运行时,如果程序比较大,那么就会遇到“段错误”(segmentation fault),主要就是收到了这个参数的限制。

PS:为什么不将这个值设置成默认值,而是调小呢?我老大说DB都是属于并发多的服务,这个值如果设置的太大的话,会导致存在大量无用内存的损耗。虽然没搞懂,我还是认为不应该修改这个值,当前太菜了,后面有机会再深入研究吧。

MySQL机制之排序算法

发表于 2020-06-27 | 分类于 MySQL

在很多场景中,我们都要求从数据库中查询出来的数据是有序的,SQL语法为order by。如果在查询使用到了排序,那么在EXPLAIN中,Extra 这个字段中会存在Using filesort。

1
2
3
4
5
6
mysql> explain select city,name,age from t where city='杭州' order by name limit 1000  ;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+----------------+
| 1 | SIMPLE | t | NULL | ref | city | city | 66 | const | 1 | 100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+----------------+

那么它在MySQL中是怎么实现的?什么参数会影响它呢?

全字段排序

通常情况下,语句执行流程如下:

  1. 初始化sort_buffer,确认需要放入的字段。(city,name,age)
  2. 从索引中查询满足条件的数据。
  3. 如果需要进行回表查询,那么会根据ID到聚簇索引中去查询到所需的字段。并将字段数据放入到sort_buffer中。
  4. 继续查询下一条记录,重复以上动作。直到将所有满足条件的数据都查询出来。
  5. 对sort_buffer中的数据按照排序字段进行排序。
  6. 将排序结果的前1000行返回给客户端。

按照name排序的这个过程,可能在内存中完成,也可能需要使用外部排序。这取决于排序所需要的内存和参数sort_buffer_size

sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。

阅读全文 »

MySQL之MGR初涉

发表于 2020-06-27 | 分类于 MySQL

简介

MySQL Group Replication(简称MGR)是MySQL官方于2016年12月推出的一个全新的高可用与高扩展的解决方案。MGR是MySQL官方在5.7.17版本引进的一个数据库高可用与高扩展的解决方案,以插件形式提供,实现了分布式下数据的最终一致性, 它是MySQL5.7版本出现的新特性,它提供了高可用、高扩展、高可靠的MySQL集群服务。组复制在数据库层面做到了高可用,只要集群中大多数主机可用,则服务可用。

特点

  • 高一致性:基于分布式paxos协议实现组复制,保证数据一致性。
  • 高容错性:自动检测机制,内置防脑裂保护机。
  • 高扩展性:节点增加移除自动更新组成员信息。新节点加入后,自动从其他节点同步增量数据。
  • 高灵活性:提供单主和多主模式,单主宕机自动选主。

限制

  • 存储引擎必须是InnoDB,即只支持InnoDB表
  • 每张表都必须要有一个主键,用于做weite set的冲突检测
  • 只支持ipv4,网络需求较高
  • 必须开启GTID
  • binlog格式必须设置为ROW
  • 一个MGR集群最多支持9个节点
  • 不支持外键于save point特性,无法做全局间的约束检测与部分部分回滚
  • 二进制日志binlog不支持Replication event checksums
  • 多主模式(也就是多写模式) 不支持SERIALIZABLE事务隔离级别
  • 多主模式不能完全支持级联外键约束
  • 多主模式不支持在不同节点上对同一个数据库对象并发执行DDL(在不同节点上对同一行并发进行RW事务,后发起的事务会失败)

搭建过程可参考Docker 环境下搭建MySQL 8.0.20 组复制

阅读全文 »

Go学习之Module介绍

发表于 2020-06-26 | 分类于 GO

最古老的GOPATH

Go的包管理方式是逐渐演进的,最初所有的包都放在GOPATH中,使用类似命名空间的包路径来区分包。
你可以将其理解为工作目录,在这个工作目录下,通常有如下的目录结构:

  • bin:存放编译生成的二进制文件
  • pkg:存放编译后的.a文件
  • src:存放项目的源代码,可以是自己写的代码。也可以是go get下载的包

在这种模式下,最严重的问题就是版本管理问题,因为GOPATH没有版本的概念,所以可能会遇到以下的问题:

  • 无法在项目中使用指定版本的包,因为不同版本的包的导入方法是一样的。
  • 其他人运行你开发的程序时,无法保证他下载的包版本是你所期望的版本。当其他人
  • 本地中,一个包只能保留一个版本,意味着你在本地开发的所有项目都是一个版本的包
阅读全文 »
12…14
OMG_By

OMG_By

133 日志
20 分类
36 标签
RSS
GitHub E-Mail
友链
  • 戎码人生
  • JosemyQAQ
  • Just do it !
  • ACM各大OJ题集
  • django大神博客
© 2020 OMG_By