作者 | 胡巍巍
责编 | 仲培艺
2019程序员转型学什么?
https://edu.csdn.net/topic/ai30?utm_source=csdn_bw
成立才三年半的熊猫直播被曝破产!
据界面新闻报道,熊猫直播创始团队成员兼首席运营官 COO 张菊元,于公司内部工作群中发出长消息称:
“在 2017 年 5 月获得由兴业证券兴证资本领投的 B 轮 10 亿人民币融资之后,至今没有外部资金注入,在资金缺口无法解决情况下做出了遣散员工的决定。”
他还表示,“熊猫 TV 被迫选择了这样的结束,选择结束并不是对员工与团队的否定,而是大势之下,一个无奈而又最理智的选择。”
如果你一直关注王思聪,想必对熊猫直播(以下简称“熊猫”)也不会太陌生。
熊猫刚成立时,王思聪入股 4 成高调入局,在校长光环的加持下,林俊杰、鹿晗、陈赫、林更新、Angelababy 等都来站台!
内测期间更是有不少淘宝店高价倒卖邀请码,光内测时用户注册数量就达几十万,火爆程度可见一斑。
真是“彩云易散琉璃脆”,谁能想昨日风光已成往事。
网传熊猫 CTO 张菊元的助理,在公司内部群说,已经给员工安排好了内推。
数位熊猫员工,也忍不住在微博和朋友圈“悼念”熊猫,有位员工发微博称:“错过了你最辉煌时期,却见证了你的低谷。”
另有业内消息称,熊猫副总裁庄明浩在一周前已经离职。
前天晚上的熊猫官微称,“来说说话吧。”下面的留言很多都是在告别熊猫。
此外,3 月 6 日的熊猫直播间里,主播们都在跟粉丝告别,也有主播让粉丝加自己的 QQ 和微信,疑似要把粉丝带走。
还有多名主播称熊猫欠薪,另据脉脉爆料,员工拿到的赔偿并不是 N+1,都是统一价:赔偿半个月工资。
没有波折,就不叫人生如戏,现在的结局有多抓马,当初的辉煌就有多耀眼。
王思聪入股:昙花一现的辉煌
曾经,熊猫和斗鱼虎牙都是坐前排的直播平台。
2017 年 5 月,熊猫 B 轮融资 10 亿元,估值 59 亿元,这对于成立不到两年的公司来说,真的很厉害了。
据艾瑞数据,到了当年年底,熊猫的用户数量,已经达到业内第三。
但是后来,其东一榔头西一棒子的运营,让其逐渐失去核心竞争力。
聚光灯下的熊猫 TV
而作为写下熊猫 TV 第二行代码的 Coder,沈冠璞无疑见证了熊猫 TV 成立初期的风风雨雨,也伴随其踩过诸多直播技术的坑。他曾在 2016 年的《程序员》杂志中,详细讲解了熊猫 TV 的技术架构演进。
从熊猫架构 0.1 开始的“新手上路”
第一阶段的最大目标就是按预期时间上线——10 人左右的 Web 团队,从接需求到上线,只用了不到三个月。其间面临的最大难题是两个月就内测!
团队为此采用了复用模块+主业务全新开发的策略:
-
复用模块得益于团队的前 360 技术背景,根据直播秀场类项目上的技术积累,利用 PHP 框架 Pylon、发版工具 Rigger,在老战友的帮助下,重新搭建了一套 QBus 消息组件,长连接系统,改进的 Redis、MongoDB 和 MySQL集群,视频云服务,敏感词服务,搜索服务,这个项目才有了强大的基础支撑,才有可能在两个月时间就上线。
-
虽然是个新项目,熊猫并未做一个一篮子应用,把所有接口放在一个项目,而是按功能模块分好项目,每人负责一个,对主站 panda.tv 项目提供内网 API,部署方便互不影响,开发效率也比较高。
高可用原则下的架构改进思路
直播面临的核心问题是网站稳定可用、视频流畅清晰、弹幕互动效果稳定。直播技术看似简单,一家视频云可以帮助创业公司一两个月就构建出一个直播 App,但其中的运营难点、技术难点、流量带宽问题都需要谨慎处理。
熊猫 TV 因快速上线和爆炸式增长,从严重依赖外部服务,到自主自建核心业务,也走了不少弯路。其架构改进思路是应对峰值流量高度集中的直播需求:
-
不能依赖单个 CDN。可自建,可用第三方,但中国网络环境太复杂,必须高度重视容灾。海外推拉流也需要十分关注。
-
弹幕消息一定要做策略优化。广播蝴蝶效应明显,峰值可能将机房整体带宽打满。区分弹幕优先级,做好降级预案。
-
提高金钱敏感度。直播网站由于有很清晰的变现模式,要严防褥羊毛,严防色情内容,火速响应监管,支付礼物交互一定是高可用、严监控。
-
N个大主播 = 半个网站峰值。必须考虑某些特殊主播的火爆人气,做好视频弹幕房间信息上的峰值应对。
除此之外,自助式运营处理、反作弊、长连优化、推荐系统等,也是直播需要关注的方向。
定位不准、运营不给力
后来的熊猫看到综艺赚钱,就开始做综艺直播《Hello!女神》《小葱秀》,但这两款节目却是叫好不叫座。
此外,熊猫的运营能力也比较挫。
其主播阿超在接受娱乐资本论的采访时表示,“熊猫的主播是所有直播平台里最舒服的。我们平时就播 4、5 个小时,人气掉了也不管。等到月底疯狂补时长,然后拿全额薪水,甚至直播间标题就叫‘划水补时长’。在其他平台如果你表现不好,CEO 甚至会直接点你的名。”
这样的运营,导致翻遍主播排行前一百名,都看不到熊猫的直播。
图源自极光大数据
管理是一方面,钱不行,自然也就黄得快。
资金链不结实
论项目烧钱度,游戏直播行业绝对算一个。
2018 年 3 月,斗鱼虎牙相继收到腾讯投资:两家分别收到 6.3 亿美元和 4.6 亿美元。
腾讯的这一动作,无异于成为熊猫继续往前冲的拦路虎。
而那时的熊猫,被爆料正在以 30 亿元价格寻求被收购,然而“卖身”一事最终无疾而终。
拉钱拉不到,卖身卖不动。
那不就剩下“慢慢死去”了吗?
此外,还有传闻称,360 入股熊猫后,其派出的高管内斗,也是熊猫“死亡”的因素之一。
360 入股加速“灭亡”?
网上流传的截图称,“熊猫之所以到今天这样,百分之 99 是管理层无能”、“360 那边来的只会内部斗争”等。
工商信息显示,熊猫的工商股东,曾变更为天津奇睿天成股权投资中心(有限合伙),而这家公司的企业法人,正是奇虎三六零软件(北京)有限公司和北京远图科技有限公司。
如此来看,高管内斗并非毫无踪迹可寻。
据娱乐资本论消息,“在熊猫直播发展的过程中,遇到过好几次发展上的大问题,领导层都要开会讨论、研究、发现问题,但实际上,每次都是一群人(携妻带子)找个度假村。”
以上是内因,植物的生长还受天气影响呢,企业亦是如此。
直播游戏行业大环境不佳
任何事情都有红利期,比如罗永浩做锤子,虽然很努力,还是赶不上其他大厂。
熊猫也同样,其入局时,行业已有战旗斗鱼虎牙等小前辈。
后续斗鱼虎牙融资、虎牙后来又上市,更是加剧了直播行业的快速洗牌。
洗着洗着,熊猫就“溶解”在了滚滚浪潮中。
你说,该用什么来作为熊猫直播的墓志铭呢?
参考文章:
-
每日经济新闻《王思聪也救不了熊猫直播?员工发文告别,主播找粉丝加群防失联》
-
娱乐资本论《熊猫直播破产背后的秘密:内斗、佛系、不作为》
-
新京报《熊猫直播濒临破产?知情人士:已凉 有平台挖人》
-
挑战高薪,进军人工智能领域:
https://edu.csdn.net/topic/ai30?utm_source=csdn_bw
【End】
热 文 推 荐
☞ 杨超越吧编程大赛;拼多多刷单?苹果新员工一半没本科学历 | 极客头条
☞ 5年Go语言经验薪资翻倍! 这份全球职业报告中, 区块链开发者薪资排第三, 前两名你绝对想不到!(含完整版下载资源)
print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"
点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。
喜欢就点击“好看”吧!


写在文章开头
在实际的软件开发项目中,我们经常会遇到需要对数据进行一系列连续操作的情况,而且这些操作必须作为一个整体要么全部成功,要么全部失败,以保证数据的一致性。比如在电商系统中,下单、扣库存、记录订单信息等操作需要作为一个不可分割的整体来执行。Redis作为一款常用的数据库,其事务功能就为解决这类问题提供了有力的支持。那么,如何在项目中正确、高效地使用Redis事务呢?
Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。
同时也非常欢迎你star我的开源项目mini-redis:github.com/shark-ctrl/…
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。
redis事务的基本概念
redis事务的基本概念
redis
的事务是一个单独隔离的操作,它会将一系列指令按需排队并顺序执行,期间不会被其他客户端的指令插队,所以redis
事务是保证组合命令的原子性。
redis的事务指令有3个关键字,分别是:
multi
:开启事务exec
:执行事务discard
:取消事务
通过multi
,当前客户端就会开启事务,后续用户键入的都指令都会保证到队列中暂不执行,当用户键入exec
后,这些指令都会按顺序执行。 需要注意的是,若开启multi
后输入若干指令,客户端输入discard
,则之前的指令通通取消执行。
redis事务基础操作示例
如上所示,事务本质就是开启、入队、提交,接下来我们就来简单演示一下,打开客户端首先开启事务:
makefile 代码解读复制代码# 开启事务
127.0.0.1:6379> MULTI
OK
然后将需要执行的操作提交:
bash 代码解读复制代码# 将两个指令组队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
完成后,我们就可以通过exec
指令提交并执行:
makefile 代码解读复制代码# 执行两个指令
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
最后查看执行验证一下结果:
makefile 代码解读复制代码# 查看执行结果
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
详解redis事务中的原子性
组队时错误
redis
事务中的错误分别以下两种:
- 组队时错误
- 执行命令时错误
我们先来说说组队时错误的指令,上文我们已经说过,redis
事务开启后提交的指令都会存到队列中,这也就意味着在指令提交阶段redis
是可以感知到语法上的错误,所以在组队时错误,redis
一旦感知到错误,这些指令都不会执行:
makefile 代码解读复制代码# 开启事务
127.0.0.1:6379> MULTI
OK
# 指令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k33
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
# 执行指令
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
# 指令并没有被执行
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
这一点我们也可以从源码的角度分析,redis
会为每一个redis
客户端分配一个结构体维护其内部信息,这其中flag
字段就代表着客户端各种状态标识,这其中低3位就表示客户端是否开启事务标识,如果1就代表开启,反之代表未开启:
对此我们也给出这段结构体定义,即位于redis.h
的redisClient
结构体定义:
arduino 代码解读复制代码typedef struct redisClient {
//......
int argc;
robj **argv;
//......
//标识是否被设置为slave、或者监控slave的、或者键入过multi开启事务
int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
//......
}
当redis
开启事务需要multi
指令,客户端键入该指令之后,redis
首先就会通过按位与判断这个二进制为是否被标识为1,若没有则直接位运算为1开启事务。后续如果再次键入multi
则会直接抛出嵌套事务异常告知客户端不可重复调用multi
指令:
对应的我们给出multi
指令的源码实现multiCommand
,逻辑和笔者说明的一致解:
scss 代码解读复制代码void multiCommand(redisClient *c) {
//REDIS_MULTI值为1<<3 如果按位与发现当前客户端已经被标识为开启事务,则直接跑错事务不可嵌套的异常
if (c->flags & REDIS_MULTI) {
addReplyError(c,"MULTI calls can not be nested");
return;
}
//REDIS_MULTI值为1<<3 通过 | 符号将低3位标识为1,意为开启事务
c->flags |= REDIS_MULTI;
addReply(c,shared.ok);
}
开启事务后,用户的指令提交处理都会走到公用处理函数processCommand
,一旦感知到某条指令处理异常,redis
就会将客户端标识flag
标记为脏事务REDIS_DIRTY_EXEC
。 基于该标记,执行exec提交事务时就可以感知指令是否在组队时存在异常,如果存在异常则直接取消所有指令的执行保证组队时事务的原子性:
对应我们给出所有指令提交前的通用逻辑函数processCommand
,可以看到如果服务端感知到指令的指令参数不一致等异常就会调用flagTransaction
将事务标记为脏:
rust 代码解读复制代码int processCommand(redisClient *c) {
//.......
c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);
if (!c->cmd) {
//......
} else if ((c->cmd->arity > 0 && c->cmd->arity != c->argc) ||
(c->argc < -c->cmd->arity)) {//检查参数数和命令表配置是否一致
//如果发现不一致则将客户端flags标识标记上REDIS_DIRTY_EXEC标识当前事务是脏事务
flagTransaction(c);
addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
c->cmd->name);
return REDIS_OK;
}
//......
}
void flagTransaction(redisClient *c) {
//如果开启事务则将flags标记上REDIS_DIRTY_EXEC,标识当前事务已脏
if (c->flags & REDIS_MULTI)
c->flags |= REDIS_DIRTY_EXEC;
}
有了上述的基础,我们执行的exec就会通过判断flags
查看是否被标记为REDIS_DIRTY_EXEC
,如果是则调用discardTransaction
也就是discard
清除队列中的指令不执行:
scss 代码解读复制代码void execCommand(redisClient *c) {
//......
//如果发现标识标记为REDIS_DIRTY_EXEC,则调用 discardTransaction释放掉事务队列的指令不执行
if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) {
addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr :
shared.nullmultibulk);
discardTransaction(c);
goto handle_monitor;
}
//......
}
来小结一下,redis组队时异常回滚的底层实现:
multi
开启事务- 提交指令,如果发现指令异常则将当前客户端事务标记为脏事务
- 调用
exec
时判断客户端标识,如果包含脏标记则清除事务队列中的指令不执行
执行时错误
有了上述基础我们就很好理解执行时错误了,执行时错误比较特殊,他在按序处理所有指令,即时遇到错误就按正常流程处理继续执行下去,如下示例所示,可以看到我们将k1对应的value是字符串类型,第二条指令执行错误后,k2还是正常设置进去了:
makefile 代码解读复制代码# 开启事务
127.0.0.1:6379> MULTI
OK
# 设置字符串k1 v1
127.0.0.1:6379(TX)> set k1 v1
QUEUED
# 设置v1进行自增,此时redis无法感知到这个异常
127.0.0.1:6379(TX)> INCR k1
QUEUED
# 正常键值对设置
127.0.0.1:6379(TX)> set k2 v2
QUEUED
# 提交执行,1、3指令执行成功
127.0.0.1:6379(TX)> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
# 即使指令2失败,指令3还是正常提交
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379>
详解redis事务中的乐观锁
为什么redis需要事务
通过redis事务解决需要高性能且需要保证原子性的符合指令操作,最经典的就是秒杀场景,如下图,假设一个秒杀活动中有3个用户,同时通过get指令发现库存剩下1,全部通过原子扣减指令进行扣减,导致超卖:
常见的解决方案有悲观锁和乐观锁,悲观锁(Pessimistic Lock)的原理是认为自己操作的数据很可能会被他人修改,所以对临界资源操作都持有悲观的态度,每次进行操作前都会对数据上锁保证互斥,常见的关系型数据库MySQL
的行锁、表锁等都是基于这种锁机制:
我们再来说说乐观锁(Optimistic Lock)
,该锁的总是乐观的认为自己操作的数据不会被他人修改,进行修改操作时不会针对临界资源上锁,而是修改的时候判断一下当前去数据版本号和修改的数据是否一致,通过比对版本号是否一致判断是否被人修改,只要版本号一致当前线程修改操作就会生效,redis
中的watch
关键字和jdk
下的JUC
包下的原子类就是采用这种工作机制:
redis事务乐观锁使用示例
这里我们就演示一下redis
乐观锁的实现,原理比较简单,通过watch
指令监听事务操作要操作的一个或者多个key
值,当用户提交修改事务时,watch
指令没有检测到key发生变化,则提交成功。
为方便演示,我们假设需要用事务操作名称为key的数据,我们首先初始化一下这个键值对:
vbnet 代码解读复制代码# 设置key值
127.0.0.1:6379> set key 10
OK
然后开始watch
指令监听这个key
:
makefile 代码解读复制代码# 监听key
127.0.0.1:6379> WATCH key
OK
此时我们就可以开启事务提交要执行的操作:
makefile 代码解读复制代码# 开启事务
127.0.0.1:6379> MULTI
OK
同理我们在这时候起一个客户端2同样执行watch
和multi
操作:
makefile 代码解读复制代码# 监听key
127.0.0.1:6379> WATCH key
OK
# 开启事务
127.0.0.1:6379> MULTI
OK
此时我们回到客户端1执行修改操作,可以看到因为watch
到key
没有发生改变,修改操作成功:
makefile 代码解读复制代码# 指令加入队列
127.0.0.1:6379(TX)> INCR key
QUEUED
# 执行指令,可以看到执行成功,修改了一条数据,值被更新为11
127.0.0.1:6379(TX)> EXEC
1) (integer) 11
此时我们回到客户端2提交指令并提交,可以看到提交结果失败了,返回nil:
makefile 代码解读复制代码127.0.0.1:6379(TX)> INCR key
QUEUED
127.0.0.1:6379(TX)> exec
(nil)
这里我们也从源码的角度解释一下redis
对于watch
乐观锁的实现,如上操作,当我们客户端键入watch
指令时监控key
时,redis
就会将当前客户端的信息挂到一个watched_keys
的字典中,用key
作为键,客户端信息作为value
追加到这个key
的链表中。
我们客户端1提交时,因为之前没有客户端进行修改,所以成功提交修改操作,并将watched_keys
中监听key
的所有客户端的flags
标识为已被CAS
修改即枚举变量REDIS_DIRTY_CAS
数值为1<<5
。
然后客户端2进行修改操作时,看到自己的flags被修改为REDIS_DIRTY_CAS
就知道了当前key被人修改了,所以乐观修改操作失败:
对应源码如下,当客户端1执行exec
时发现监听的key没有被人修改,执行incr操作之后,就会走到下面这个方法touchWatchedKey
将watched_keys
中监听key的客户端标识标记为REDIS_DIRTY_CAS
,告知当前这个key
已被我们修改:
scss 代码解读复制代码void touchWatchedKey(redisDb *db, robj *key) {
//......
//从watched_keys找到监听当前key的所有客户端
clients = dictFetchValue(db->watched_keys, key);
//......
//遍历订阅这个key的所有客户端
listRewind(clients,&li);
while((ln = listNext(&li))) {
redisClient *c = listNodeValue(ln);
//标识为REDIS_DIRTY_CAS
c->flags |= REDIS_DIRTY_CAS;
}
}
所以当客户端2的执行exec
时,调用来到了execCommand
,当他发现自己的标识即flags字段被客户端1标记为REDIS_DIRTY_CAS
,就知道当前key
被人修改了,于是就执行discard
取消执行当前指令:
scss 代码解读复制代码
void execCommand(redisClient *c) {
//......
//如果发现标识标记为REDIS_DIRTY_EXEC或REDIS_DIRTY_CAS(当前watch的key被人修改),则调用 discardTransaction释放掉事务队列的指令不执行
if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) {
addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr :
//执行discard操作清除当前客户端提交的执行,且不执行 shared.nullmultibulk);
discardTransaction(c);
goto handle_monitor;
}
//......
redis事务中的一些常见问题
为什么redis不支持事务回滚
redis
实际上是支持事务回滚的,只不过这种回滚是仅仅支持组队时的异常,只有组队时感知到指令错误,redis
服务端才会标记异常,后续执行exec
时就会将提交队列的指令清除且不执行,由此原子性。
如何理解redis的事务与ACID
- 原子性: redis设计者认为他们是支持原子性的,因为原子性的概念是,
所有指令要么全部执行,要么全部不执行
,只要客户端提交的指令能够在组队阶段被感知,它就能做到指令操作的原子性。 - 一致性: 针对数据的一致性,我们从3种情况进行讨论:
markdown 代码解读复制代码
1. 组队阶段:如果在事务组队阶段感知到异常,redis会主动丢弃事务中的指令且不执行,可以保证一致性。
2. 执行时异常:在事务执行阶段出现异常,redis还是会顺序执行后续的指令,一致性就会被破坏
3. 事务提交前redis宕机:如果开启了rdb或者aof持久化机制,可以在服务重启时重新加载提交到队列中的数据,保证一致性。
- 隔离性: 隔离性要求避免所有的客户端事务操作并发交叉执行时导致数据不一致问题,如上乐观锁的说明,我们可以通过watch关键字监听key的变化保证事务提交时感知到其他客户端的修改,如果发生修改就不提交事务,由此避免隔离性遭到破坏。
- 持久性: 持久性的定义为事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 ),考虑到性能问题,redis无论rdb还是aof都是异步持久化,所以并不能保证持久性。
Redis事务的其他实现方式吗
基于lua脚本可以保证redis指令一次性执按顺序执行完成,并且不会被其他客户端打断,但是这种方式却无法实现事务回滚,所以我们可以需要在lua脚本的实现上进行响应的处理。
Redis事务三特性是什么?
- 单独的隔离操作:事务中的命令都会序列化并且按序执行,执行过程中不会被其他客户端的指令打断。
- 没有隔离级别的概念: 事务提交前所有指令都不会被执行。
- 组队阶段原子性:上文示例已经演示过,执行时出错某段指令,事务过程中的指令仍然会生效。
如何使用 Redis 事务?
Redis 可以通过 MULTI
,EXEC
,DISCARD
和 WATCH
等命令来实现事务(transaction)功能。
如何解决 Redis 事务的缺陷
从上文我们看出基于redis事务进行秒杀方面的需求时会出现库存遗留问题,这就是redis事务乐观锁机制的缺陷。 为了保证所有事务都能一次性的执行,我们可以使用lua脚本更快(lua脚本可以轻易调用C语言库函数以及被C语言直接调用)、更有效(基于lua脚本可以保证指令一次性被执行不会被其他线程打断),但是这种方案不支持回滚。
小结
本文从redis事务和底层源码两个角度深入分析了其工作机制和使用注意事项,希望对你有帮助。 我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。
同时也非常欢迎你star我的开源项目mini-redis:github.com/shark-ctrl/…
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。
参考
Redis进阶 - 事务:Redis事务详解:www.pdai.tech/md/db/nosql…
Redis常见面试题总结(下):javaguide.cn/database/re…
Redis的watch机制详解:blog.csdn.net/jkzyx123/ar…
取二进制数中特定第几的位置:blog.csdn.net/LOUTINI/art…
Redis实现库存扣减操作:blog.csdn.net/weixin_4066…
悲观锁和乐观锁的区别:blog.csdn.net/weixin_5065…
acid:baike.baidu.com/item/ACID/1…
《Redis核心技术与实战》
本文使用 markdown.com.cn 排版
评论记录:
回复评论: