Redis常用

基础入门教程

中文官方文档

数据结构常见的应用方式

Redis Strings 字符串

值最大不能超过 512MB

字符串类型对应常用命令

业务不经常变更的数据,接口响应的json字符串等

图片的base64的值

数值秒杀数量之类的,INCR , INCRBYDECR , DECRBY 命令(内部就是同一个命令,只是看上去有点儿不同)会将字符串解析成整数进行原子操作。原子操作意味着多个客户端对同一个key发出INCR命令,也决不会导致竞争的情况。

统计数据,每小时更新访客信息计数器,GETSET可以和INCR一起使用实现支持重置的计数功能

redis> INCR mycounter //访问
(integer) 1
redis> GETSET mycounter "0" //获取并重置计数
"1"
redis> GET mycounter //获取重置后的数据
"0"
redis> 

为减少等待时间,也可以一次存储或获取多个key对应的值,使用MSETMGET命令

> mset a 10 b 20 c 30
OK
> mget a b c //返回由值组成的数组
1) "10"
2) "20"
3) "30"

Redis Hash 哈希

hash (散列) 指令的完整列表

特别适合用于存储对象,Redis 中每个 hash (散列) 可以存储 232 – 1 键值对(40多亿)

系统参数常量配置功能

Redis Lists 列表

list常用命令

简单的消息队列

lpoprpush(或者反过来,lpushrpop)能实现队列的功能,BLPOP,BRPUSH阻塞式实现消息队列。

朋友圈的点赞列表、评论列表、排行榜:lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表。

限速器,可用于限制某个用户访问某个接口的频率,比如秒杀场景用于防止用户快速点击带来不必要的压力

好友关系,利用集合的一些命令,比如交集、并集、差集等,实现共同好友、共同爱好之类的功能

Redis Set 集合

 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

Redis Sorted Set 有序集合

 string 类型元素的集合,且不允许重复的成员,每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

发布/订阅

Redis 发布订阅简单教程

Pub/Sub发布订阅中文文档

redis实现消息队列(轻量级)的方案

消息队列的考验:Redis有哪些解决方案?

消息队列特征 基于List 基于streams 基于发布订阅
消息保序适用LPUSH/RPOP使用ADD/XREAD
阻塞读取适用BRPOP使用XREAD block
重复消息处理生产者自行实现全局唯一IDStreams自动生成全局唯一ID
消息可靠性适用BRPOP LPUSH使用PENDING List自动留存消息,使用XPENDING查看,使用XACK确认消息
适用场景Redis5.0之前版本的部署环境消息总量少Redis5.0及以后的版本的部署环境消息总量大,需要消费组形式读取数据

缓存使用常见问题

如何保证双写一致性

Cache Aside Pattern 模式

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。

更新的时候,先更新数据库,然后再删除缓存。删除缓存而不更新缓存的原因:有些需要进行复杂计算或查询的缓存场景,更新的操作成本太高。

不一致场景及解决方案

先删除缓存再更新数据库

进行更新操作时,先删除缓存,然后更新数据库,后续的请求再次读取时,会从数据库读取后再将新数据更新到缓存

先更新数据库再删除缓存

进行更新操作时,先更新 MySQL,成功之后,删除缓存,后续读取请求时再将新数据回写缓存。

存在的问题:更新 MySQL 和删除缓存这段时间内,请求读取的还是缓存的旧数据,不过等数据库更新完成,就会恢复一致,影响相对比较小。

异步更新缓存

数据库的更新操作完成后不直接操作缓存,而是把这个操作命令封装成消息扔到消息队列中,然后由 Redis 自己去消费更新数据,消息队列可以保证数据操作顺序一致性,确保缓存系统的数据正常。

Redis 缓存击穿、穿透、雪崩

相关文章和面试问题

Redis必知必会20问

如何保证缓存(redis)与数据库的双写一致性

缓存一致性,缓存穿透,缓存击穿,缓存雪崩解决方案分析

PHP+Redis 有序集合实现 24 小时排行榜实时更新

redis的五种数据结构和应用场景【如微博微信点赞/共同关注/加购物车】

真实项目中应用案例记录

mysql skip-name-resolve

错误描述

[Warning] IP address ‘192.168.0.110’ could not be resolved: Name or service not known

解决方案

配置文件添加

skip-name-resolve

原因描述

mysql接收到连接请求后,获得的是客户端的ip,为了更好的匹配mysql.user里的权限记录(某些是用hostname定义的)。
如果mysql服务器设置了dns服务器,并且客户端ip在dns上并没有相应的hostname,那么这个过程很慢,导致连接等待。

添加skip-name-resolve以后就跳过着一个过程了。

相关文章

mysql skip-name-resolve 的解释

mySQL 错误日志分析

MySQL网络原因导致的连接失败

Elasticsearch 安装备忘

下载地址

下载ES 下载kibana logstash cerebo analysis-ik中文分词插件 用户案例

所有软件及插件版本必须一致

安装ES

install-elasticsearch

启动方式systemed

service elasticsearch start

查看版本

sudo /usr/share/elasticsearch/bin/elasticsearch --version
Version: 7.17.1, Build: default/deb/e5acb99f822233d62d6444ce45a4543dc1c8059a/2022-02-23T22:20:54.153567231Z, JVM: 17.0.2

开发机器修改内存配置

官方文档 ES6/7修改内存大小

Elasticsearch参数调优

//配置文件目录,如果没有权限请使用高权限账号修改
/etc/elasticsearch/jvm.options

//内存配置项,开发机建议设置为1~2g节省内存,生产环境不能超过32g
-Xms1g
-Xmx1g

安装插件analysis-ik为例

插件默认目录:/usr/share/elasticsearch/plugins 新建目录ik

下载插件,移动所有文件到ik目录下,重启elasticsearch

sudo cd /usr/share/elasticsearch/plugins
sudo unzip -o elasticsearch-analysis-ik-x.x.x.zip -d ik
sudo rm -rf elasticsearch-analysis-ik-x.x.x.zip

访问地址和默认端口 http://127.0.0.1:9200/

{
  "name" : "MINIPC-PN51-E1",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "e9ml_7fiTemo3tW5ug5_Jg",
  "version" : {
    "number" : "7.17.0",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "bee86328705acaa9a6daede7140defd4d9ec56bd",
    "build_date" : "2022-01-28T08:36:04.875279988Z",
    "build_snapshot" : false,
    "lucene_version" : "8.11.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

配置用户名,密码

安装kibana

kibanna下载地址

service kibana start

访问地址和默认端口 http://localhost:5601/

汉化配置

//配置文件目录
/etc/kibana/kibana.yml
//i18n 设置为中文
i18n.locale: "zh-CN"

安装logstash

下载logstash 需要安装jdk

安装cerebro

下载地址 需要安装jdk

启动失败解决方法

#修改systemd配置 /usr/lib/systemd/system/cerebro.service
ExecStart=/usr/share/cerebro/bin/cerebro -java-home /usr/java/jdk-11.0.12 -Dhttp.port=9000 -Dhttp.address=127.0.0.1
service cerebro start

访问地址和默认端口 http://localhost:9000/

FAQ: mysqld_safe mysqld from pid file xxx.pid ended

处理一个兼职人员部署的服务器故障

1.php故障

Warning: require_once(ROOTPATHconfig/bluebee.inc.php): failed to open stream: No such file or directory in /web/code/mygym/mygym_pc/include/head.php on line 23

Fatal error: require_once(): Failed opening required 'ROOTPATHconfig/bluebee.inc.php' (include_path='.:/usr/local/php54/lib/php') in /web/code/mygym/mygym_pc/include/head.php on line 23

boss反馈,一个兼职人员开发部署的项目,出现了这个问题,根据经验初步判断,是文件不存在了,或者目录没有权限,登录之后发现,这个phper根本没有linux基础,以及不懂php-fpm运行机制,文件用户和组是 nginx 然后给了777权限

解决方法

service php-fpm status 显示 php-fpm 是www 用户跑的,但是当前服务器没有该用户

执行如下命令,创建www用户并加入www用户组

命令参考

groupadd www
useradd -g www -M -s /sbin/nologin www

更改代码目录权限

//更改用户组
chown -R www.www /web/code
//更改目录权限
chmod -R 755 /web/code
文件权限根据情况可以给644

2.php报错提示mysql连接失败

service mysqld status 显示启动失败,查看/var/log/mysqld.log 日志 报错如下

mysqld_safe mysqld from pid file /var/lib/mysql/mysqld.pid ended

/etc/my.cnf配置如下

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

[mysqld]
skip-grant-tables
#
# 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

# Recommended in standard MySQL setup
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

发现是使用rpm包使用的社区版安装的。

尝试了各种发,都没有用,最后参考如下问答解决

https://stackoverflow.com/questions/33984848/mysqld-safe-mysqld-from-pid-file-var-run-mysqld-mysqld-pid-prevent-from-server

restorecon -r /var/lib/mysql
service mysqld start

原因分析

可能是 /var/lib/mysql 目录,用户组 不是 mysql,

移动复制或修改文件时导致了 SELinux文件属性 丢失

首先保证 mysql 数据目录/var/lib/mysql 用户组 必须是 mysql

然后使用 restorecon 恢复文件的安全上下文

restorecon指令参考

数据库设计相关文章索引

Mysql FAQ

隐式类型转换

例如 pid 字段类型是 int,我们 where pid = “1”,这样就会触发隐式类型转换。字段为数字类型,字符串数字转换成数字时,并不会导致索引失效如下图

当where查询操作符**左边为字符类型**时发生了隐式转换,那么会导致索引失效,造成全表扫描效率极低。

name为字符串类型,传入了数字类型001 转换后索引失效

导致查询结果不符合预期

类型隐式转换规则

当操作符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容,某些转换是隐式发生的

如果不与数字比较,则将十六进制值视为二进制字符串


如果参数之一是a TIMESTAMP或 DATETIME column,而另一个参数是常量,则在执行比较之前,该常量将转换为时间戳。这样做是为了使ODBC更友好。对于的参数,此操作未完成 IN()。为了安全起见,在进行比较时请始终使用完整的日期时间,日期或时间字符串。例如,要在BETWEEN与日期或时间值一起使用时获得最佳结果 ,请使用CAST()将值显式转换为所需的数据类型。


一个或多个表中的单行子查询不被视为常量。例如,如果子查询返回要与DATETIME 值进行比较的整数,则比较将作为两个整数进行。整数不转换为时间值。要将操作数作为DATETIME值进行比较 ,请使用 CAST()将子查询值显式转换为DATETIME


如果参数之一是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较;如果另一个参数是浮点值,则将参数作为浮点值进行比较。


在所有其他情况下,将参数作为浮点数(实数)进行比较。例如,将字符串和数字操作数进行比较,将其作为浮点数的比较。

条件的由字符转为浮点时候

不以数字开头的字符串都将转换为0。如’abc’、’a123bc’、’abc123’都会转化为0;
以数字开头的字符串转换时会进行截取,从第一个字符截取到第一个非数字内容为止。比如’123abc’会转换为123,’012abc’会转换为012也就是12,’5.3a66b78c’会转换为5.3,其他同理。

避免规则,通过程序处理,尽量使类型与数据库字段保持一致

参考

mysql-8.隐式转换导致索引失效或查出不符合where条件结果

类型转换官方文档