步骤/目录： 1.Redis简介与安装 2.redis的数据结构 （1）string （2）list （3）set （4）hash （5）zset （6）HLL 3.redis的一些命令 4.redis事务 5.TTL（time to live） 6.排序 7.发布/订阅 8.管道 9.redis GEO 10.其他本文首发于个人博客https://lisper517.top/index.php/archives/53/，转载请注明出处。本文的目的是初步介绍Redis、为爬虫使用redis打好基础，主要整理自 runoob教程 。这里介绍的内容非常浅显，更深入的内容请自行查询书籍。本文写作日期为2022年9月15日。运行的平台为win10和树莓派，编辑器为VS Code。1.Redis简介与安装Redis是一个由 Salvatore Sanfilippo 在2008年开始创造的 key-value 存储系统，是一种开源的非关系型（NoSql）数据库，它的特点有：基于内存，分布式，键值对，支持多种语言的API（Redis本身是由ANSI C写的）。虽然它主要在内存中运行，但也可以将数据保存在磁盘；它支持主从式的数据备份；它的读写性能极高（所以把Redis开放到公网上时还要注意安全性）；它支持事务，多个操作可以打包到一起，要么不执行，要么全部执行（all or nothing）；它支持5种数据类型（字符串，列表，hash散列，集合，有序集合）；它支持推送，key过期。总的来说Redis就是好。在使用Redis时，你可以把它用作主数据库，也可以用作辅数据库，不论何种方式，都是对关系型数据库功能的极大补充。由于redis的一些特性，它特别适合做存储标签这种一对多的工作，而存储标签在mysql这样的关系型数据库中比较麻烦；redis可以设置键的过期时间TTL（time to live），到期后自动过期，这是很多服务都需要的（比如登录cookie的过期）；redis的读写效率非常高，在轻度使用中很少会遇到redis是瓶颈的情况；redis的命令比sql要简单得多（因为它以键值对形式存储数据）。下面介绍三种安装redis的方法。需要注意，redis为了效率而牺牲了安全性，所以默认情况下redis几乎没有保护措施，不要把它开放到外网。在windows上安装redis：window版redis由热心网友维护，版本远落后于linux版或docker版（目前是5.0和7.0的差距），所以不推荐下载。需要的话，建议在windows上用docker安装redis，见 Docker入门（一） 。如果嫌麻烦的话，到 windows版redis下载网页 下载zip文件或msi文件，解压或安装即可。解压zip文件，或用msi文件安装后，在cmd中进入redis目录，运行 redis-server.exe redis.windows.conf 即可运行redis服务器端。然后在同样的目录下，运行 redis-cli.exe -h 127.0.0.1 -p 6379 即可连接到redis数据库。但是要注意，目前它的版本只有5.0，笔者在后续将演示redis使用tls双向验证，但这是redis 6.0后才加入的功能。所以有条件的话还是用docker装redis。在linux上：到 https://download.redis.io/releases/ 下载tar.gz文件，解压、 make 即可。具体过程为：mkdir /usr/local/redis cd /usr/local/redis wget https://download.redis.io/releases/redis-7.0.4.tar.gz #最新版本的redis tar -xzf redis-7.0.4.tar.gz cd redis-7.0.4 apt-get install pkg-config make gcc libssl-dev #一些依赖项 make BUILD_TLS=yesBUILD_TLS=yes 这个选项在redis 6.0以后可用，是用tls在传输层对redis通信加密的一种方式，在后续安全性的部分会提到。这里介绍一下如何用docker安装redis（安装docker、docker-compose请参考 Docker入门（一） 和 Docker入门（二））。在linux上使用如下命令（windows上也是一样的步骤，只是路径改一下）：mkdir -p /docker/redis/data/redis vim /docker/redis/docker-compose.yml写入如下内容：version: "3.9" services: redis: image: redis ports: - "56379:6379" volumes: - /docker/redis/data/redis:/data logging: driver: json-file restart: always然后运行：cd /docker/redis docker-compose config docker-compose up -d然后你可以使用redis客户端尝试连接，比如本文后面将用的python，但是首先需要 pip install redis 。然后写一个py文件：import redis, pprint r = redis.StrictRedis(host='127.0.0.1', port=56379, decode_responses=True, db=0) pprint.pprint(r.info())运行，如果成功连接的话它将会打印出redis服务器的一些信息。在python中，更好的连接方式是使用连接池：import redis pool = redis.ConnectionPool(host='127.0.0.1', port=56379, decode_responses=True, db=0) r = redis.Redis(connection_pool=pool)或者你也可以使用redis-cli连接，这是redis服务器端自带的软件。比如你可以进入docker-redis容器：cd /docker/redis docker-compose exec -it redis bash redis-cli -h localhost -p 6379 SAVESAVE 将返回一个 OK ，并且在/docker/redis/data下出现一个dump.rdb文件。实际上， SAVE 会把redis在内存中的数据写到磁盘中，这会在后面提及。更常用的测试连接命令为 ping ，服务器会返回一个 PONG 表示服务器已连接。另外， clear 可以清屏， exit 可以断开连接。最后，如果你想在redis中看到中文，使用 redis-cli --raw 来发起连接。除了redis-server、redis-cli，你还能找到redis-benchmark（性能测试工具，使用方法同redis-cli）、redis-check-aof（AOF文件修复）、redis-check-dump（RDB文件检查）。另外，如果想让redis把内存数据写到硬盘并关闭服务器，可使用 redis-cli SHUTDOWN 命令（由于docker-compose.yml里写了 restart: always ，所以它还会重启）。最后再提醒一下，目前的redis安装方式，效率极高，但安全性几乎没有，不要把它开放到外网了。后续将介绍如何通过一些方法提升redis的安全性。安装好redis后，使用 select 数据库编号 来选择一个数据库。默认情况下redis有16个database，从0~15编号，不支持自定义数据库名（你需要自己记住每个库里存了什么），不支持用户对单独一个数据库有权限。2.redis的数据结构正如前面提到过，redis中有5种数据结构：string字符串，list列表，hash散列，set集合，zset有序集合，接下来将一一介绍它们。下面介绍的操作是一小部分，更多操作参考 redis官网 。（1）string首先是字符串，它是redis最基本的类型，一般的格式就是一个键对应一个字符串。它还可以存储二进制数据，比如图片等，但它最大只能存储512MB（毕竟redis跑在内存里）。你可以在redis-cli尝试下面3种命令（set，get，del）：set test 123 OK get test "123" del test (integer) 1 get test (nil) del test (integer) 0set用于给键赋值，get用于取出键对应的值，del用于删除一个键。在上面的例子中，如果你在python中运行，代码如下：import redis r = redis.StrictRedis(host='localhost', port=536379, decode_responses=True, db=0) a = [] a.append(r.set('test', '123')) a.append(r.get('test')) a.append(r.delete('test')) a.append(r.get('test')) a.append(r.delete('test')) for i in a: print(i)这里把每个返回的值都打印了出来，注意观察对应关系。另外，如果字符串是纯数字的话，redis提供了 INCR ，用于让其自增1，这个函数返回自增后的数字（如果键不存在，会自动创建一个为 "0" 的值并自增为1）。常见的例子是用于存储阅读量，比如键为 page.view ，在里面存储阅读量。注意在redis键的命名中，要力求写详细、直观，一般用 : 或 . 来分隔。在mysql中对列可用指定 AUTO_INCREMENT 来让列值自增，在redis中则可以用 INCR 达到类似的效果。 INCRBY 可达到相同的效果，但是它可以指定增加多少。同系列的命令还有 DECR 、 DECRBY （decrby每太大用，因为incrby可以设置成负值）， INCRBYFLOAT （增加浮点数）。其他关于字符串的命令还有：APPEND ，用于向字符串的末尾追加字符串。STRLEN ，获取字符串长度。注意UTF-8编码中一个中文字符的长度为3。MSET 和 MGET 同时设置、获取多个键值。位操作，包括 GETBIT （获得字符串的一个bit位，超出范围时返回0）、 SETBIT （返回旧值）、 BITCOUNT （返回为1的bit个数）、 BITOP （进行位运算，包括 AND 、 OR 、XOR 、 NOT）。 使用位操作，可以让存储空间非常紧凑。最后，下面介绍的其他类型都是字符串衍生出来的，它们的键值只能是字符串，不能嵌套。（2）list下面介绍一下列表。列表是有序的，可以存储多个字符串，在redis-cli中它支持的方法有：lpush 在列表头部添加一个元素 rpush 在列表末尾添加一个元素 lrange 获取从头到尾、一定范围的元素（包含两端；支持负索引） ltrim 用法和lrange一样，但是它将会删除范围外的元素 lindex 获取从头到尾的第几个元素。支持负索引 lset 给出索引并赋值指定元素 lpop 从列表头部弹出一个或几个元素（弹出，意为返回这个元素的值，并且从列表中删除它） rpop 从列表末尾弹出一个或几个元素 llen 获取列表中元素个数 lrem 删除列表中的几个元素，这些元素的值需要指定。格式为 LREM key count value，count指定要删除几个，当count为正时从左边开始删，为负时从右边开始删，0时删除所有 linsert 在一个元素的前或后插入元素 rpoplpush 将旧列表转移到新列表 brpop 类似rpop，区别在于列表内无元素时会被阻塞（每当列表加入一个新元素时brpop就会返回这个元素）。常用于实现任务队列（可带优先级）如果熟悉数据结构的话，会发现这里的列表可以当作栈或队列使用。在redis-cli中实验如下：lpush test 123 (integer) 1 lpush test 234 (integer) 2 lpush test 345 (integer) 3 rpush test 456 (integer) 4 lrange test 0 -1 1) "345" 2) "234" 3) "123" 4) "456" lindex test 0 "345" lpop test "345" rpop test 2 1) "456" 2) "123" lrange test 0 -1 1) "234" del test (integer) 1除了这些命令，redis对列表还有其他操作，将在后面介绍。另外，一个列表最多可存储 2^32-1 个元素，即 4,294,967,295 。（3）set列表中可以出现相同的元素，且有序，但集合中每个元素不能相同，且set是无序的（set里的元素只有键没有值）。它支持的命令有：sadd 添加一个元素到集合 srem 从集合中移除一个元素 sismember 检查元素是否在集合中 smembers 返回集合的所有元素。这个命令在集合较大时运行很慢 sdiff 差集 sinter 交集 sunion 并集 sdiffstore 存储运算结果 sinterstore 同上 sunionstore 同上 scard 获得集合中元素个数 srandmember 随机获取一个元素。它可以添加count参数，当count为正时取出count个不重复元素，为负时表示可以重复。但是由于redis的底层机制，某些元素出现的概率可能更大 spop 随机弹出一个或多个元素使用例：sadd test 123 (integer) 1 sadd test 234 (integer) 1 sadd test 234 #添加重复元素时被忽略了 (integer) 0 sadd test 345 (integer) 1 sadd test 456 (integer) 1 srem test 123 (integer) 1 sismember test "123" (integer) 0 sismember test "234" (integer) 1 smembers test 1) "234" 2) "345" 3) "456" del test (integer) 1redis中的集合使用哈希表实现（只有键的hash），它增、删、查元素的复杂度都是O(1)。除了这些命令，redis对集合还有其他操作，将在后面介绍。另外，一个集合最多也可存储 2^32-1 个元素，即 4,294,967,295 。在一般的实践中，常用set来存储tag，或者用列表。比如，键名为 tag:标签名:posts ，值为set，存储带有该标签的文章id（4）hash散列是存储键值对的集合，它存储的值可以为字符串或数字（不能嵌套字符串以外的类型）。hash的命令有：hset 在hash中添加或修改一个键值对 hget 获取hash中指定键的值 hmset 添加或修改多个键值对 hmget 获取多个键值 hsetnx 仅当键不存在时新建一个键 hincrby 类似字符串的 incrby 操作 hgetall 获取hash中所有键值对 hexists 判断键是否存在 hdel 如果hash中存在一个或多个键，删除它 hkeys 获得所有键名 hvals 获得所有值 hlen 获得键值对数量使用例：hset test 1 111 (integer) 1 hset test 2 222 (integer) 1 hset test 3 333 (integer) 1 hset test 1 123 (integer) 0 hget test 1 "123" hgetall test 1) "1" 2) "123" 3) "2" 4) "222" 5) "3" 6) "333" hdel test 1 (integer) 1 hget test 1 (nil) del test (integer) 1一个hash可以看作mysql中的一行，不同之处在于每行包含的列可以不同。hash比较适合存储对象；它同样能存储 2^32-1 个键值对，即 4,294,967,295 。现在可用比较一下string和hash。比如你想存储一篇文章，需要存储的信息有文章名，文章url，文章内容等。那么你此时有两种选择，一是把文章对象序列化、转换为二进制数据，用string存储；二是用hash，把它当成mysql中的一行。用hash显得更直观，也不需要在读写是进行编解码。（5）zset有序集合，它可以看作是介于列表和集合之间，因为zset中的元素是唯一的，但它里面的元素有序；但它又像散列，存储键值对（但是zset中的键称为member，值称为score，值必须为浮点数）。zset支持的操作如下：zadd 添加键值对到zset（ +inf 和 -inf 表示正无穷和负无穷） zrange 取出范围内的成员值（键值），按score从小到大 zrevrange 同上，但是score从大到小 zrangebyscore 给定score范围，取出所有在范围内的元素（包含极值。如果不想包含，可加上 ( 如 "80 (100"） zrem 如果zset中存在一个或多个成员，删除它 zscore 获取元素的分数 zincrby 增加score zcard 获取元素个数 zcount 获取分数在范围之间的元素个数 zremrangebyrank 按照元素score从小到大的顺序删除范围内的元素 zremrangebyscore 删除指定分数范围的元素 zrank 获取元素的排名，从小到大排列 zrevrank 同上，从大到小 zinsertstore 计算并导出有序集合的交集。新zset中的分数会使用聚合函数，支持sum、min、max。还能设置权重 zunionstore 计算并导出并集使用例：zadd test 123 1 (integer) 1 zadd test 234 2 (integer) 1 zadd test 345 3 (integer) 1 zrange test 0 -1 1) "1" 2) "2" 3) "3" zrangebyscore test 124 345 1) "2" 2) "3" zrem test 1 (integer) 1 del test (integer) 1它也支持 2^32-1 个键值对。在应用场景上，一般string用于存储文件、文字；hash用于存储对象（描述对象的各种属性），可以当成mysql中的一行来使用；list用于列表、队列；set可用于去重；zset用于排行、权重等。（6）HLL在2.8.9版本中，redis添加了HyperLogLog，这种结构专用于数据量很大的集合，在一定误差内返回集合中元素的个数（不能返回元素本身），它主要用于计算视频点击量（上千万、上亿次）等。它的特点有：占用空间小，一个HLL键在redis中只占12KB，就能统计2^64量级的元素；使用了一些概率算法，标准差在 0.81% 左右（可以设置辅助因子降低，但要付出空间）。redis中HLL相关命令有：pfadd 添加元素到HLL中 pfcount 返回个数估算值 pfmerge 将多个HLL合并为一个HLL3.redis的一些命令除了前面提到的 ping ， exit ， clear ， save ， shutdown ， select ，数据类型相关的命令，还有一些命令：keys 模式 ，返回所有匹配模式的键。在模式中， ? 匹配一个字符， * 匹配0到任意个字符， [] 用于给出单个字符的范围， \ 用于转义。DEL ，删除一个或多个键。不能用通配符，但是可在linux命令行借助管道与xargs实现类似的功能： redis-cli KEYS "模式" | xargs redis-cli DEL 。DUMP ，把一个键序列化，类似python中decode的功能。EXISTS ，检查键是否存在。EXPIRE ，为键设定过期时间（单位为秒）。到过期时间后，键会被删除。EXPIREAT key timestamp ，和 EXPIRE 功能相同，但是使用UNIX时间戳（从1970年1月1日到现在的秒数）。PEXPIRE ，和 EXPIRE 功能相同，只是单位为毫秒。PERSIST ，取消键的过期时间。TTL （time to live），以秒为单位返回键的剩余时间。PTTL ，以毫秒为单位返回键的剩余时间。KEYS ，给出一个pattern，返回符合模式的键。MOVE ，把键转移到另一个库中（redis中默认有16个库）。RANDOMKEY ，返回一个随机键。RENAME ，修改键名。RENAMENX ，仅当要改成的键名不存在时，将旧键名改为新键名。SCAN ，返回可迭代的数据库键（数据库编号）。TYPE ，返回键对应值的类型。更多命令可参考 redis官网 。4.redis事务事务（transaction）是现在很流行的一个概念。设想我进行一个转账1000￥的操作，银行的数据库系统需要进行两步：从我的账户扣去1000，然后给目标账户增加1000。但是如果中间出了差错，比如我的账户扣钱、对方账户却没有收到钱，这怎么办呢？这种类型的问题可用事务解决，包括在事务内的多条命令要么全部执行，要么全部都不执行，不存在执行一半的状态。在redis-cli中执行事务如下：multi 命令1 命令2 ... execredis先接受各条命令，当接收到exec时redis会将所有命令执行。如果在客户端输入命令时断线，redis就不会执行命令。另外，事务不会被其他命令打断，redis在执行一个事务时会把它执行完，再执行其他命令或事务；redis中的事务也不支持回滚。另外，如果事务中的某条命令有错误，其他命令也会继续执行。事务相关的命令除了 multi 和 exec ，还有：discard 取消事务 watch 监视键 unwatch 放弃监视键watch 是事务的重要功能之一，它用于监视键，保证在事务执行前相关的一些键不被改动，一般格式为：watch multi exec如果watch监视到了键被改动，事务的执行将被阻止（watch的作用不是阻止键被改动，而是阻止事务执行）。5.TTL（time to live）这里介绍一下redis的键过期功能。使用 expire 可以为一个键设置过期时间，单位为秒，到时间后该键会自动被删除。使用 ttl 则可以返回一个键剩余的时间，单位为秒（当键不存在时返回-2，键没有设置过期时间时返回-1）。使用 persist 可以取消键的过期时间，成功取消时返回1，否则返回0。另外，如果用 set 、 getset 等命令为键赋值，也会取消过期时间（incr 、 lpush 、 hset 、 zrem 等修改键值的命令则不会）。pexpire 以毫秒设置ttl。对应的有 pttl 。最后，还有 expireat 和 pexpireat ，它们给出的是UNIX时间，到该时间后删除键。另外，如果键是被expire相关命令删除，watch不会认为键被改动过。使用ttl功能，可以方便地为网页提供cookies等服务。6.排序redis中使用 sort 排序（升序），用 sort key desc 降序排序，用 sort key alpha 对字符串排序。在hash中，使用 sort 键名 by 参考键名*->字段名 可以指定排序的字段，redis会用字段值来替换 * ，by只能出现一次； sort by GET 参考键名*->字段名 可以返回指定的字段，get可以出现多次，用 # 可以代替元素本身的值； sort by get STORE 键名 可以把结果保存到新的键中。7.发布/订阅redis中提供了发布、订阅的功能。类似youtube，发布者向频道（channel）中发布一个消息，订阅者会收到这个消息。发布消息的命令为 publish ，订阅频道的命令为 subscribe 。另外还有以下命令：unsubscribe 可以取订一个或所有频道；psubscribe 按一定的模式订阅频道。支持的匹配符有 ? 、 * 等；punsubscribe 按模式退订频道。在分布式的scrapy中，主机发布待爬url就可以用publish，所有订阅url频道的机器就能收到待爬url。另外，redis 5.0后新增了stream，它主要用于消息队列。publish的一个特点是不会存储之前发布的消息，就是说新订阅的用户不能接受到订阅之前发布的消息。stream就是为了解决这个问题而出现的，它对历史发布的消息进行了持久化8.管道在redis的使用中，上面提到的方法都有返回值。日常使用中，redis-cli发出指令，server收到后执行并返回结果，如果client要执行多条语句，有时只需要最后的值，就可以使用管道。管道应用于多条命令，每条命令的执行不依赖于前面的命令，只需要最后的结果时。管道的具体实现和编程语言有关，比如用python：import redis pool = redis.ConnectionPool(host='127.0.0.1', port=56379, db=0, decode_responses=True) r = redis.Redis(connection_pool=pool) pipe = r.pipeline() pipe.set('test', '123') #pipe的其他操作 pipe.execute()你会发现这和pymysql差不多。使用管道，即使在局域网中，也可以大大降低延迟。9.redis GEO在redis 3.2版本新增了geo功能，主要用于计算实际的地理位置。这里就不过多介绍了。10.其他save 命令可将内存中的数据写入磁盘，默认情况下是dump.rdb文件。恢复数据时将这个文件放到redis安装目录（用 config get dir 查看）即可（docker-redis则是放到容器的/data下）。bgsave 在后台执行save。client 相关操作，包括 client list （查看所有连接的客户端）、 client setname （设置当前连接的名称）、 client getname （获取连接名称）、 client pause （客户端挂起多少毫秒）、 client kill 关闭客户端连接。redis支持分区，就是把一个很大的键分成小份，每个redis实例只保存它的一个子集，这个技术稍微有些复杂，不拓展了。redis命令行使用Lua语言，并且支持编写脚本（如同mysql）。客户端提供一个脚本后，其会永久存储在redis中，便于其他客户端使用。Lua的语法这里也不介绍了。config 系列命令，可获取server的配置。redis支持主从模式，这主要是因为一台机器的资源有限。当需要扩展时，你可以在一台机器上运行主redis，其他机器上运行从redis；主redis负责写入的操作，从redis会把数据拷贝到本地、负责读取的操作，也称为读写分离。最后，要提醒一下：注意redis的安全性；安装redis的时候提到过 make BUILD_TLS=yes 这个选项，但是redis应该尽量追求效率，只在内网运行，尽量不用tls等安全手段，因为会降低redis的速度。redis内部使用Lua语言，有时你使用爬虫入库的东西可能被当成脚本执行，比如说给你把redis清空（ flushall ），这点要注意（反爬手段之一）；如果想更深入学习redis，可以参考 redis的官方文档 或 《redis实战》 等书籍。
步骤/目录： 1.在windows笔记本上下载并配置redis-server 2.购买阿里云服务器，安装frp并配置frps服务器端 3.配置frpc客户端 4.开启服务并验证 5.附录：mysql+frp （1）修改配置 （2）创建远程连接用户 （3）赋予用户权限并刷新退出 （4）打开端口 （5）修改frpc.ini并开启frp本文首发于个人博客https://lisper517.top/index.php/archives/3/，转载请注明出处。本文实验日期2022年1月31日。采用windows笔记本（跑redis服务器）+阿里云服务器（系统镜像Ubuntu 20.04）1.在windows笔记本上下载并配置redis-serverredis官方不建议在windows下运行redis，所以并未提供windows版redis下载。有一些其他大神更新了windows版redis，以下推荐2个：首先是微软版redis。由微软方提供，于2016年7月1日更新了3.0.504版后停止更新。其次是tporadowski版redis（推荐）。由github用户tporadowski提供，目前最新版本为2021年10月18日更新的Redis 5.0.14 for Windows。（若遇到github网页无法打开，可在gitee上注册并导入仓库后下载）（根据runoob网站，Redis5.0新增了Stream数据结构，所以还是下新版的好）对于tporadowski版redis，下载.zip包，解压到安装目录即可。解压完毕后，打开Redis文件夹，编辑redis.windows.conf文件，需要修改3处：将bind 127.0.0.1行注释掉。这一行是仅允许从本地访问redis；用frp应该不用改，但是笔者需要在局域网中访问，所以还是打开了。 将protected-mode yes改为protected-mode no。老版本的redis可能没有这一行，如果没有则建议重新下载新版redis； 新增一行：requirepass 你的密码。由于redis的处理速度较快，建议密码设置的复杂一些。配置完成后，打开cmd命令行，cd到redis文件夹（也可以将redis文件夹添加到系统路径），输入redis-server redis.windows.conf，正常显示redis服务器端界面，即可。在linux下redis的配置也差不多，不同的是linux下redis的配置文件是redis.conf。2.购买阿里云服务器，安装frp并配置frps服务器端首先介绍一下frp。frp分为frps（server）和frpc（client），其中frps运行在有公网ip的云服务器上，frpc运行在内网中的机器上。frp主要用于把内网机器的端口映射到云服务器端口，比如把内网机器的22端口（一般用于ssh）映射到云服务器的6000端口，那么访问云服务器的6000端口即可接入内网机器的ssh服务。如果有其他方法搞到公网ip，也可以跳过这一步。随便选择一个便宜的服务器，购买后安装镜像，这里选择的系统镜像是Ubuntu 20.04。在左侧 服务器运维-远程连接 中设置一下root账户密码，然后下载putty，通过putty连接：连接类型为SSH，端口为默认的22，主机地址填云服务器的ip地址。输入root和root密码后即登录到云服务器。目前frp最新版本为0.38.0（2021年10月25更新）。这里安装frp到/bin目录下（wget github速度慢可以换成gitee上的仓库）：cd /bin wget https://github.com/fatedier/frp/releases/download/v0.38.0/frp_0.38.0_linux_amd64.tar.gz tar -zxvf frp_0.38.0_linux_amd64.tar.gz mv frp_0.38.0_linux_amd64 frp cd frp nano frps.ini然后配置一下frps.ini：[common] bind_port = 7000 #frpc上也要有相同的token值 token = 你的密码 #配置log log_file = /var/logs/frps.log log_level = info log_max_days = 3 #frps统计板 dashboard_port = 7500 dashboard_user = wuhuqifei dashboard_pwd = wuhuqifei kcp_bind_port = 7000解读一下配置选项：bind_port是frp使用的端口；token是密码令牌；log是日志相关；dashboard是统计板，设置好以后，网页访问 服务器ip:7500 即可看到frps的统计情况，user和pwd分别设置统计板的用户名密码（不用太复杂，简单易记即可）。如果后面运行frps时显示没有frps.log文件，可以自己新建一个并chmod改一下权限（或者直接删掉log相关设置）。最后的kcp_bind_port是多消耗15%左右流量、降低tcp延迟的，不要也可以不加。详细配置可以参考frps_full.ini。配置完成后，需要打开云服务器相应端口。在 安全-防火墙 中新增规则，打开7000和7500端口（云服务器在此处打开，非云服务器则使用ufw、iptables等。云服务器用ufw会出问题）。附带一些github上常见问题：流量是否经过服务器中转？ 目前除了 xtcp 外，其他类型的内网穿透模式的流量都需要经过 frps 所在服务器中转。 网络传输速度慢是什么原因？ 由于流量需要经过服务器转发，所以传输速度的快慢取决于服务器的下行带宽和客户端的上行带宽，通常家用宽带的上行带宽较低，限制了出口的速度。 另外一种情况是服务器部署在国外的 VPS 上，丢包率较高，也会影响到传输速度。这种情况下可以考虑开启 kcp 传输模式。 开启加密和压缩会消耗一定的 cpu 资源，且影响到传输速度，具体影响情况取决于机器性能。 客户端连接失败，提示 authorization failed 出现这种情况说明鉴权失败，检查 frps 和 frpc 的配置文件中的 token 是否一致。 客户端连接失败，提示 authorization timeout 出现这种情况是因为 frps 所在服务器和 frpc 所在服务器的系统时间相差较大。如果不希望在身份校验时加入系统时间，可以将 frps 配置文件中的 authentication_timeout 设置为 0 来解决这个问题。 frpc 能否在系统启动阶段无网络时一直等待而不是直接退出？ 在 frpc 的配置文件中将 login_fail_exit 设置为 false，则 frpc 启动后会不断尝试连接 frps，直到连接成功，而不是直接退出。最后使用./frps -c ./frps.ini即可启动frps。启动后不能关闭putty，这时可以访问7500端口查看是否成功开启。3.配置frpc客户端linux安装frp同上。对于windows，在frp下载页面下载frp_0.38.0_windows_amd64.zip，解压到目标文件夹即可。windows安全中心可能会删掉frps.exe，因为用不到所以无妨。配置一下frpc.ini：[common] server_addr = 云服务器ip地址 server_port = 7000 token = 你的密码 login_fail_exit = false [frp-redis] type = tcp local_port = 6379 local_ip = localhost remote_port = 16380解读frpc.ini：[common]是基础设置，下面的[frp-redis]是一个映射。以后要添加新的映射就在下面加，不用改动[common]，具体可以参考frpc_full.ini。要注意的是，如果有多个内网机器的多个端口需要映射，每个映射名要不同。比如多个redis要开放到外网，就可以写[frp-redis-1]、[frp-redis-2]、[frp-redis-3]等等。然后打开云服务器的16380端口（同前），本地的6379端口不用打开（因为frp穿透时，被映射的本地端口接收的操作都会被frp改成从本地发起）。Ubuntu系统可以安装ufw，然后ufw allow 6379（其他发行版请自行搜索）。另外，windows打开端口，是在 控制面板-Windows防火墙-高级设置-入站规则-新建规则 ，新建一个tcp类型、6379端口的规则，之后有程序使用6379端口时即可使用netstat -na查看所有开放的端口。以上都配置完后，使用frpc -c frpc.ini即可开启服务。这时访问dashboard地址，就能在 Proxies-TCP 中看到名为 frp-redis 的服务，其status为online。4.开启服务并验证验证时需要在云服务器上也安装redis。本例中云服务器的系统镜像是Ubuntu20.04，可以直接用apt下载：apt install redis-server开启frps：使用putty连接至云服务器，输入frp路径\frps -c frp路径\frps.ini开启后勿关闭putty。开启frpc：在windows下，cmd中输入frp路径\frpc -c frp路径\frpc.ini开启后勿关闭cmd窗口。开启redis-server：在windows下，cmd中输入redis路径\redis-server redis路径\redis.windows.conf开启后勿关闭cmd窗口。这时用另一个putty窗口连接到云服务器，输入redis-cli -h 云服务器ip -p 16380 -a redis密码（也可省略-a，在redis命令行中使用auth命令）其中redis密码即requirepass中自己设置的密码。登录上后使用ping命令，服务器端会返回PONG。之后为了方便，可以设置开机自动运行frps、frpc、redis-server。之后即可将redis用于scrapy-redis等其他用途。5.附录：mysql+frp这里假设windows10机器上已安装好mysql。（1）修改配置在mysql安装目录下找到配置文件my.ini，添加一行：bind-address=*允许从其他ip地址访问mysql数据库。用frp应该不用改，但是笔者需要在局域网中访问，所以还是打开了。（2）创建远程连接用户在mysql命令行中输入以下命令，可查看mysql用户及允许登录的地点：select distinct concat('User: ''',user,'''@''',host,''';') as query from mysql.user;如果想将root登录的地点改为任意ip，可使用：RENAME USER 'root'@'localhost' TO 'root'@'%';但允许root用户远程登录mysql比较危险，不如创建一个新用户专门用于远程连接：CREATE USER 'mysql-remote1'@'%' IDENTIFIED BY '你的密码';mysql 8.0后用户认证默认使用sha2，这里将该用户改为用原生密码认证：ALTER USER 'mysql-remote1'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';创建用原生密码认证的用户，只需将上述命令的ALTER改为CREATE。（3）赋予用户权限并刷新退出接着赋予该用户一定的权限。输入下面的命令可以给账号全局权限，包括创建（CREATE）、修改（ALTER）、删除（DROP） 数据库、表、用户，任意表的插入（INSERT）、更新（UPDATE）、删除（DELETE）操作权限。可以使用 SELECT 查询数据，使用 REFERENCES 建立外键关系权限，以及使用 RELOAD 权限执行 FLUSH 操作的权限。当然，你也可以根据自己都需求，对账号权限进行调整。GRANT CREATE, ALTER, DROP, INSERT, UPDATE, DELETE, SELECT, REFERENCES, RELOAD on *.* TO 'mysql-remote1'@'%' WITH GRANT OPTION;这里我需要能远程修改数据库，所以只赋予了部分权限：GRANT ALTER, INSERT, DELETE, SELECT on *.* TO 'mysql-remote1'@'%' WITH GRANT OPTION;然后刷新权限并退出:FLUSH PRIVILEGES; quit;（4）打开端口mysql默认用3306端口，但是本地端口不用打开。在云服务器上打开frp要用的端口（以16381为例）。（5）修改frpc.ini并开启frp在frpc.ini中添加：[frp-mysql] type = tcp local_port = 3306 local_ip = localhost remote_port = 16381之后重启win10机器的frpc即可。