译文-Redis集群入门
官方文章:
本文永久地址:
本文档是Redis集群的简单介绍,没有涉及复杂难懂的分布式概念的赘述,只是提供了从用户角度来如何搭建测试以及使用的方法,若你打算使用并深入了解Redis集群,推荐阅读完本章节后,仔细阅读一章。本教程试图提供最终用户一个简单的关于集群和一致性特征的描述。
请注意,本教程基于Redis 3.0或更高的版本。如果你计划部署集群,那么我们建议你从阅读这个文档开始。
Redis集群基础
Redis集群定义
Redis集群提供一种redis运行方式,能将数据自动分片到多个Redis节点,且Redis集群在分区期间也提供一定的可用性,即在某些节点发生故障或无法通信时,集群也能正常工作,但当大面积节点故障,如大多数master都不可用时,集群就不能使用了。
从实用性角度,Redis集群提供一下功能:
·自动切割数据到多个Redis节点
·小部分节点故障或者不可达时,集群能正常工作
Redis集群TCP端口
Redis集群中每个节点都需侦听两个TCP端口,6379端口用于客户端通信,客户端通信端口加上10000(两个端口总是相差10000),如16379专用于集群总线(Cluster bus),用于节点间二进制协议的节点间通信。各节点使用集群总线故障检测,配置更新,故障转移授权等。客户端不能使用集群总线端口。
请注意,为了让Redis群集正常工作,需要为每个节点配置2个端口(必须):
·客户端端口(默认6379)需要对所有客户端和集群节点开放,因为集群节点需要通过该端口进行密钥迁移(keys migrations)
·集群总线端口(客户端端口+ 10000)对集群所有节点开放即可
集群总线使用不同的二进制协议(不同于客户端与Redis使用的协议)进行节点到节点的数据交换,此协议可以减少带宽和处理时间
Redis集群和Docker
目前,redis集群并不支持地址和端口都被重新映射的NAT环境。
Docker使用一种端口映射技术:运行在docker容器内部的程序可能使用的端口和客户端程序使用的端口不同,这对于同一服务器中同时使用相同端口运行多个容器很有用
为了使Docker与Redis Cluster兼容,您需要使用Docker的主机联网模式。请查看的--net=host选项以获取更多信息。
Redis集群数据分片
Redis集群不使用一致性哈希,而是一种不同的分片形式,其中每个键在概念上都是我们称之为哈希槽的部分。
Redis集群中有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。
集群中每个节点负责哈希槽的的一个子集,如一个有3点歌节点的Redis集群:
·节点A包含从0到5500的哈希槽
·节点B包含从5501到11000的哈希槽
·节点C包含从11001到16383的哈希槽
如此便能方便地添加和删除集群中的节点。如我想添加一个新节点D,我需要将节点A,B,C中的一些哈希槽移动到D;同样,想删除节点A,则可以移动由A服务的散列槽到B和C.当节点A将为空时,我可以将它从群集中彻底删除。
由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态
若多个key都属于一个哈希槽,那么集群能通过单个命令(或者一个完成的事务或Lua脚本执行)同时操作这些key,我们可以使用“哈希标签”(Hash tags)强制让多个key分配到同一哈希槽。“哈希标签”在中有介绍,简单来说就是若key含有大括号”{}”,则只有大括号中的字符串会被哈希,如“this{foo}和another{foo}”这两个key一定会被分配到同一个哈希槽,然后在具有多个间的命令中作为参数一起使用。
Redis集群主从模式
为了保证在部分主master节点挂掉或不能与大多数节点通信时保持可用性,Redis集群使用主从模式,保证每个哈希槽都有1个到N个副本。
上述例子我们有节点A,B,C三个,若节点B故障,集群则不再可用,且会丢失从5501到11000哈希槽。然而若每个master都有一个slave,也就是说A,B,C三个master节点就会分别有A1,B1,C1三个slave节点,即使B节点挂掉,集群也不会受影响,B1复制了B的数据,此时集群将提升B1作为新master继续正常工作。但B和B1同时挂掉,redis集群肯定就不可用了。
Redis集群对一致性的保证
Redis集群不能保证强一致性,在架构中这意味着在某些情况下,可能会丢失向客户端返回“确认写成功”的数据。
丢失写入数据的第一个原因就是redis异步复制数据,也就是说:
·客户端写入数据到master B
·master B向客户端返回“写入成功”
·master B传输数据到slave:B1,B2,B3
由上可知,B在回复客户端之前不等待B1,B2,B3的写入完成确认,因此这会对redis造成严重的延迟损失,就像客户端写入了数据,master B确认写入,但在B将数据复制到任何一个slave前就已经挂掉,那写入将永久丢失,因为被提升为新master的任何slave都没有收到该数据。
这与大多数每秒刷新数据到磁盘的数据库配置类似,也可以通过强制数据库在回复客户端前先刷新数据到磁盘来提高一致性,但这种做法性能很差,这种方式就是让Redis集群在使用同步复制。
到底使用哪种方式,要根据应用场景在性能和一致性之间有一个权衡。
若真的需要,redis集群也能通过“WAIT”指令实现同步复制,这使得写入丢失的可能行大大降低,但并不意味着使用同步复制Redis集群就是强一致性了,如master还未来得及同步数据到任一slave就挂掉,或者被提升为新master没有收到同步过来的数据,都会导致不一致性的发生。使用“WAIT”只能相对的提高一致性。
还有一个值得注意的场景发生在网络故障时,当客户端与少数节点(至少一个master节点)正常通信,但与其他大多数节点网络不通。以A,B,C,A1,B1,C1 三主三从组成的6个节点集群为例,另外一个客户端称之为Z1。网络故障产生网络分区后,可能A,C,A1,B1,C1在一个分区,而B和Z1在另一个分区。此时B仍然能接收写入请求,Z1仍然能写入B。若分区在很短时间能恢复,集群将继续正常运行,但若网络太久未恢复,网络分区持续时间太长,B1会在大多数节点都能通信的分区里面被提升为master,master B在网络恢复后,会成为master B1的新slave,且丢弃Z1发送给B的写操作,然后从B1重新复制数据。
节点间网络通信断开有一个时间限制,若断开时间超过了大多数节点能容忍的长度,那就会有一个新的master被选举出来。
这个时间被称之为节点超时(node timeout),这个时间对集群非常重要,当达到节点超时时间,master被认为已经下线,会有新master被选举出来。同样,在节点超时后,若master仍然不能联系到其他master,它将进入错误状态,并停止接收写入请求。
Redis集群参数配置
先介绍redis.conf中集群的参数配置,后面会有集群部署示例。
·cluster-enabled yes/no #Redis集群开关。Yes表示他是集群中一个节点,no表示他是一个普通单一的redis实例
·cluster-config-file nodes-6379.conf #配置被称之为“集群配置文件”,但此配置文件是集群节点自动维护,不需要人工干预,每次集群配置有所变动,都会自动更新到此文件,以便节点重启时能重新加载配置。该文件列出集群中其他节点的状态,持久化的参数选项等等
·cluster-node-timeout 15000 #单位毫秒,集群节点能够失联的最大时间,超过该时间,该节点就会被认为故障。Master超过此时间不可达,它的slave节点就会选举出新master替代之。另外,任何节点超过此时间没有与大部分master通信将停止接收任何请求
·cluster-slave-validity-factor 10 #用于限定slave与master的失联时长的倍数。若设置0,无论slave与master失联多久,slave都会尝试升级为master(只要slave无法与master通讯,都会尝试故障转移,Cluster有选举机制,有可能会被否决),若设置为正数,则失联的最大时长为(cluster-node-timeout * cluster-slave-validity-factor),超过此时间slave不具备故障转移资格,无法被提升为master。如cluster-node-timeout为5s,cluster-slave-validity-factor为10,,当slave与master失联超过50s后,slave就不再具备成为master的资格。注意,如果此参数不为0,可能出现由于某master节点失联却没有slave能顶上的情况,从而导致集群不能正常工作,此时,只有等到原来的master重新回归到集群,集群才恢复正常。
·cluster-migration-barrier 1 #此参数保证Redis集群中不会出现裸奔的master节点,即保证每个master节点都有slave节点。只有当一个master节点至少拥有给定数量个处于正常工作中的slave节点时,才会分配slave节点给集群中孤立的master节点。这个给定数量就是cluster-migration-barrier。给定数量是1意味着一个slave节点只有在其master节点另外至少还有一个正常工作的slave节点的情况下才会被分配(副本迁移)。那些分配后仍然剩余migration barrier个slave节点的master节点才会触发副本迁移,而不是分配前有migration barrier个slave节点的master节点会触发节点分配!!有关教程,请参阅本文档副本迁移部分
·cluster-require-full-coverage yes #在部分key所在的节点不可用时,如果此参数设置为”yes”(默认值), 则整个集群停止接受操作;如果此参数设置为”no”,则集群依然为可达节点上的key提供读操作(集群是否需要所有的slot都分配给在线节点才能正常访问)
创建和使用Redis集群(主要两步骤:创建实例和连接实例创建集群)
注意:手动部署一个redis集群,最主要是在学习各种操作。
若想尽快启动并运行一个集群,可以直接看下一节“使用create-cluster脚本直接创建Redis群集”
要创建一个redis集群,首要任务就是以集群模式运行几个空Redis实例,必须以集群模式运行,才能使Redis实例具有集群节点功能、支持集群节点指令。
以下是最小redis集群配置文件:
port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes
Redis集群正常运行至少需要3个master,对于第一次测试,建议启动一个由三主三从组成的六节点群集:
1、创建6个以redis实例端口名称的目录:
mkdir -pv /usr/local/cluster-test/700{0..5}
2、在每个端口号目录下创建配置文件redis700{0..5}.conf,内容为上面最小redis集群配置,注意修改端口号
3、启动6个redis集群节点,建议启动6个终端分别启动:
cd /usr/local/cluster-test/7000 ; redis-server /usr/local/cluster-test/7000/redis7000.conf & cd /usr/local/cluster-test/7001 ; redis-server /usr/local/cluster-test/7001/redis7001.conf & cd /usr/local/cluster-test/7002 ; redis-server /usr/local/cluster-test/7002/redis7002.conf & cd /usr/local/cluster-test/7003 ; redis-server /usr/local/cluster-test/7003/redis7003.conf & cd /usr/local/cluster-test/7004 ; redis-server /usr/local/cluster-test/7004/redis7004.conf & cd /usr/local/cluster-test/7005 ; redis-server /usr/local/cluster-test/7005/redis7005.conf &
由于每个实例都是新启动的,nodes.conf还没有自动生成,所以会发出此信息,且生成nodes.conf,都会为自己分配一个新的ID:
10390:M 31 May 14:33:58.078 * No cluster configuration found, I'm f219739744e2fca6f2e6e6c75c9c1f2caa95b05b
作为此节点在整个集群中的唯一标识,生成的ID将一直被各节点使用,节点使用ID来区分其他节点而非IP+PORT,这个ID在节点的整个生命周期内都不会改变,除非节点被移除集群。这个ID我们称之为节点ID(Node ID)。
4、此时6个集群模式的Redis实例已经运行,可以开始创建Redis集群。Ruby脚本“redis-trib”是一个可以让我们非常方便地创建Redis集群的命令行工具,该脚本用于创建新集群,状态检查,或给集群重新分片:
yum install rubygems ruby gem install redis #若提示ruby版本过低,请查看 https://www.cnblogs.com/erbiao/p/9117018.html 。另外,若你的redis版本是4.0.X,强烈建议安装低版本的redis版本库,否则reshard时会出现语法错误。具体请查看:https://www.cnblogs.com/erbiao/p/9138604.html redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 #“--replicas 1”表示每个master节点需要一个slave节点。其他参数就是需要加入这个集群的redis实例的地址。执行后,redis-trib会提供一些建议的配置。
... ...
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered. #表示有16384个哈希槽可用
显示如上信息表示集群创建完成
5、查看nodes.conf信息
cat /usr/local/cluster-test/7001/nodes.conf
06c5baf38ae368bbe8b7fef037d42026ab385590 127.0.0.1:7001@17001 myself,master - 0 1527753131000 2 connected 5461-10922
fdc0c79f9f782b218dad297b48bde32aa0acc31f 127.0.0.1:7005@17005 slave 3fbbebd7bd822dfada7db5bde983534ff2906d4f 0 1527753131000 6 connected
b88654ae05706a771d6f23d8877e890f99dba315 127.0.0.1:7004@17004 slave 06c5baf38ae368bbe8b7fef037d42026ab385590 0 1527753131000 5 connected
41ec008599691424cdf8cdf9f3dc26ab1eef7050 127.0.0.1:7003@17003 slave f219739744e2fca6f2e6e6c75c9c1f2caa95b05b 0 1527753131600 4 connected
f219739744e2fca6f2e6e6c75c9c1f2caa95b05b 127.0.0.1:7000@17000 master - 0 1527753131000 1 connected 0-5460
3fbbebd7bd822dfada7db5bde983534ff2906d4f 127.0.0.1:7002@17002 master - 0 1527753130599 3 connected 10923-16383
vars currentEpoch 6 lastVoteEpoch 0
使用脚本create-cluster创建redis集群
上述的创建方法比较繁琐,“utils/create-cluster/create-cluster”此脚本能简化创建步骤,此脚本会调用其他redis集群命令,所以最好在utils/create-cluster中执行,或者修改脚本文件也是可以的。
脚本“utils/create-cluster/create-cluster”有默认参数,可以根据需要重新定义。
如要启动一个三主三从6节点的Redis集群:
1、命令默认生成6个集群模式的Redis实例,端口30001 ~ 30006
cd utils/create-cluster/ ./create-cluster start
2、连接各个实例,创建Redis集群
cd utils/create-cluster/ ./create-cluster create
[OK] All 16384 slots covered. #表示创建成功
3、默认生成的文件都在当前目录,包括持久化AOF文件,日志文件,RDB数据文件(手动也会生成)
[root@hd4 create-cluster]# ll
总用量 92
-rw-r--r-- 1 root root 2518 5月 31 16:27 30001.log
-rw-r--r-- 1 root root 3683 5月 31 16:27 30002.log
-rw-r--r-- 1 root root 3683 5月 31 16:27 30003.log
-rw-r--r-- 1 root root 4739 5月 31 16:27 30004.log
-rw-r--r-- 1 root root 4739 5月 31 16:27 30005.log
-rw-r--r-- 1 root root 4739 5月 31 16:27 30006.log
-rw-r--r-- 1 root root 0 5月 31 16:27 appendonly-30001.aof
-rw-r--r-- 1 root root 0 5月 31 16:20 appendonly-30002.aof
-rw-r--r-- 1 root root 0 5月 31 16:20 appendonly-30003.aof
-rw-r--r-- 1 root root 0 5月 31 16:27 appendonly-30004.aof
-rw-r--r-- 1 root root 0 5月 31 16:27 appendonly-30005.aof
-rw-r--r-- 1 root root 0 5月 31 16:27 appendonly-30006.aof
-rwxrwxr-x 1 root root 2321 2月 3 00:39 create-cluster
-rw-r--r-- 1 root root 175 5月 31 16:27 dump-30001.rdb
-rw-r--r-- 1 root root 175 5月 31 16:27 dump-30002.rdb
-rw-r--r-- 1 root root 175 5月 31 16:27 dump-30003.rdb
-rw-r--r-- 1 root root 175 5月 31 16:27 dump-30004.rdb
-rw-r--r-- 1 root root 175 5月 31 16:27 dump-30005.rdb
-rw-r--r-- 1 root root 175 5月 31 16:27 dump-30006.rdb
-rw-r--r-- 1 root root 787 5月 31 16:27 nodes-30001.conf
-rw-r--r-- 1 root root 787 5月 31 16:27 nodes-30002.conf
-rw-r--r-- 1 root root 799 5月 31 16:27 nodes-30003.conf
-rw-r--r-- 1 root root 799 5月 31 16:27 nodes-30004.conf
-rw-r--r-- 1 root root 787 5月 31 16:27 nodes-30005.conf
-rw-r--r-- 1 root root 787 5月 31 16:27 nodes-30006.conf
-rw-rw-r-- 1 root root 1308 2月 3 00:39 README
4、其他
(1) 清除集群数据,会删除生成的所有文件,包括aof文件,日志文件,rdb文件,nodes.conf文件
cd utils/create-cluster/ ./create-cluster clean
(2) 停止集群
cd utils/create-cluster/ ./create-cluster stop
(3) create-cluster其他用法:
[root@hd4 create-cluster]# create-cluster
Usage: /usr/bin/create-cluster [start|create|stop|watch|tail|clean]
start -- Launch Redis Cluster instances.
create -- Create a cluster using redis-trib create.
stop -- Stop Redis Cluster instances.
watch -- Show CLUSTER NODES output (first 30 lines) of first node.
tail <id> -- Run tail -f of instance at base port + ID.
clean -- Remove all instances data, logs, configs.
clean-logs -- Remove just instances logs.
(4) 解析create-cluster脚本,我们可以根据需求修改脚本
a. PORT=30000 #集群端口从30000开始,生成“NODES”个实例
b. TIMEOUT=2000 #指定cluster-node-timeout
c. NODES=6 #生成节点数量
d. REPLICAS=1 #表示每个master需要一个slave
玩转Redis集群
现阶段Redis集群的一个问题就是现成的客户端库比较少。现知道的有如下几种:
· Ruby实现,是redis-rb的简单封装,实现了与集群交互的基础功能
· Python实现的redis-rb-cluster接口,支持大部分redis-py功能,正处于活跃开发状态
· 支持Redis集群,处于活跃状态
· java实现,最近添加了对集群的支持
· 提供C#支持(且对大多数.NET语言都适用,VB,F#等)
· 提供对Node.js和io.js的支持,它是支持pipelining和集群的thunk/promise-based客户端
· 集群工具,使用Redisgo库实现的go语言客户端,通过结果聚合实现MGET/MSET
·redis-cli github中的redis不稳定分支,-c选项提供了基础的集群管理功能
以下是redis-cli工具的检测测试:
$ redis-cli -c -p 7000
redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
redis 127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
redis 127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
redis 127.0.0.1:7000> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"
redis-cli实现了集群客户端最基础的功能:将客户端请求正确重定向到正确节点。如上例中,写入和读取时会自动切换到不同节点。逻辑实现比较严谨的客户端可以缓存哈希槽到节点的映射关系,让客户端直接连接到正确的节点,只有集群配置发生改变时才刷新映射关系,如故障转移后,或者增加/删除节点。
使用“redis-rb-cluster”编写示例程序
在说明如何操作Redis集群前,如故障切换或重新分片,先创建一个示例程序了解Redis集群与客户端是怎么交互的。
我们通过一个例子,让部分节点故障或重新分片等,来了解这实际运作中,redis集群是如何处理的。如果这期间没有客户端对集群发起写操作,将不益于我们了解情况
这节通过2个例子来演示redis-rb-cluster的基础用法,下面是第一个例子,源码在redis-rb-cluster目录下的example.rb文件中。
1 require './cluster'
2
3 if ARGV.length != 2
4 startup_nodes = [
5 {:host => "127.0.0.1", :port => 7000},
6 {:host => "127.0.0.1", :port => 7001}
7 ]
8 else
9 startup_nodes = [
10 {:host => ARGV[0], :port => ARGV[1].to_i}
11 ]
12 end
13
14 rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)
15
16 last = false
17
18 while not last
19 begin
20 last = rc.get("__last__")
21 last = 0 if !last
22 rescue => e
23 puts "error #{e.to_s}"
24 sleep 1
25 end
26 end
27
28 ((last.to_i+1)..1000000000).each{|x|
29 begin
30 rc.set("foo#{x}",x)
31 puts rc.get("foo#{x}")
32 rc.set("__last__",x)
33 rescue => e
34 puts "error #{e.to_s}"
35 end
36 sleep 0.1
37 }
程序做的事情非常简单: 它不断地以foo<number>为键,number为值,使用SET命令向数据库设置键值对:
·SET foo0 0
·SET foo1 1
·SET foo2 2
·And so forth…
代码中的每个集群操作都使用一个begin和rescue代码块(block)包裹着,因为我们希望在代码出错时,将错误打印到终端上面, 而不希望应用因为异常(exception)而退出。
代码的第七行是代码中第一个有趣的地方,它创建了一个Redis集群对象, 其中创建对象所使用的参数及其意义如下:第一个参数是记录了启动节点的startup_nodes列表, 列表中包含了两个集群节点的地址。第二个参数指定了对于集群中的各个不同的节点, Redis 集群对象可以获得的最大连接数,第三个参数timeout指定了一个命令在执行多久之后,才会被看作是执行失败。
启动列表中并不需要包含所有集群节点的地址,但这些地址中至少要有一个是有效的:一旦redis-rb-cluster成功连接上集群中的某个节点时,集群节点列表就会被自动更新, 任何真正的的集群客户端都应该这样做。
现在,程序创建的Redis集群对象实例被保存到rc变量里面,我们可以将这个对象当作普通Redis对象实例来使用。
在十一至十九行,我们先尝试阅读计数器中的值,如果计数器不存在的话, 我们才将计数器初始化为0:通过将计数值保存到Redis的计数器里面,我们可以在示例重启之后,仍然继续之前的执行过程,而不必每次重启之后都从foo0开始重新设置键值对。为了让程序在集群下线的情况下, 仍然不断地尝试读取计数器的值, 我们将读取操作包含在了一个 while 循环里面, 一般的应用程序并不需要如此小心。
二十一至三十行是程序的主循环,这个循环负责设置键值对,并在设置出错时打印错误信息。程序在主循环的末尾添加了一个sleep调用,让写操作的执行速度变慢,帮助执行示例的人更容易看清程序的输出。执行example.rb程序将产生以下输出:
ruby ./example.rb
1
2
3
4
5
6
7
8
9
^C (I stopped the program here)
这个程序并不是十分有趣, 稍后我们就会看到一个更有趣的集群应用示例, 不过在此之前, 让我们先使用这个示例来演示集群的重新分片操作。
集群重新分片
现试试对集群进行重新分片操作。执行重新分片的过程中,让example.rb程序处于运行状态,这样你就会看到,重新分片并不会对正在运行的集群程序产生任何影响,你也可以考虑将example.rb中的sleep调用删掉,从而让重新分片操作在近乎真实的写负载下执行;重新分片操作基本上就是将某些节点上的哈希槽移动到另外一些节点上面,和创建集群一样,重新分片也可以使用redis-trib程序来执行
执行命令可开始一次重新分片操作:
redis-trib.rb reshard 127.0.0.1:7000
指定集群中一个节点地址即可,“redis-trib”就会自动找到集群中其他节点。
目前redis-trib只能在管理员的协助下完成重新分片,要让redis-trib自动将哈希槽移动到另一节点目前无法完成。另外,移动哈希槽目前只能以数量进行移动,不能以百分比进行移动,就是说指定redistrib移动50%哈希槽到另一节点是不行的,必须指定数字。
此命令以问题的方式开启一次重新分片(reshard)。
第一个问题,你想重新分片多少个哈希槽:
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: a466e88499423858c5f53de9be640500d9fb3e5b 127.0.0.1:7000
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: b36883be3b39692f71a441a67277ab23dff80afb 127.0.0.1:7004
slots: (0 slots) slave
replicates d1ce7d9db6086c41f13ef0ce3753f82a3bfc420f
M:
相关文章:
-
-
缘由:最近北京市二环内大兴土木,各种挖沟埋线。忽而一纸通令周末断电,故多年不断电的服务器,便令人有了关机后是否还能正常启动的隐忧。其中一台较年迈的服... [阅读全文]
-
创建存储过程 DELIMITER $$ DROP PROCEDURE IF EXISTS ; CREATE PROCEDURE sp_test1(I... [阅读全文]
-
删除重复记录,只保留id最大的一条记录的性能测试 环境 测试表的id为是唯一的,或是自增的主键。 mysql不能直接写循环,只能写在存储过程里。 存... [阅读全文]
-
ShellExecuteEX打开iqy文件导致excel hang的原因分析
1. 问题 当在console中调用API ShellExecuteEx打开"test.iqy"文件时,发现excel会hang... [阅读全文] -
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
下一篇: java实现给图片加铺满的网格式文字水印
推荐阅读
-
Spark新手入门——2.Hadoop集群(伪分布模式)安装
-
Springboot 2.0.x 集成基于Centos7的Redis集群安装及配置
-
JAVAEE——宜立方商城06:Redis安装、数据类型和持久化方案、Redis集群分析与搭建、实现缓存和同步
-
干货--Redis30分钟快速入门
-
laravel项目利用twemproxy部署redis集群的完整步骤
-
Redis(二):Redis入门介绍
-
Linux(Centos7)下redis5集群搭建和使用
-
redis系列--你真的入门了吗?redis4.0入门~
-
redis集群错误解决:/usr/lib/ruby/gems/1.8/gems/redis-3.0.0/lib/redis/client.rb:79:in `call': ERR Slot 15495 is already busy (Redis::CommandError)
-
读书笔记——《redis入门指南(第2版)》第四章 进阶——4.1-5
发表评论