• Redis for OPS 01:关于 Redis 基础说明与安装部署


    写在前面的话

    本章节开始在主要介绍在运维工作中绕不开的一个话题,数据缓存 NoSQL 服务 Redis,搭建很简单,使用很简单,运行也稳定的一批,一般小公司几乎很少出现以为量的问题导致他 down 掉的情况,但如果我们想走上更高的台阶,只是简单的安装运行肯定是不够的。所以我会写这几篇博客,算是做一个简单的小结,其内容涉及:主从,哨兵(高可用),集群(分布式)。

    Redis 简介

    在之前专门学习了 MySQL,我们把它称为关系型数据库,现在开始谈谈非关系型数据库(NoSQL,Key - Value 键值对),其主要产品包含 Redis,MongoDB,Memcached,Tair 等。

    可以看看 Redis 的 logo:

    Redis 的简单优点有以下这些:

    1. 支持的数据类型丰富,包括 String / hash / List / Set / SortSet 等。

    2. 支持持久化。

    3. 多种内存分配和回收策略。

    4. 支持消息对了,订阅发布。

    5. 支持高可用 / 分布式集群等等。

    目前在企业缓存产品中主要有两个:Memcached 和 Redis,所以我们常常把这两个东西拿来做对比。

    Memcached

    优点:高性能读写,单一数据类型,支持客户端分布式集群,一致性 Hash,多核结构,多线程读写性能高。

    缺点:没持久化,节点故障可能出现缓存穿透,分布式需要客户端配置,跨主机同步数据困难,架构扩展复杂。

    Redis

    优点:高性能读写,多数据类型支持,数据持久化,高可用架构,支持自定义虚拟内存,支持分布式集群分片。

    缺点:多线程读写不如 Memcached。

    Tair(淘宝):

    优点:高性能读写,支持三种存储引擎,支持高可用,分布式分片集群。

    缺点:单机情况下性能不及前两个。

    使用场景比较:

    Memcached:多核的缓存服务,更适用于多用户并发访问次数较少的应用场景。

    Redis:单核的缓存服务,单节点时适合于少量用户,多次访问的场景。

    截至文章更新日期,Redis 已经更新到了 5.0.5 版本,但是目前主流的还是 3 版本,新的项目可能会用到 4 版本。

    说明:为了文章的时效性,所以本文选择从 Redis 4 版本开始,而不再是 3 版本,4 版本相对于用户而言变化其实不大,但是在其内部的性能以及各种机制方面还是有很大的提升。所以选择更好的。

    Redis 的下载地址如下:

    https://redis.io/download

    但是国内由于墙的原因,所以下载速度大家懂的,好在 redis 也就 1.6 M 左右(真niubi),也可以去其它下载源试一试。

    安装部署 Redis

    安装前准备:

    # 创建目录,并将安装包上传到 /data/packages
    mkdir -p /data/{backup,data,logs,packages,services}

    安装过程超级简单,解压,编译:

    # 解压编译安装
    yum -y install gcc automake autoconf libtool make
    tar -zxf redis-4.0.14.tar.gz
    cd redis-4.0.14/
    make
    make PREFIX=/data/services/redis install
    
    # 创建数据目录
    cd /data/services/redis
    mkdir data logs conf

    添加配置文件,在源码包解压目录中有模板,redis.conf,但是不适合我们,所以需要修改一下:

    #################################################################################################
    # Redis 配置文件
    #################################################################################################
    bind 127.0.0.1 192.168.200.101
    protected-mode yes
    port 6379
    tcp-backlog 2048
    timeout 0
    tcp-keepalive 300
    daemonize yes
    supervised no
    pidfile /data/services/redis/logs/redis-6379.pid
    loglevel notice
    logfile "/data/services/redis/logs/redis-6379.log"
    databases 16
    always-show-logo yes

    该配置为最基础的配置,后续我们会渐渐的完善它!

    启动查看 Redis:

    # 启动
    /data/services/redis/bin/redis-server /data/services/redis/conf/redis.conf
    
    # 查看
    netstat -tlunp | grep 6379

    结果如图:

    登录测试:

    # 登录
    /data/services/redis/bin/redis-cli

    结果如图:

    redis-cli 主要常用参数:

    -h:指定主机

    -p:指定端口

    -s:指定 socket

    -a:指定密码

    -n:指定 db

    全局基础操作

    基础操作如下:

    # 查看所有
    keys *
    
    # 查看指定
    keys name
    
    # 查看匹配的
    keys n*
    
    # 查看类型
    type name
    
    # 以秒为单位设置生存时间,毫秒则用 pexpire
    expire name 30
    
    # 查看剩余生存时间,单位秒,毫秒则使用 pttl
    ttl name
    
    # 取消生存时间
    persist name
    
    # 删除key
    del name
    
    # 检查key是否存在
    exists name
    
    # 重命名key
    rename name user

    结果如下:

    127.0.0.1:6379> keys *
    1) "name"
    127.0.0.1:6379> type name
    string
    127.0.0.1:6379> keys n*
    1) "name"
    127.0.0.1:6379> type name
    string
    127.0.0.1:6379> expire name 30
    (integer) 1
    127.0.0.1:6379> ttl name
    (integer) 26
    127.0.0.1:6379> pttl name
    (integer) 13051
    127.0.0.1:6379> keys name
    (empty list or set)
    127.0.0.1:6379> set name zhangsan
    OK
    127.0.0.1:6379> keys name
    1) "name"
    127.0.0.1:6379> get name
    "zhangsan"
    127.0.0.1:6379> expire name 60
    (integer) 1
    127.0.0.1:6379> ttl name
    (integer) 57
    127.0.0.1:6379> persist name
    (integer) 1127.0.0.1:6379> ttl name
    (integer) -1
    127.0.0.1:6379> get name
    "zhangsan"
    127.0.0.1:6379> del name
    (integer) 1
    127.0.0.1:6379> keys name
    (empty list or set)
    127.0.0.1:6379> exists name
    (integer) 0
    127.0.0.1:6379> set name zhangsan
    OK
    127.0.0.1:6379> rename name user
    OK
    127.0.0.1:6379> keys *
    1) "user"

    另外,切换数据库可以使用 select + 库

    数据类型

    Redis 包含以下五种数据类型:

    类型说明KEYVALUE
    String 字符串,基础类型 name zhangsan
    Hash 哈希,类似MySQL的表 students id:1 name:zhangsan age:18
    List 列表,简单的字符串列表 code [...5,4,3,2,1]
    Set String类型的无序集合,不能重复 names (zhangsan,lisi,...)
    SortSet 有序集合,不能重复 music (mc1,mc2,mc3...)

    String 类型的操作,常见的应用场景:session 保存,常规计数,如粉丝数,观看人数等。

    # 设置一个key
    set name zhangsan
    
    # 获取一个key的value
    get name
    
    # 获取key的value指定区间
    getrange name 1 3
    
    # 给key设置新的value并返回旧的value
    getset name lisi
    
    # 获取一个或多个key
    mget name user
    
    # 设置value的时候顺便设置生存时间
    setex a 10 haha
    
    # 当key不存在的时候则设置,否则不改变
    setnx a haha
    
    # 设置多个key
    mset a haha b xixi c hehe
    
    # 设置多个key,但是要求所有key都不存在才生效
    msetnx c aaa d ttt e hhh
    
    # 显示value的长度
    strlen a
    
    # 自加1
    incr num
    
    # 自加指定值
    incrby num 1000
    
    # 自加浮点数
    incrbyfloat num 100.23
    
    # 自减1
    decr num
    
    # 自减指定value
    decrby num 100
    
    # 当key存在并且为字符串,则将新的字符串拼接到后面
    append name superman

    结果如下:

    127.0.0.1:6379> set name zhangsan
    OK127.0.0.1:6379> get name
    "zhangsan"
    127.0.0.1:6379> GETRANGE name 1 3
    "han"
    127.0.0.1:6379> GETSET name lisi
    "zhangsan"
    127.0.0.1:6379> get name
    "lisi"
    127.0.0.1:6379> set user dylan
    OK
    127.0.0.1:6379> MGET name user
    1) "lisi"
    2) "dylan"
    127.0.0.1:6379> SETEX a 10 haha
    OK
    127.0.0.1:6379> ttl a
    (integer) 6
    127.0.0.1:6379> SETNX a xixi
    (integer) 1
    127.0.0.1:6379> get a
    "xixi"
    127.0.0.1:6379> SETNX a haha
    (integer) 0
    127.0.0.1:6379> get a
    "xixi"
    127.0.0.1:6379> MSET a haha b xixi c hehe
    OK
    127.0.0.1:6379> keys *
    1) "c"
    2) "num"
    3) "name"
    4) "b"
    5) "user"
    6) "a"
    127.0.0.1:6379> MSETNX c aaa d ttt e hhh
    (integer) 0
    127.0.0.1:6379> keys *
    1) "c"
    2) "num"
    3) "name"
    4) "b"
    5) "user"
    6) "a"
    127.0.0.1:6379> MSETNX d ttt e hhh f eee
    (integer) 1
    127.0.0.1:6379> keys *
    1) "c"
    2) "e"
    3) "num"
    4) "d"
    5) "f"
    6) "user"
    7) "name"
    8) "a"
    9) "b"
    127.0.0.1:6379> STRLEN a
    (integer) 4
    127.0.0.1:6379> STRLEN f
    (integer) 3
    127.0.0.1:6379> set num 100
    OK
    127.0.0.1:6379> INCR num
    (integer) 101
    127.0.0.1:6379> INCR num
    (integer) 102
    127.0.0.1:6379> INCR num
    (integer) 103
    127.0.0.1:6379> INCRBY num 1000
    (integer) 1103
    127.0.0.1:6379> INCRBYFLOAT num 100.23
    "1203.22999999999999998"
    127.0.0.1:6379> set num 1
    OK
    127.0.0.1:6379> DECR num
    (integer) 0
    127.0.0.1:6379> DECR num
    (integer) -1
    127.0.0.1:6379> DECR num
    (integer) -2127.0.0.1:6379> DECRBY num 100
    (integer) -102
    127.0.0.1:6379> get name
    "lisi"
    127.0.0.1:6379> APPEND name superman
    (integer) 12
    127.0.0.1:6379> get name
    "lisisuperman"

    Hash 类型操作,常用于数据库缓存:

    # 创建hash键值对
    hmset stu_1 name zhangsan age 18 gender m
    
    # 查看key中指定字段,可以多个
    hmget stu_1 name age
    
    # 判断key中是否操作指定字段
    hexists stu_1 name
    
    # 获取key中所有value
    hgetall stu_1
    
    # 获取key中所有字段
    hkeys stu_1
    
    # 获取key中所有字段的值
    hvals stu_1
    
    # 统计key中字段个数
    hlen stu_1
    
    # 给key增加字段
    hmset stu_1 id 100
    
    # 给key中某个字段自增指定值
    hincrby stu_1 id 100
    
    # 修改key中字段,如果不存在就添加,存在不变
    hsetnx stu_1 name lisi
    
    # 删除指定字段
    hdel stu_1 id

    结果如下:

    127.0.0.1:6379[1]> HMSET stu_1 name zhangsan age 18 gender m
    OK
    127.0.0.1:6379[1]> HMGET stu_1 name
    1) "zhangsan"
    127.0.0.1:6379[1]> HMGET stu_1 name age
    1) "zhangsan"
    2) "18"
    127.0.0.1:6379[1]> HLEN stu_1
    (integer) 3
    127.0.0.1:6379[1]> HEXISTS stu_1 name
    (integer) 1
    127.0.0.1:6379[1]> HEXISTS stu_1 a
    (integer) 0
    127.0.0.1:6379[1]> HGETALL stu_1
    1) "name"
    2) "zhangsan"
    3) "age"
    4) "18"
    5) "gender"
    6) "m"
    127.0.0.1:6379[1]> HMSET stu_1 id 100
    OK
    127.0.0.1:6379[1]> HGETALL stu_1
    1) "name"
    2) "zhangsan"
    3) "age"
    4) "18"
    5) "gender"
    6) "m"
    7) "id"
    8) "100"
    127.0.0.1:6379[1]> HINCRBY stu_1 id 100
    (integer) 200
    127.0.0.1:6379[1]> HGET stu_1 id
    "200"
    127.0.0.1:6379[1]> HKEYS stu_1
    1) "name"
    2) "age"
    3) "gender"
    4) "id"
    127.0.0.1:6379[1]> HVALS stu_1
    1) "zhangsan"
    2) "18"
    3) "m"
    4) "200"
    127.0.0.1:6379[1]> HSETNX stu_1 name lisi
    (integer) 0
    127.0.0.1:6379[1]> HGET stu_1 name
    "zhangsan"
    127.0.0.1:6379[1]> HDEL stu_1 id
    (integer) 1
    127.0.0.1:6379[1]> HKEYS stu_1
    1) "name"
    2) "age"
    3) "gender"

    List 类型操作,如朋友圈更新这样的需求,后来居上:

    # 创建key并插入数据,左边插入
    lpush wechat "This is 1"
    
    # 可以插入多个
    lpush wechat hello world
    
    # 查看个数
    llen wechat
    
    # 查看全部,指定角标
    lrange wechat 0 -1
    
    # 左边插入,如果key不存在就不插入
    lpushx wechat_2 haha
    
    # 在哪个之前插入
    linsert wechat before hello yes
    
    # 在哪个之后插入
    linsert wechat after hello no
    
    # 从右边插入
    rpush wechat xixi
    
    # 将key1中的最右边的值弹出并插入key2中
    rpoplpush wechat wechat_2
    
    # 弹出key中第一个
    lpop wechat
    
    # 显示指定角标
    lindex wechat 1
    
    # 从左边开始删除指定个数的指定值
    lrem wechat 2 hello
    
    # 只保留指定角标范围,其它全删除
    ltrim wechat 0 1
    
    # 修改角标的值
    lset wechat 1 nooo
    
    # 删除key
    del wechat

    结果如下:

    127.0.0.1:6379[2]> LPUSH wechat "This is 1"
    (integer) 1
    127.0.0.1:6379[2]> LPUSH wechat "This is 2"
    (integer) 2
    127.0.0.1:6379[2]> LPUSH wechat "This is 3"
    (integer) 3
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "This is 3"
    2) "This is 2"
    3) "This is 1"
    127.0.0.1:6379[2]> LPUSH wechat hello world
    (integer) 5
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "world"
    2) "hello"
    3) "This is 3"
    4) "This is 2"
    5) "This is 1"
    127.0.0.1:6379[2]> LRANGE wechat 0 1
    1) "world"
    2) "hello"
    127.0.0.1:6379[2]> LPUSHX wechat_2 haha
    (integer) 0
    127.0.0.1:6379[2]> LPUSHX wechat haha
    (integer) 6
    127.0.0.1:6379[2]> LRANGE wechat 0 1
    1) "haha"
    2) "world"
    127.0.0.1:6379[2]> LINSERT wechat before hello yes
    (integer) 7
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "haha"
    2) "world"
    3) "yes"
    4) "hello"
    5) "This is 3"
    6) "This is 2"
    7) "This is 1"
    127.0.0.1:6379[2]> LINSERT wechat after hello no
    (integer) 8
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "haha"
    2) "world"
    3) "yes"
    4) "hello"
    5) "no"
    6) "This is 3"
    7) "This is 2"
    8) "This is 1"
    127.0.0.1:6379[2]> RPUSH wechat xixi
    (integer) 9
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "haha"
    2) "world"
    3) "yes"
    4) "hello"
    5) "no"
    6) "This is 3"
    7) "This is 2"
    8) "This is 1"
    9) "xixi"
    127.0.0.1:6379[2]> RPOPLPUSH wechat wechat_2
    "xixi"
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "haha"
    2) "world"
    3) "yes"
    4) "hello"
    5) "no"
    6) "This is 3"
    7) "This is 2"
    8) "This is 1"
    127.0.0.1:6379[2]> LRANGE wechat_2 0 -1
    1) "xixi"
    127.0.0.1:6379[2]> LPOP wechat
    "haha"
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "world"
    2) "yes"
    3) "hello"
    4) "no"
    5) "This is 3"
    6) "This is 2"
    7) "This is 1"
    127.0.0.1:6379[2]> LPOP wechat
    "world"
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "yes"
    2) "hello"
    3) "no"
    4) "This is 3"
    5) "This is 2"
    6) "This is 1"
    127.0.0.1:6379[2]> LINDEX wechat 1
    "hello"127.0.0.1:6379[2]> LREM wechat 2 hello
    (integer) 1
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "yes"
    2) "no"
    3) "This is 3"
    4) "This is 2"
    5) "This is 1"
    127.0.0.1:6379[2]> LTRIM wechat 0 1
    OK
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "yes"
    2) "no"
    127.0.0.1:6379[2]> LSET wechat 1 nooo
    OK
    127.0.0.1:6379[2]> LRANGE wechat 0 -1
    1) "yes"
    2) "nooo"
    127.0.0.1:6379[2]> del wechat
    (integer) 1

    Set 类型操作,类似于QQ好友推荐你可能认识的人,共同好友问题:

    # 创建 set和追加
    SADD s1 a b c d e f g
    
    # 取并集
    SUNION s1 s2
    
    # 将并集存到新的set unionkey中
    SUNIONSTORE unionkey s1 s2
    
    # 取交集
    SINTER s1 s2
    
    # 将交集存到新的set interkey中
    SINTERSTORE interkey s1 s2
    
    # 取前面和后面的差集
    SDIFF s1 s2
    
    # 将差集存到新的set diffkey中
    SDIFFSTORE diffkey s1 s2
    
    # 查看数量
    SCARD s1
    
    # 查看所有值
    SMEMBERS s1
    
    # 随机删除一个
    SPOP s1
    
    # 将1中元素移动到2中
    SMOVE s1 s2 x
    
    # 删除指定元素
    SREM s1 a b g

    结果如下:

    127.0.0.1:6379[3]> SADD s1 a b c d e f g
    (integer) 7
    127.0.0.1:6379[3]> SADD s2 e f g h i j k
    (integer) 7
    127.0.0.1:6379[3]> SUNION s1 s2
     1) "f"
     2) "b"
     3) "a"
     4) "e"
     5) "c"
     6) "i"
     7) "d"
     8) "j"
     9) "h"
    10) "g"
    11) "k"
    127.0.0.1:6379[3]> SINTER s1 s2
    1) "e"
    2) "g"
    3) "f"
    127.0.0.1:6379[3]> SDIFF s1 s2
    1) "c"
    2) "b"
    3) "a"
    4) "d"
    127.0.0.1:6379[3]> SDIFF s2 s1
    1) "i"
    2) "j"
    3) "h"
    4) "k"
    127.0.0.1:6379[3]> SADD s1 x y z
    (integer) 3
    127.0.0.1:6379[3]> SCARD s1
    (integer) 10
    127.0.0.1:6379[3]> SMEMBERS s1
     1) "x"
     2) "g"
     3) "d"
     4) "f"
     5) "a"
     6) "b"
     7) "e"
     8) "c"
     9) "z"
    10) "y"
    127.0.0.1:6379[3]> SUNIONSTORE unionkey s1 s2
    (integer) 14
    127.0.0.1:6379[3]> SINTERSTORE interkey s1 s2
    (integer) 3
    127.0.0.1:6379[3]> SDIFFSTORE diffkey s1 s2
    (integer) 7
    127.0.0.1:6379[3]> SMOVE s1 s2 x
    (integer) 1
    127.0.0.1:6379[3]> SMEMBERS s2
    1) "e"
    2) "i"
    3) "h"
    4) "j"
    5) "x"
    6) "g"
    7) "f"
    8) "k"
    127.0.0.1:6379[3]> SPOP s1
    "z"
    127.0.0.1:6379[3]> SPOP s1
    "g"
    127.0.0.1:6379[3]> SMEMBERS s1
    1) "e"
    2) "c"
    3) "d"
    4) "f"
    5) "y"
    6) "b"
    7) "a"
    127.0.0.1:6379[3]> SREM s1 a b g
    (integer) 2
    127.0.0.1:6379[3]> SMEMBERS s1
    1) "e"
    2) "c"
    3) "d"
    4) "f"
    5) "y"

    SortSet 类型操作,应用场景如歌曲排行榜这种:

    # 创建集合
    ZADD music 0 a 0 b 0 c 0 d 0 e 0 f
    
    # 给指定元素自增指定值
    ZINCRBY music 1 a
    
    # 查看所有元素
    ZRANGE music 0 -1
    
    # 查看所有元素和分值
    ZRANGE music 0 -1 withscores
    
    # 显示指定元素角标
    ZRANK music a
    
    # 统计元素个数
    ZCARD music
    
    # 统计分 1<=x<=2 的个数
    ZCOUNT music 1 2
    
    # 查看指定元素的分
    ZSCORE music a
    
    # 查看 1 - 2 分之间的元素和分
    ZRANGEBYSCORE music 1 2 withscores
    
    # 删除元素
    ZREM music f
    
    # 删除指定分范围
    ZREMRANGEBYSCORE music 0 0
    
    # 删除指定角标范围
    ZREMRANGEBYRANK music 0 0
    
    # 指定范围倒序
    ZREVRANGE music 0 3
    
    # 分数范围倒序
    ZREVRANGEBYSCORE musci 3 0

    结果如下:

    127.0.0.1:6379[4]> ZADD music 0 a 0 b 0 c 0 d 0 e 0 f
    (integer) 6127.0.0.1:6379[4]> ZINCRBY music 1 a
    "1"
    127.0.0.1:6379[4]> ZINCRBY music 1 a
    "2"
    127.0.0.1:6379[4]> ZINCRBY music 1 b
    "1"
    127.0.0.1:6379[4]> ZRANGE music 0 -1
    1) "c"
    2) "d"
    3) "e"
    4) "f"
    5) "b"
    6) "a"
    127.0.0.1:6379[4]> ZRANGE music 0 -1 withscores
     1) "c"
     2) "0"
     3) "d"
     4) "0"
     5) "e"
     6) "0"
     7) "f"
     8) "0"
     9) "b"
    10) "1"
    11) "a"
    12) "2"
    127.0.0.1:6379[4]> ZRANK music a
    (integer) 5
    127.0.0.1:6379[4]> ZCARD music
    (integer) 6
    127.0.0.1:6379[4]> ZCOUNT music 1 2
    (integer) 2
    127.0.0.1:6379[4]> ZSCORE music a
    "2"
    127.0.0.1:6379[4]> ZRANGEBYSCORE music 1 2 withscores
    1) "b"
    2) "1"
    3) "a"
    4) "2"
    127.0.0.1:6379[4]> ZRANGEBYSCORE music -inf +inf limit 2 3
    1) "e"
    2) "f"
    3) "b"
    127.0.0.1:6379[4]> ZREM music f
    (integer) 1
    127.0.0.1:6379[4]> ZRANGE music 0 -1 withscores
     1) "c"
     2) "0"
     3) "d"
     4) "0"
     5) "e"
     6) "0"
     7) "b"
     8) "1"
     9) "a"
    10) "2"
    127.0.0.1:6379[4]> ZREMRANGEBYSCORE music 0 0
    (integer) 3
    127.0.0.1:6379[4]> ZRANGE music 0 -1 withscores
    1) "b"
    2) "1"
    3) "a"
    4) "2"
    127.0.0.1:6379[4]> ZREMRANGEBYRANK music 0 0
    (integer) 1
    127.0.0.1:6379[4]> ZRANGE music 0 -1 withscores
    1) "a"
    2) "2"
    127.0.0.1:6379[4]> ZREVRANGE music 0 -1 withscores
    1) "a"
    2) "2"127.0.0.1:6379[4]> ZREVRANGE music 0  3
    1) "a"
    127.0.0.1:6379[4]> ZREVRANGEBYSCORE musci 3 0
    (empty list or set)

    至此,简单的应用就到这里!

  • 相关阅读:
    杭电acm1517
    杭电acm1228
    杭电acm1859
    杭电acm1124
    杭电acm1327
    CPP Templates 之 template 关键字的用法技巧
    malloc与calloc区别
    CPP Templates 之 类模板的继承
    CPP Templates 之 模板演绎的注意事项
    CPP Templates 之 局部类模板特化
  • 原文地址:https://www.cnblogs.com/Dy1an/p/11792497.html
Copyright © 2020-2023  润新知