新聞中心
使用Redis點(diǎn)贊遇到的問題及解決方案

創(chuàng)新互聯(lián)建站企業(yè)建站,10多年網(wǎng)站建設(shè)經(jīng)驗(yàn),專注于網(wǎng)站建設(shè)技術(shù),精于網(wǎng)頁設(shè)計(jì),有多年建站和網(wǎng)站代運(yùn)營(yíng)經(jīng)驗(yàn),設(shè)計(jì)師為客戶打造網(wǎng)絡(luò)企業(yè)風(fēng)格,提供周到的建站售前咨詢和貼心的售后服務(wù)。對(duì)于網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)中不同領(lǐng)域進(jìn)行深入了解和探索,創(chuàng)新互聯(lián)在網(wǎng)站建設(shè)中充分了解客戶行業(yè)的需求,以靈動(dòng)的思維在網(wǎng)頁中充分展現(xiàn),通過對(duì)客戶行業(yè)精準(zhǔn)市場(chǎng)調(diào)研,為客戶提供的解決方案。
在實(shí)際的項(xiàng)目中,點(diǎn)贊功能通常都需要使用到Redis來緩存數(shù)據(jù),加快點(diǎn)贊處理速度。但若不注意實(shí)現(xiàn)細(xì)節(jié),會(huì)出現(xiàn)一些問題,本文將介紹點(diǎn)贊功能的實(shí)現(xiàn)及解決方案。
一、點(diǎn)贊功能的實(shí)現(xiàn)
1.1 使用Redis的SET實(shí)現(xiàn)點(diǎn)贊
使用Redis的set類型可以實(shí)現(xiàn)點(diǎn)贊功能。每個(gè)用戶的點(diǎn)贊信息可以用Redis中的一個(gè)set表示,set名稱為like:obj_type:obj_id,其中obj_type為點(diǎn)贊對(duì)象類型,obj_id為點(diǎn)贊對(duì)象ID,表示該對(duì)象有哪些用戶進(jìn)行了點(diǎn)贊操作。例如,用戶id為100的用戶對(duì)類型為post、ID為23的文章進(jìn)行了點(diǎn)贊,則可以使用以下命令將這個(gè)用戶id添加到點(diǎn)贊set中:
SADD like:post:23 100
1.2 點(diǎn)贊數(shù)量的統(tǒng)計(jì)
使用Redis的set實(shí)現(xiàn)點(diǎn)贊時(shí),可以使用以下命令統(tǒng)計(jì)點(diǎn)贊數(shù)量:
SCARD like:post:23
1.3 取消點(diǎn)贊
取消點(diǎn)贊操作可以使用以下命令:
SREM like:post:23 100
1.4 判斷是否點(diǎn)贊過
判斷某個(gè)用戶是否已經(jīng)點(diǎn)贊可以使用以下命令:
SISMEMBER like:post:23 100
二、遇到的問題
2.1 并發(fā)問題
如果有多個(gè)用戶同時(shí)對(duì)同一對(duì)象進(jìn)行點(diǎn)贊操作,可能會(huì)出現(xiàn)并發(fā)問題。假設(shè)有兩個(gè)用戶同時(shí)對(duì)同一文章進(jìn)行點(diǎn)贊操作,Redis的set類型可以支持多個(gè)用戶同時(shí)添加到同一個(gè)集合中,但在統(tǒng)計(jì)點(diǎn)贊數(shù)時(shí),可能會(huì)出現(xiàn)計(jì)數(shù)偏差的情況。
2.2 內(nèi)存占用問題
使用Redis的set類型實(shí)現(xiàn)點(diǎn)贊時(shí),每個(gè)點(diǎn)贊操作都需要在內(nèi)存中記錄一條點(diǎn)贊信息,如果點(diǎn)贊操作過于頻繁,會(huì)導(dǎo)致內(nèi)存占用過高。
三、解決方案
3.1 并發(fā)問題的解決方案
使用Redis的事務(wù)機(jī)制可以保證點(diǎn)贊操作的原子性,防止多個(gè)用戶同時(shí)對(duì)同一對(duì)象進(jìn)行點(diǎn)贊操作。以下是一個(gè)Java代碼示例:
public class RedisLikeService {
private final String redisKey;
public RedisLikeService(String objType, long objId) {
this.redisKey = "like:" + objType + ":" + objId;
}
public Long like(long userId) {
Jedis jedis = RedisUtil.getJedis();
try {
while (true) {
jedis.watch(redisKey);
Set members = jedis.smembers(redisKey);
if (members.contns(String.valueOf(userId))) {
jedis.unwatch();
return jedis.scard(redisKey);
}
Transaction tx = jedis.multi();
tx.sadd(redisKey, String.valueOf(userId));
Response response = tx.scard(redisKey);
List resultList = tx.exec();
if (resultList != null && !resultList.isEmpty()) {
return response.get();
}
}
} finally {
RedisUtil.closeJedis(jedis);
}
}
public Long unlike(long userId) {
Jedis jedis = RedisUtil.getJedis();
try {
Transaction tx = jedis.multi();
tx.srem(redisKey, String.valueOf(userId));
Response response = tx.scard(redisKey);
List resultList = tx.exec();
return resultList != null && !resultList.isEmpty() ? response.get() : null;
} finally {
RedisUtil.closeJedis(jedis);
}
}
}
在上面的代碼中,使用Redis的watch和multi機(jī)制實(shí)現(xiàn)了原子性的點(diǎn)贊和取消點(diǎn)贊操作。如果當(dāng)前的點(diǎn)贊set中已經(jīng)含有該用戶,則直接返回點(diǎn)贊數(shù)量。否則,使用multi命令將點(diǎn)贊操作添加到事務(wù)中,執(zhí)行exec命令提交事務(wù)。如果因?yàn)椴l(fā)問題導(dǎo)致exec執(zhí)行失敗,則重新嘗試執(zhí)行。
3.2 內(nèi)存占用問題的解決方案
對(duì)于內(nèi)存占用問題,可以在Redis的set類型記錄點(diǎn)贊信息的基礎(chǔ)上,再使用zset類型記錄點(diǎn)贊更新時(shí)間,通過定期刪除點(diǎn)贊時(shí)間較早的set,以減少內(nèi)存占用。以下是一個(gè)Java代碼示例:
public class RedisLikeService {
private final String redisKey;
private final String timeKey;
private final int maxCount;
public RedisLikeService(String objType, long objId, int maxCount) {
this.redisKey = "like:" + objType + ":" + objId;
this.timeKey = "time:" + objType + ":" + objId;
this.maxCount = maxCount;
}
public Long like(long userId) {
Jedis jedis = RedisUtil.getJedis();
try {
jedis.sadd(redisKey, String.valueOf(userId));
jedis.zadd(timeKey, System.currentTimeMillis(), String.valueOf(userId));
return jedis.scard(redisKey);
} finally {
RedisUtil.closeJedis(jedis);
}
}
public Long unlike(long userId) {
Jedis jedis = RedisUtil.getJedis();
try {
jedis.srem(redisKey, String.valueOf(userId));
jedis.zrem(timeKey, String.valueOf(userId));
return jedis.scard(redisKey);
} finally {
RedisUtil.closeJedis(jedis);
}
}
public Long getCount() {
Jedis jedis = RedisUtil.getJedis();
try {
return jedis.scard(redisKey);
} finally {
RedisUtil.closeJedis(jedis);
}
}
public void clean() {
Jedis jedis = RedisUtil.getJedis();
try {
Long size = jedis.zcard(timeKey);
if (size > maxCount) {
Set oldLikes = jedis.zrange(timeKey, 0, size - maxCount - 1);
jedis.del(oldLikes.toArray(new String[oldLikes.size()]));
jedis.zremrangeByRank(timeKey, 0, size - maxCount - 1);
}
} finally {
RedisUtil.closeJedis(jedis);
}
}
}
在上面的代碼中,使用zset類型記錄點(diǎn)贊信息的更新時(shí)間,并使用定時(shí)任務(wù)在一定時(shí)間間隔內(nèi)清理時(shí)間較早的點(diǎn)贊信息,以減少內(nèi)存占用??梢酝ㄟ^clean方法手動(dòng)清理緩存,也可以使用定時(shí)任務(wù)自動(dòng)定時(shí)清理。
成都創(chuàng)新互聯(lián)科技有限公司,是一家專注于互聯(lián)網(wǎng)、IDC服務(wù)、應(yīng)用軟件開發(fā)、網(wǎng)站建設(shè)推廣的公司,為客戶提供互聯(lián)網(wǎng)基礎(chǔ)服務(wù)!
創(chuàng)新互聯(lián)(www.cdcxhl.com)提供簡(jiǎn)單好用,價(jià)格厚道的香港/美國(guó)云服務(wù)器和獨(dú)立服務(wù)器。創(chuàng)新互聯(lián)成都老牌IDC服務(wù)商,專注四川成都IDC機(jī)房服務(wù)器托管/機(jī)柜租用。為您精選優(yōu)質(zhì)idc數(shù)據(jù)中心機(jī)房租用、服務(wù)器托管、機(jī)柜租賃、大帶寬租用,可選線路電信、移動(dòng)、聯(lián)通等。
網(wǎng)站欄目:使用Redis點(diǎn)贊遇到的問題及解決方案(redis點(diǎn)贊出現(xiàn)的問題)
文章網(wǎng)址:http://fisionsoft.com.cn/article/cogpjoi.html


咨詢
建站咨詢
