news 2026/9/25 4:44:19

Redis三主三从集群搭建实战:从零配置到故障转移验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis三主三从集群搭建实战:从零配置到故障转移验证

1. 为什么是"三主三从":集群架构背后的取舍逻辑

"三主三从"这四个字,是所有学习Redis集群安装的人绕不过去的一道坎。如果你已经搞定了单机版Redis,也做过主从复制,接下来大概率就会遇到一个现实问题:业务数据量一上来,单机内存不够用了,主从架构虽然能扛读写分离,但主节点一挂需要人工介入,而且数据量超过单机物理上限时,加再多副本也解决不了扩容问题。这时候就需要引入Redis集群——把数据水平切分到多个节点上,同时通过多副本保证高可用。这篇文章我会按照自己在一台Linux服务器(示例用的是Rocky Linux 9,CentOS 7/8流程几乎一致)上从零搭建三主三从Redis集群的完整过程,把配置、命令、验证步骤和我踩过的坑一次性讲透,适合已经会Redis单机安装、准备上集群的运维和开发同学参考。

1.1 单机、主从、集群:三种模式的分水岭

很多人在"该不该上集群"这个问题上纠结很久。我个人的判断标准很简单:只要单台服务器的内存已经快被Redis占满,或者你担心某个节点挂了之后整个缓存服务不可用,就该考虑上集群了。

单机Redis最大的优势就是简单,一个进程、一个端口、一套配置文件,所有数据都在一个实例里,所有命令都能用。但它有两个天花板:一是容量天花板,你的内存多大,Redis就能缓存多少;二是可用性天花板,进程一崩,全站缓存瞬间归零,数据库直接被流量打穿。

主从复制解决的是可用性,不解决容量。Master写、Slave同步,你可以做读写分离,Master挂了还能手动把Slave提升上来,但这个"提升"通常需要人工干预或者额外搭配哨兵组件。更关键的是,主从架构下所有节点存的是同一份数据,你加再多Slave,总容量还是只有Master那台机器那么大。

集群模式跟前面两种有本质区别:数据不是冗余存放,而是被分片存放在不同节点上。它把一个完整的Key空间切成16384个槽位,每个主节点负责其中一部分槽位,每份数据又有自己的副本节点。三主三从是我最推荐的入门规模——三个主节点把数据水平切成三份,任何一个主节点挂了,对应的从节点能在几秒内顶上,整体容量是三台服务器的内存总和。

1.2 16384个槽位如何在三主之间分配

Redis Cluster里判断一个Key该放到哪个节点,靠的是CRC16算法:对Key做CRC16校验,然后对16384取模,得到一个0到16383之间的槽位号,这个槽位属于哪个主节点,Key就落在哪个主节点上。

16384这个数字不是随便定的。官方设计时考虑了消息开销和心跳包大小——集群节点之间通过Gossip协议互相交换槽位信息,每个节点的心跳包里要携带自己负责的槽位bitmap,16384个槽位换算成位图是2KB(16384/8),能压在合理范围内。

三主节点分16384个槽,非常接近均分。默认情况下每个主节点大约负责5461个槽(其中两个主节点各5461,一个主节点5462)。如果你三个主节点的内存不一样大,可以用reshard手动调整槽位权重,给内存大的节点多分一些槽位,默认是按节点数均分。

理解槽位分配之后,很多现象就解释得通了:比如集群模式下MGET这种跨Key操作,如果多个Key分布在不同的槽位节点上,是没法直接执行的,需要用Hash Tag把相关Key归到同一个槽位里。这就是集群架构给应用层带来的第一个约束,后面接入客户端时还要再提一次。

1.3 三主三从的最少节点门槛与仲裁机制

为什么官方文档明确写了"一个集群最少需要6个节点"?因为集群模式下,每个分片(Shard)至少要有1主1从,否则这个分片上的数据就没有任何冗余。三个分片对应三个主节点三个从节点,刚好凑成6个。

如果只有三主零从,集群也能创建,但任何一个主节点挂了,它负责的那部分槽位就没人接管了,集群会进入fail状态,部分Key完全不可用。从这个角度看,三主三从是最小的高可用集群规格。

集群里的主从关系不是Redis Sentinel那种独立哨兵进程在监控,而是节点之间互相通过Gossip协议通信。每个节点每秒会跟其他节点交换PING/PONG消息,把节点状态(在线、疑似故障、已故障)传遍整个集群。当一个主节点被多数主节点标记为疑似故障(PFAIL),并且超过cluster-node-timeout设定的时间后,它会被正式判定为FAIL,这时它名下的从节点就会发起选举,成为新的主节点。

这个机制没有中心节点,任何一个节点挂了集群都还能自我修复,代价就是故障检测需要几秒到十几秒的延迟,具体由cluster-node-timeout控制,我习惯设置为15000毫秒。

1.4 端口规划:从6379到16379

安装前先把端口想清楚,后面能少踩一半的坑。我见过太多人只在防火墙里放开了6379,结果集群一直创建不起来,日志里全是节点连接超时,最后发现是集群总线端口没放行。

Redis Cluster里每个节点实际占用两个TCP端口:一个是客户端连接端口(client port),默认6379,用来处理命令请求;另一个是集群总线端口(cluster bus port),默认是客户端端口加10000,也就是16379。节点之间所有Gossip通信、槽位迁移、主从握手全部走总线端口。

三主三从意味着你有三个客户端端口和三个总线端口。我习惯的规划如下:

节点角色客户端端口集群总线端口数据目录
Master-1637916379/data/redis/6379
Slave-1638016380/data/redis/6380
Master-2638116381/data/redis/6381
Slave-2638216382/data/redis/6382
Master-3638316383/data/redis/6383
Slave-3638416384/data/redis/6384

如果六个节点不在同一台机器上,而是在三台或多台机器上,则每台机器上要规划好各自的端口。这里顺便提醒一句:云服务器控制台的安全组里放行的端口,和你Linux服务器上firewalld或iptables放行的端口,必须同时保持开放,缺一个都不行。

2. 环境准备与关键配置:编译安装、系统参数、目录规划

2.1 编译安装Redis前的系统依赖

三主三从集群对操作系统的要求,其实比单机版高不了多少。我这里以Rocky Linux 9为例,CentOS 7/8、Ubuntu Server的流程大同小异,只是包管理器从yum/dnf换成了apt。

首先确认系统里有没有编译工具链。Redis是C语言写的,从源码编译安装必须有gcc和make。Rocky Linux 9自带的gcc版本足够编译Redis 7.x:

yum install -y gcc gcc-c++ make tcl

tcl是给Redis跑内置测试用的,跑make test会用到。如果你不想跑测试,可以省略,但我建议还是装上,编译完跑一遍make test能提前暴露很多潜在问题。

然后去Redis官网或国内镜像站下载源码包。我用的版本是redis-7.0.14,7.x系列在集群功能和稳定性上已经很成熟了。

wget https://download.redis.io/releases/redis-7.0.14.tar.gz tar -xzf redis-7.0.14.tar.gz cd redis-7.0.14 make -j$(nproc) make install

make install会把redis-server、redis-cli这些二进制文件装到/usr/local/bin下。装完之后先执行redis-server --version确认版本号,再顺手跑一下redis-benchmark --version,防止某些发行版提前装了低版本覆盖PATH。

2.2 三个必调的系统内核参数

Redis官方文档里点名了几个系统参数,单机版调不调影响不大,但集群版不调,运气不好会出诡异问题。

第一个是vm.overcommit_memory。Redis做RDB持久化时会fork子进程,在写COW(写时复制)页面时,如果系统内存不够又启用了默认的overcommit策略,内核可能拒绝分配内存,导致fork失败。集群模式下每个节点都可能持续做RDB/AOF操作,保险起见设为1:

sysctl -w vm.overcommit_memory=1 echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf

第二个是关闭Transparent Huge Pages(THP)。THP会把小内存页合并成大页,本意是减少TLB miss,但Redis的AOF重写和RDB fork对内存页的释放时机非常敏感,THP反而会导致fork后延迟变高、内存占用暴涨。关闭方式:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

这个修改重启后会失效,需要写进rc.local或者用systemd unit文件固定。

第三个是somaxconn。如果生产环境的并发连接数很高,内核backlog太小会导致客户端建连超时。我一般顺手调大:

sysctl -w net.core.somaxconn=1024 sysctl -w net.ipv4.tcp_max_syn_backlog=1024

这些参数单独拿出来看都不起眼,但集群里6个节点同时跑起来之后,任何一个因为fork失败或连接超时都可能引发雪崩式的故障迁移,提前调好是值得的。

2.3 目录与账号规划

我最开始搭集群的时候,把Redis数据目录放在/usr/local/redis下面,结果机器重装,数据全没了。后来学乖了,统一用/data/redis/端口号的结构,每个节点一个独立目录,日志、RDB文件、AOF文件、节点配置文件都在各自目录里,排查时非常直观。

mkdir -p /data/redis/{6379,6380,6381,6382,6383,6384} mkdir -p /data/redis/logs

生产环境建议给Redis单独建一个系统账号,不要用root跑。注意Redis目录的属主和属组都要改成该账号,否则以后AOF重写写临时文件时会遇到权限拒绝:

useradd -M -s /sbin/nologin redis chown -R redis:redis /data/redis

集群模式下每个节点的nodes-6379.conf这类文件也是运行中自动生成的,所以目录权限必须放给redis用户。我见过有人图省事用root启动所有节点,数据目录权限倒是没问题了,但一旦Redis进程被利用,整台机器就直接暴露在风险里,这个习惯不能养。

2.4 防火墙与安全组

这里单独拎出来说,是因为我至少帮四个人排过"明明端口开着为什么集群建不起来"的问题。你需要在两个层面同时放行端口:Linux本机的firewalld或iptables,以及云控制台的安全组。

以firewalld为例:

firewall-cmd --permanent --add-port=6379-6384/tcp firewall-cmd --permanent --add-port=16379-16384/tcp firewall-cmd --reload

关于SELinux,Rocky Linux默认是Enforcing模式,如果不想折腾,建议临时设为Permissive验证一下集群能正常跑,再决定要不要给Redis写SELinux策略:

setenforce 0

我不会一刀切说"必须彻底禁用SELinux",但现实情况是大多数运维同学直接选择关闭它,避免大量不明所以的访问拒绝日志。如果你的安全要求严格,那可以另写SELinux模块,把6379/16379等端口的监听和连接权限赋给redis进程。

3. 六个节点的配置文件逐个拆解:从单机到集群的关键开关

3.1 cluster-enabled是第一个分水岭

Redis单机实例和集群节点,本质上是同一份二进制,只是配置文件里几个开关不同。第一个开关就是cluster-enabled:

cluster-enabled yes

这个参数默认是no。设为yes之后,Redis进程启动时会把自己当成集群节点来运行,开始监听集群总线端口,并且会读取或生成一个集群节点配置文件。这个文件默认叫nodes.conf,里面记录着这个节点已知的集群拓扑信息。

第二个关键开关是cluster-config-file,它指定刚才说的节点配置文件名。每个节点的文件名一定要不同,否则多个进程共享同一个nodes.conf,可能会出现非常诡异的角色混乱:

cluster-config-file nodes-6379.conf

第三个是cluster-node-timeout,单位毫秒,表示一个节点多久没响应就会被判定为疑似故障。15秒是比较中庸的值。设得太小,网络抖动会导致频繁误判和主从切换;设得太大,真故障时恢复时间会拖得很长。

还有一个很多人忽略的cluster-require-full-coverage参数。默认yes,表示集群中只要有任何一个分片的槽位没有主节点负责,整个集群就会拒绝客户端请求。在三主三从的正常情况下没问题,但在做节点维护、临时取出节点时,建议设为no,否则业务会有大面积报错:

cluster-require-full-coverage no

3.2 一份模板,六份变体

下面是一份我实际使用的节点配置文件模板,以6379节点为例:

bind 0.0.0.0 protected-mode yes port 6379 daemonize yes pidfile /var/run/redis_6379.pid logfile /data/redis/logs/redis-6379.log dir /data/redis/6379 appendonly yes appendfsync everysec cluster-enabled yes cluster-config-file nodes-6379.conf cluster-node-timeout 15000 cluster-require-full-coverage no

其他五个节点只需要把port、pidfile、logfile、dir、cluster-config-file里的路径和文件名改成对应端口即可。

有几个参数值得讲一下。

bind 0.0.0.0意味着监听所有网卡。如果你有多块网卡或者云主机有内外网IP,更精准的做法是只bind内网IP,或者配合cluster-announce-ip/port来声明客户端能访问到的地址。云上环境经常出现一个问题:节点之间通过内网通信没问题,但客户端从外网连接时拿到的节点导向地址可能是内网IP,导致客户端无法跳转。这种情况你必须在每个节点配置里显式设置cluster-announce-ip为公网IP或客户端可达的IP。

protected-mode yes配合bind 0.0.0.0是有风险的。Redis的protected-mode逻辑是:如果没设置requirepass,并且bind了所有网卡,那Redis只允许来自回环地址的访问。这样做的结果是集群创建时节点之间通过真实IP通信会被拒。所以我建议要么设置requirepass密码,要么在严格隔离的内网环境里把protected-mode设为no。我在演示环境里用的是后者,但生产环境必须设密码。

生产环境的密码是集群模式里的经典难点:所有主从节点必须使用同一个requirepass,同时还要设置masterauth,否则主从切换后,新主节点无法向旧主节点认证:

requirepass your-strong-password masterauth your-strong-password

redis-cli创建集群时也要带密码认证参数。这个细节后面会讲。

3.3 为什么六个节点建议全部先独立启动

配置写完之后不要急着创建集群,而是先把六个节点全部以单机模式启动,这样能先把配置错误暴露得干干净净。

启动方式很简单:

redis-server /data/redis/6379/redis-6379.conf redis-server /data/redis/6380/redis-6380.conf # ... 依次启动剩余四个节点

启动后逐个用redis-cli确认每个节点的状态:

redis-cli -p 6379 ping redis-cli -p 6379 info server | grep version redis-cli -p 6379 cluster info

注意cluster info在未创建集群时会返回cluster_state:fail,这是正常的,因为节点虽然启动了集群模式,但还没有形成集群拓扑。你要确认的是节点进程能稳定运行,日志里没有明显报错。

我还习惯在这时候验证一次重启。随便挑一个节点kill掉再启动,确认它能正常重新加载目录里的AOF/RDB文件,这一步能避免后面集群建好后才发现持久化配置有问题,导致重启丢数据。

4. 集群创建与角色确认:用一条命令把六个节点串起来

4.1 redis-cli --cluster create的参数细节

六个节点都启动确认无异常后,终于可以创建集群了。Redis 5.0之后的redis-cli内置了集群管理的完整子命令,不需要再额外安装redis-trib.rb,也不需要Ruby环境,对运维来说友好太多了。

创建命令如下:

redis-cli --cluster create 192.168.1.101:6379 192.168.1.101:6380 \ 192.168.1.101:6381 192.168.1.101:6382 \ 192.168.1.101:6383 192.168.1.101:6384 \ --cluster-replicas 1

--cluster-replicas 1表示每个主节点配备1个从节点。redis-cli会读一遍所有节点的信息,然后自动生成一个合理的分配方案。这个方案通常满足三个原则:槽位尽量均分;主节点尽量分散在不同机器上(如果节点跨机器);从节点尽量不与它的主节点落在同一台机器上。

如果配置了requirepass,创建命令里需要加认证参数:

redis-cli -a your-strong-password --no-auth-warning \ --cluster create 192.168.1.101:6379 ... --cluster-replicas 1

如果不加,你可能会在创建中途看到权限拒绝,然后整个创建流程卡在那里。

4.2 创建过程输出逐行解读

执行创建命令后,redis-cli会把六个节点信息打出来,然后问你是否接受这个分配方案。第一次跑的人容易被那一段"Can I set the above configuration?"卡住,回车确认就行。

确认后你会看到类似这样的输出:

[OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.

这段输出说明槽位已经分配完整,没有遗漏,没有重叠,16384个槽全部有主节点负责。到这步,集群就算创建成功了。

接下来验证节点角色。用cluster nodes命令:

redis-cli -p 6379 cluster nodes

输出里面每行是一个节点信息,包括节点ID、IP:端口、角色标志、负责的槽位范围。比如某种输出:

0c4f20be... 192.168.1.101:6379@16379 myself,master - 0 1700000000000 1 connected 0-5460

master节点后面跟的connected 0-5460就表示它负责0到5460号槽位。

4.3 集群状态验证三板斧

第一板斧,看cluster info的cluster_state是不是ok。注意每一节点上都可以执行,我用的是连接6379再查。如果你之前设了cluster-require-full-coverage yes,一旦某个分片的主节点挂了,cluster_state会立刻变成fail,所有命令都可能被拒绝。所以我一般按上面配置里写的那样,把它设成no。

第二板斧,验证槽位和数据的路由。用redis-cli的-c模式连接任意一个节点,写一个Key再读出来:

redis-cli -c -p 6379 set user:1001 zhangsan redis-cli -c -p 6381 get user:1001

-c模式下客户端会自动处理MOVED跳转和ASK跳转,所以即使Key落在其他节点上,读写也能成功。如果你不带-c,去非槽位节点写Key,会得到一个MOVED错误,这是集群路由的正常行为,不是故障。

第三板斧,验证主从复制。进入任意从节点执行info replication,确认role是slave,master_host和master_port指向正确的主节点,master_link_status是up:

redis-cli -p 6380 -c info replication

到这里,三主三从集群的基础功能已经全部就绪。接下来是这个项目里最有意思的部分——故障演练。

5. 故障演练、扩容思路与高频踩坑实录

5.1 手动杀掉主节点,观察从节点怎么上位

搭建集群的第一件事就是验证高可用,不是验证它能缓存数据。我的做法是挑一个主节点直接kill掉,观察集群的自动恢复流程。

比如杀掉192.168.1.101:6379:

kill -9 $(cat /var/run/redis_6379.pid)

杀之前先记录一下6379的从节点是谁。然后等10到15秒,再看cluster nodes:

redis-cli -p 6381 cluster nodes

你会看到原来6379的状态从master变成fail,而它对应的从节点从slave变成了master,接手了0-5460的槽位。整个过程不需要任何人工干预,这就是集群高可用的核心能力。

注意,这个failover不是瞬时的。Gossip协议需要传播故障信息,从节点需要发起选举并获得半数以上主节点的投票,整个过程通常十几秒。业务侧如果配置了合理的重试机制,这十几秒的抖动可以平滑过去。

杀掉的主节点重新启动之后,它的表现是:找到自己原来所在分片的新主节点,自动降级为从节点并开始同步数据:

redis-server /data/redis/6379/redis-6379.conf redis-cli -p 6381 cluster nodes | grep 6379

这里有个容易踩的坑:主节点被kill后,如果数据源目录里还有旧RDB/AOF数据,重新启动时会先把旧数据加载进内存,再向新主发送PSYNC进行全量同步。如果旧数据很大,重启后的一段时间可能占用较多内存和CPU,同步完成前它是不对外提供服务的,所以没事别乱kill生产主节点,最好走CLUSTER FAILOVER这种优雅切换。

5.2 扩容思路:增加一组主从的大致路径

三主三从只是个起点。业务增长到内存再次吃紧时,集群是可以在线扩容的,不需要重建。扩容的基本套路是先加节点,再迁移槽位。

把新节点的配置文件写好、启动好之后,用add-node将它加入集群:

redis-cli --cluster add-node 192.168.1.102:6385 192.168.1.101:6379

加进去的节点默认是master,但没有任何槽位,需要reshard把一部分槽位迁过去:

redis-cli --cluster reshard 192.168.1.101:6379 --cluster-from <源节点ID> --cluster-to <新节点ID> --cluster-slots 1000

reshard是个异步过程,槽位迁移时,相关Key会分批次从源节点搬到目标节点,期间客户端可能会遇到ASK错误,正常处理重试即可,不会有数据丢失。缩容就反过来,先把槽位移走,再用del-node移除节点。完整讲扩容又是一篇文章了,这里先把路线图画清楚,至少知道三主三从不是终点,随时可以往四主四从甚至更多节点扩展。

5.3 我踩过的四个高频坑

第一个坑:nodes.conf文件残留。如果你之前启动过一个Redis节点,后来删掉了它的数据目录,或者复用了同一个目录,里面残留的nodes.conf会让新节点以为它认识一堆节点,导致加入集群时报"Node is not empty"。解决办法很简单,搭建环境时用全新目录,或者删掉数据目录里所有nodes开头的文件再启动。

第二个坑:bind 127.0.0.1。这是单机版习惯害的。单机Redis绑定回环地址没问题,但集群节点之间需要跨IP通信,bind 127.0.0.1会导致节点间握手失败,日志里全是"Connection refused"。集群环境的bind最少要绑内网网卡地址。

第三个坑:防火墙只放行了业务端口,忘了集群总线端口。表现是节点能启动,redis-cli --cluster create命令能执行,但节点之间一直处于握手状态,pong收不到,集群卡在创建阶段。解决方式就是前面说的,6379-6384和16379-16384两段端口同时放行。

第四个坑:重复执行create命令。中途失败后直接再执行一次创建命令,六个节点里可能有一部分已经处于集群状态,这时候会得到各种奇怪的报错。我实测最有效的处理方式是:把相关节点进程全部停掉,清掉数据目录下的nodes.conf和RDB/AOF文件(保留配置文件),然后重新启动再创建。测试环境可以这么处理,生产环境千万别这么玩,最好先在测试环境完整演练一遍再上生产。

5.4 集群客户端接入与监控的一些补充经验

三主三从建成之后,接入层还有几个容易翻车的点。

使用Jedis或Lettuce这类客户端时,建议开启集群模式,不要把连接池里塞一堆普通Redis连接。开启集群模式后,客户端能自动感知MOVED和ASK重定向,维护节点列表和槽位映射,主从切换后也能自动刷新节点信息。

推荐在接入层之上再套一层带名字分区规则的算法。比如业务Key大多是形如user:10001、order:20240101这样的模式,可以在代码里预留Hash Tag机制,把需要一起操作的Key用{user:10001}这种格式归到同一个槽位,从而支持MGET这类跨Key操作的原子性。这个细节在集群规模变大后越来越重要。

最后提醒一下监控告警。三主三从的Redis集群,至少要监控这三个指标:cluster_state是否为ok、每个分片主从是否各在线、每个节点内存使用率和Key命中率的趋势。用Prometheus配合redis_exporter可以很方便地采集cluster info和cluster nodes信息,脚本定期抓取,有节点状态变化立刻触发告警。这些准备看起来麻烦,等真正出了事,节省的是你半夜爬起来救火的时间。

我在实际搭建过程中最大的感受是:Redis集群的原理一点都不神秘,难点全在配置细节和网络规划上。你只要把端口规划清楚、参数逐个理解透、故障演练提前跑一遍,三主三从这套架构就能稳稳地成为业务缓存层最可靠的那块压舱石。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 4:44:02

LTspice运放电路仿真:从虚短虚断到PID工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:42:29

RK3128通用固件刷机指南:华为EC6108V9A全网通去广告焕新

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:42:11

PMOS缓启动电路全解析:从RC参数计算到Multisim仿真实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:42:10

淘宝商品API与视频资源采集接口接入实战:电商运营与开发必读

做电商运营的人大概都经历过这样的早晨&#xff1a;打开表格&#xff0c;对着几百个商品链接&#xff0c;一个一个复制标题、主图、价格&#xff0c;再跑到另一个平台手动上传&#xff0c;顺便下载商品主图视频、详情页视频&#xff0c;给短视频账号做素材。一上午过去&#xf…

作者头像 李华
网站建设 2026/9/25 4:41:49

Mac 修改 iOS 定位全攻略:AnyGo 原理、实操与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华