作者 | Eaton
导语 | 在之前的系列文章中,咱们介绍了 DCache 及其 KV, K-K-Row 和 List 缓存模块的应用,本文将持续介绍如何应用 DCache 中的汇合类型缓存模块 —— Set 和 ZSet 缓存模块。
系列文章
- DCache 分布式存储系统|DCache 部署与利用创立
- DCache 分布式存储系统|Key-Value 缓存模块的创立与应用
- DCache 分布式存储系统|K-K-Row 缓存模块的创立与应用
- DCache 分布式存储系统|List 缓存模块的创立与应用
- DCache 分布式存储系统|Set, ZSet 缓存模块的创立与应用
目录
- Set 与 ZSet 模块简介
- 创立 Set/ZSet 缓存模块
调用 Set/ZSet 缓存模块服务
- Set 模块读写操作
- ZSet 模块读写操作
- 实例
- 其它 Set/ZSet 缓存模块服务接口
- 总结
DCache 是一个基于 TARS 框架开发的分布式 NoSQL 存储系统,反对多种数据结构,包含了 key-value
(键值对),k-k-row
(多键值),list
(列表),set
(汇合),zset
(有序汇合)等,满足多种业务需要。
在后面的文章中,咱们介绍过 key-value
, k-k-row
和 list
两种类型缓存模块的应用形式,本文将持续介绍汇合类型,set
和 zset
缓存模块的应用。
Set 与 ZSet 模块简介
set
即汇合,与 list
相似,以列表模式存储数据。不同的中央在于 set
是会对增加的数据进行排重的。如果你须要存储一个列表数据,又不心愿呈现反复数据时,set
是一个很好的抉择。
zset
为有序汇合,应用场景与 set
相似,但 set
并不是主动有序的。在 zset
中,提供了一个的参数 score 来为数据成员排序。当你须要一个有序的并且不反复的汇合列表,那么能够抉择 zset
数据结构。比方微信朋友圈能够以发表工夫作为 score 来存储,这样获取时就是主动按工夫排好序的。
和 set
相比,zset
关联了一个 double
类型权重参数 score,使得汇合中的元素可能按 score 进行有序排列。
同样地,与其它模块类似,应用 set
和 zset
缓存服务的步骤如下
- 创立 Set/ZSet 缓存模块
- 获取 DCache 接口文件
- 创立缓存服务代理
- 调用 Set/ZSet 缓存模块服务
接下来将持续基于 TestDemo
介绍如何创立和应用 Set/ZSet 缓存模块。
本文应用的示例能够在 GitHub 仓库 DCacheDemo 中查看。
创立 Set/ZSet 缓存模块
后面的文章咱们曾经介绍过缓存模块的创立,各类型缓存模块创立流程是类似的。这里 Set 缓存服务命名为 TestDemoSet
,cache 类型
抉择 Set(MKVCache)
新建 ZSet 缓存服务命名为 TestDemoZSet
,cache 类型
抉择 Zset(MKVCache)
对于步骤 2 和 3,咱们曾经在后面的系列文章中介绍过,本文不再赘述。还不理解的敌人请移步 [Key-Value 缓存模块的创立与应用]()。
调用缓存模块服务
本局部将通过简略示例,介绍 set
和 zset
类型缓存模块局部接口的应用。对于其它接口的信息,参见 Proxy 接口指南。
咱们持续应用 TestDemo
,新增模块名 ModuleTestDemoSet
和 ModuleTestDemoZSet
,值为咱们后面创立的模块名 TestDemoSet
和 TestDemoZSet
,用于之后通过代理调用这两个模块,如下。
// main.cpp
...
static string ModuleTestDemoSet = "TestDemoSet";
static string ModuleTestDemoZSet = "TestDemoZSet";
...
接口调用流程与 TARS 服务接口调用流程统一。如果你还不分明 TARS 服务的调用形式和流程,能够阅读文章 TARS RPC 通信框架|提供多种近程调用形式 理解 TARS 服务的调用形式。
前面的示例中,会应用到三个工具函数,定义如下
// 构建 UpdateValue
DCache::UpdateValue genUpdateValue(DCache::Op op, const string &value)
{
DCache::UpdateValue updateValue;
updateValue.op = op;
updateValue.value = value;
return updateValue;
}
// 打印 map<string, string> 类型数据
void printMapData(const map<string, string> &data)
{map<string, string>::const_iterator it = data.begin();
while (it != data.end())
{
cout << "|" << it->first << ":" << it->second;
++it;
}
cout << endl;
}
// 打印 vector<map> 数据
void printVectorMapData(const vector<map<string, string>> &data)
{for (auto item : data)
{printMapData(item);
}
}
那么接下来,咱们来看看怎么应用 DCache 的 Set/ZSet 缓存模块。
Set 模块读写操作
Set 为汇合缓存模块。这里介绍写接口 addSet
和读接口 getSet
,其它接口用法类似。
向汇合增加值
接口 addSet
用于向特定汇合增加值,定义如下
int addSet(const AddSetReq &req)
其中构造 AddSetReq
及其嵌套构造 AddSetKeyValue
的定义如下
struct AddSetReq
{
1 require string moduleName; // 模块名
2 require AddSetKeyValue value; // 待写入数据
};
struct AddSetKeyValue
{
1 require string mainKey; // 主 key
2 require map<string, UpdateValue> data; // 其余字段数据
3 require int expireTime; // 过期工夫
4 require bool dirty = true; // 是否设置为脏数据
};
应用示例如下
void testAddSet(const string &mainKey, const map<string, string> &data, DCache::ProxyPrx prx)
{
cout << SUBTEST_PREFIX << "addSet";
// 结构申请
DCache::AddSetReq req;
req.moduleName = ModuleTestDemoSet;
req.value.mainKey = mainKey;
req.value.expireTime = time(NULL) + 60 * 60 * 24;
map<string, string>::const_iterator it = data.begin();
while (it != data.end())
{req.value.data[it->first] = genUpdateValue(DCache::SET, it->second);
++it;
}
int ret = prx->addSet(req);
if (ret == DCache::ET_SUCC)
{printMapData(data);
return;
}
cout << "ret:" << ret << endl;
}
获取汇合
接口 getSet
用于获取汇合中的数据,定义如下
int getSet(const GetSetReq &req, BatchEntry &rsp)
其中申请音讯构造 GetSetReq
和返回音讯构造 BatchEntry
定义如下
struct GetSetReq
{
1 require string moduleName; // 模块名
2 require string mainKey; // 主 key
3 require string field; // 须要查问的字段集,多个字段用 ',' 分隔如 "a,b", "*" 示意所有
4 require string idcSpecified = ""; //idc 区域
};
struct BatchEntry
{1 require vector<map<string, string>> entries; // 查问后果汇合};
应用示例如下
void testGetSet(const string &mainKey, DCache::ProxyPrx prx)
{
cout << SUBTEST_PREFIX << "getSet" << endl;
// 结构申请
DCache::GetSetReq req;
req.moduleName = ModuleTestDemoSet;
req.mainKey = mainKey;
req.field = "*";
DCache::BatchEntry rsp;
int ret = prx->getSet(req, rsp);
if (ret == DCache::ET_SUCC)
{
// 打印返回值
printVectorMapData(rsp.entries);
return;
}
cout << "ret:" << ret << endl;
}
ZSet 模块读写操作
ZSet 即有序汇合缓存模块,这里介绍写接口 addZSet
和读接口 getZSetByPos
,其它接口用法相似。
向汇合增加值和权重
接口 addZSet
用于向汇合增加数据值及其权重,定义如下
int addZSet(const AddZSetReq &req)
其中申请音讯构造体 AddZSetReq
及其嵌套构造体 AddSetKeyValue
的定义如下
AddZSetReq
{
1 require string moduleName; // 模块名
2 require AddSetKeyValue value; // 待写入数据
3 require double score; // 待写入数据分值
};
struct AddSetKeyValue
{
1 require string mainKey; // 主 key
2 require map<string, UpdateValue> data; // 其余字段数据
3 require int expireTime; // 数据过期工夫
4 require bool dirty = true; // 是否设置为脏数据
};
应用示例如下
void testAddZSet(const string &mainKey, const map<string, string> &data, const double &score, DCache::ProxyPrx prx)
{
cout << SUBTEST_PREFIX << "addZSet";
// 结构申请
DCache::AddZSetReq req;
req.moduleName = ModuleTestDemoZSet;
req.value.mainKey = mainKey;
req.score = score;
map<string, string>::const_iterator it = data.begin();
while (it != data.end())
{req.value.data[it->first] = genUpdateValue(DCache::SET, it->second);
++it;
}
int ret = prx->addZSet(req);
if (ret == DCache::ET_SUCC)
{printMapData(data);
return;
}
cout << "ret:" << ret << endl;
}
获取汇合
接口 getZSetByPos
用于获取汇合中指定索引区间内的数据,定义如下
int getZSetByPos(const GetZsetByPosReq &req, BatchEntry &rsp)
其中申请音讯构造体 GetZsetByPosReq
的定义如下
struct GetZsetByPosReq
{
1 require string moduleName; // 模块名
2 require string mainKey; // 主 key
3 require string field; // 须要查问的字段集,多个字段用 ',' 分隔如 "a,b", "*" 示意所有
4 require long start; // 开始索引
5 require long end; // 完结索引
6 require bool positiveOrder = true; //true 示意返回的后果按递增排序,false 示意递加
7 require string idcSpecified = ""; //idc 区域
};
struct BatchEntry
{1 require vector<map<string, string>> entries; // 查问后果数据汇合};
应用示例如下
void testGetZSet(const string &mainKey, DCache::ProxyPrx prx)
{
cout << SUBTEST_PREFIX << "getZSet" << endl;
// 结构申请
DCache::GetZsetByPosReq req;
req.moduleName = ModuleTestDemoZSet;
req.mainKey = mainKey;
req.field = "*";
req.start = 0;
req.end = 3;
DCache::BatchEntry rsp;
int ret = prx->getZSetByPos(req, rsp);
if (ret == DCache::ET_SUCC)
{
// 打印返回值
printVectorMapData(rsp.entries);
return;
}
cout << "ret:" << ret << endl;
}
实例
咱们来理论运行一下下面的应用示例。残缺的应用示例能够在 GitHub 仓库 DCacheDemo 中获取。
咱们通过 testSet
和 testZSet
测试上节提到的接口,别离向 Set 和 ZSet 缓存服务中顺次增加值 hello
, hello
, hi
, test
;并且向 ZSet 服务增加的值附带权重,如下
void testSet(DCache::ProxyPrx prx)
{
cout << START << "testSet" << endl;
string mainKey = "testKey";
map<string, string> data1, data2, data3, data4;
data1["VALUE"] = "hello";
data2["VALUE"] = "hello";
data3["VALUE"] = "hi";
data4["VALUE"] = "test";
testAddSet(mainKey, data1, prx);
testAddSet(mainKey, data2, prx);
testAddSet(mainKey, data3, prx);
testAddSet(mainKey, data4, prx);
testGetSet(mainKey, prx);
cout << END << "testSet" << endl;
}
void testZSet(DCache::ProxyPrx prx)
{
cout << START << "testZSet" << endl;
string mainKey = "testKey";
map<string, string> data1, data2, data3, data4;
double score1, score2, score3, score4;
data1["VALUE"] = "hello";
score1 = 0.1;
data2["VALUE"] = "hello";
score2 = 0.1;
data3["VALUE"] = "hi";
score3 = 0.8;
data4["VALUE"] = "test";
score4 = 0.5;
testAddZSet(mainKey, data1, score1, prx);
testAddZSet(mainKey, data2, score2, prx);
testAddZSet(mainKey, data3, score3, prx);
testAddZSet(mainKey, data4, score4, prx);
testGetZSet(mainKey, prx);
cout << END << "testZSet" << endl;
}
接着,在 main
函数中执行
int main(int argc, char *argv[])
{
...
auto prx = comm->stringToProxy<DCache::ProxyPrx>(DCacheTestDemoObj);
// 调用 DCache 缓存服务
testSet(prx);
testZSet(prx);
...
}
执行后果如下
能够看到,只管咱们插入了两次 hello
,然而并没有反复的数据。同时相较于 Set,ZSet 中返回的数据都是依据 score
的权重来排序的。
其它 Set 与 ZSet 缓存模块服务接口
除了后面提到的向汇合增加和获取数据,DCache 中还提供了丰盛的汇合操作接口,如下
/**************** Set ****************/
// 查问汇合数据
int getSet(GetSetReq req, out BatchEntry rsp);
// 向汇合增加数据
int addSet(AddSetReq req);
// 删除指定的一条汇合数据
int delSet(DelSetReq req);
/**************** ZSet ****************/
// 依据指定条件,查问某条记录的 score 值
int getZSetScore(GetZsetScoreReq req, out double score);
// 依据指定条件,查问某条记录在已排序列表的索引地位
int getZSetPos(GetZsetPosReq req, out long pos);
// 查问汇合内指定索引区间 [start, end] 内的数据
int getZSetByPos(GetZsetByPosReq req, out BatchEntry rsp);
// 查问分值区间 [minScore, maxScore] 内的数据
int getZSetByScore(GetZsetByScoreReq req, out BatchEntry rsp);
// 将带有给定分值的数据增加到有序汇合中,如果数据已存在,则重置 score 值
int addZSet(AddZSetReq req);
// 批改有序汇合中某条记录的分值,若数据不存在,则新建一条数据
int incScoreZSet(IncZSetScoreReq req);
// 删除有序汇合中合乎指定条件的某条数据
int delZSet(DelZSetReq req);
// 从有序汇合中删除分值在区间 [minScore, maxScore) 的数据
int delZSetByScore(DelZSetByScoreReq req);
// 依据指定条件更新有序汇合的某条数据
int updateZSet(UpdateZSetReq req);
接口的应用形式与后面介绍的相似,对于接口的具体入参和出参构造能够参考 Proxy 接口指南。
总结
本文简要介绍了 DCache 中的 set
和 zset
缓存模块的原理和应用流程,同时通过具体实例对局部接口的应用进行了具体介绍,帮忙读者了解并可能疾速上手应用 set
和 zset
缓存模块。
TARS 能够在思考到易用性和高性能的同时疾速构建零碎并主动生成代码,帮忙开发人员和企业以微服务的形式疾速构建本人稳固牢靠的分布式应用,从而令开发人员只关注业务逻辑,进步经营效率。多语言、麻利研发、高可用和高效经营的个性使 TARS 成为企业级产品。
TARS 微服务助您数字化转型,欢送拜访:
TARS 官网:https://TarsCloud.org
TARS 源码:https://github.com/TarsCloud
Linux 基金会官网微服务收费课程:https://www.edx.org/course/bu…
获取《TARS 官网培训电子书》:https://wj.qq.com/s2/7849909/…
或扫码获取: