sns社區架構設計案例分享(二)


源碼下載地址:http://www.jinhusns.com/Products/Download/?type=xcj

五、 架構使用說明 > 緩存 > 使用說明 >


 (一)基礎類庫介紹

 

  1. ICacheService:緩存服務接口,供緩存的存取的調用;

ICacheService方法說明:

方法名稱

成員修飾

說明

備注

Add(多個參數):void +1重載

public static

加入緩存項

 

Set(多個參數):void +1重載

public static

添加或更新緩存

如果無對應緩存項則創建,否則更新

Remove(stringcacheKey):void

public static

移除緩存

 

MarkDeletion(多個參數):void

public static

標識為刪除

 

Clear():void

public static

清空緩存

 

Get(string cacheKey):object

public static

從緩存獲取

 

Get<T>(string cacheKey): T

public static

從緩存獲取

 

GetFromFirstLevel(stringcacheKey): object

public static

從一層緩存獲取

分布式緩存情況下從分布式緩存獲取

GetFromFirstLevel<T>(string cacheKey) : T

public static

從一層緩存獲取

分布式緩存情況下從分布式緩存獲取

1)         提供Tunynet.Caching.DefaultCacheService作為ICacheService的默認實現;

  1. CacheSettingAttribute:用於在實體標注緩存相關的設置;

CacheSettingAttribute屬性說明:

屬性名稱

成員修飾

說明

備注

EnableCache: bool

public

是否啟用緩存

僅允許在構造器設置屬性

ExpirationPolicy :

EntityCacheExpirationPolicies

public

實體緩存(實體正文緩存)過期策略

 

PropertyNameOfBody : string

public

實體正文緩存對應的屬性名稱(如果不需單獨存儲實體正文緩存,則不要設置該屬性)

 

PropertyNamesOfArea : string

public

緩存分區的屬性名稱(可以設置多個,用逗號分隔)

 

  1. RealTimeCacheHelper:主要功能是遞增緩存版本號(一般無需開發人員干涉)和輔助獲取緩存CacheKey;

RealTimeCacheHelper方法說明:

方法名稱

成員修飾

說明

備注

GetGlobalVersion():long

public

列表緩存全局version

 

GetEntityVersion(objectprimaryKey): long

public

獲取Entity的緩存版本

 

GetAreaVersion(多個參數): long

public

獲取列表緩存區域version

 

GetCacheKeyOfEntity(object primaryKey): string

public

獲取實體的cacheKey

 

GetListCacheKeyPrefix(多個參數): string

public

獲取列表緩存CacheKey的前綴(例如:abe3ds2sa90:8:)

 

IncreaseEntityCacheVersion(object entityID): void

public

遞增實體緩存(僅更新實體時需要遞增)

 

IncreaseListCacheVersion(IEntity entity): void

public

遞增列表緩存version(僅增加、刪除實體時需要遞增)

 

IncreaseAreaVersion(多個參數): void +2重載

public

遞增列表緩存區域version

 

 

(二)緩存時間過期類型

1.          預設以下幾種過期時間(在Tunynet.Caching.CachingExpirationTypes定義);

緩存期限類型

描述

備注

Invariable

永久不變的

 

Stable

穩定數據

例如: Resources.xml、Area、Application

RelativelyStable

相對穩定

例如: 權限配置、審核配置、敏感詞、表情、站點類別、資訊版塊、資訊版塊集合

UsualSingleObject

常用的單個對象

例如: 用戶、群組、類別、標簽、博客Section、相冊Section、論壇版塊、活動

UsualObjectCollection

常用的對象集合

例如: 用戶的朋友

SingleObject

單個對象

例如: 博文、帖子

ObjectCollection

對象集合

例如: 用於分頁的私信數據

 

  1. 目前實際使用的都是絕對過期時間(例如:5分鍾過期);
  2. 盡量不要在使用緩存時直接設置具體過期時間;
  3. 可以配置過期時間因子(cacheExpirationFactor),用於統一調配預設過期時間類型對應的具體時間;

 (三)緩存配置說明

緩存服務通過DI容器進行注冊,例如:

//注冊緩存

containerBuilder.Register(c => new DefaultCacheService(new RuntimeMemoryCache(), 1.0F)).As<ICacheService>().SingleInstance();

 

  1. 可以使用不同的構造函數實例化DefaultCacheService以支持分布式緩存,或者設置緩存過期時間因子(會整體影響預置的緩存過期時間);
  2. 為性能考慮,必須注冊成單例;

3.          如果自行實現ICacheService,同樣在此注冊替換掉DefaultCacheService;

(四)緩存開發注意事項

  1. 在分布式緩存情況下,如需更新緩存必須顯式調用更新操作(ICacheService.Set()),因為web服務器與緩存服務器可能位於不同的服務器,而非分布式緩存情況下可以利用引用類型的特征直接更新從緩存獲取的數據,而無需顯示調用緩存更新操作(ICacheService.Set());
  2. 所有可能需要分布式緩存的數據必須支持序列化/反序列化:

1)         需緩存的實體必須標注[Serializable];

2)         特殊數據類型必須驗證是否支持序列化/反序列化,例如從Dictionary<T key,T value>派生的類型無法直接序列化;

3.         不要在使用Repository.GetTopEntities(inttopNumber, CachingExpirationTypescachingExpirationTypes, Func<string>getCacheKey, Func<PetaPoco.Sql>generateSql)設置CacheKey時與topNumber相關,因為不管topNumber值是多少,實際都會最多獲取SecondaryMaxRecords條數據並緩存起來。即不同的topNumber可以共用一份緩存,用於提升緩存使用率,進而提升性能。

(五)實體的緩存標注

使用CacheSettingAttribute在實體上進行標注,使大部分緩存工作得以在Repository自動處理。

  1. 可以通過ExpirationPolicy設置實體的緩存策略(目前主要與緩存失效時間有關);
  2. 可以通過PropertyNameOfBody設置實體正文緩存對應的屬性名稱;
  3. 可以通過PropertyNamesOfArea設置列表分區緩存相關的屬性,可以設置多個分區(即多個屬性,用英文逗號分隔);

 

[CacheSetting(true, ExpirationPolicy = EntityCacheExpirationPolicies.Normal, PropertyNamesOfArea = "UserId,CategoryId", PropertyNameOfBody = "Body")]

[Serializable]

publicclassDiscussQuestion : IEntity

{

……

}

(六)使用實體正文緩存

當實體正文可能很大時,為了提升運行效率並減少分布式緩存時的網絡流量將實體正文緩存單獨存儲,並且不在實體緩存中存儲該部分內容。使用實體正文緩存,需要遵循以下步驟:

  1. 使用CacheSettingAttribute的PropertyNameOfBody在實體中進行標注,可以參見上一節的代碼示例;
  2. 在自行派生的Repository編寫實體正文的獲取方法,例如:

/// <summary>

///獲取DiscussQuestion內容

/// </summary>

public string GetBody(long questionId)

{

string cacheKey = RealTimeCacheHelper.GetCacheKeyOfEntityBody(questionId);

string body = cacheService.Get<string>(cacheKey);

if (body == null)

{

DiscussQuestion question = Database.SingleOrDefault<DiscussQuestion>(questionId);

body = question != null ? question.Body : string.Empty;

cacheService.Add(cacheKey, body, CachingExpirationType.SingleObject);

}

return body;

}

(七)列表緩存使用

列表緩存的主要工作是CacheKey的獲取。

  1. 1.          使用無版本的列表緩存

StringBuilder cacheKey = new StringBuilder(CacheSetting.GetListCacheKeyPrefix(CacheVersionTypes.None));

cacheKey.AppendFormat("Ranking:sb-{0}", (int)sortBy);

return cacheKey.ToString();

 

  1. 2.          使用有版本的列表緩存

1)         可以通過RealTimeCacheHelper的以下方法獲取列表緩存CacheKey前綴,直接使用第一個方法是最簡便的方式;

public string GetListCacheKeyPrefix(CacheVersionType cacheVersionType, string areaCachePropertyName, object areaCachePropertyValue);

 

2)         在使用查詢條件類並且需要即時性緩存時,可以使查詢條件類實現IListCacheSetting,例如:

///<summary>

/// DiscussQuestion查詢條件封裝

///</summary>

public class DiscussQuestionQuery : IListCacheSetting

{

public DiscussQuestionQuery(CacheVersionTypes cacheVersionType)

{

this.cacheVersionType = cacheVersionType;

}

……

#region IListCacheSetting 成員

Private CacheVersionTypes cacheVersionType = CacheVersionTypes.None;

///<summary>

///列表緩存版本設置

///</summary>

CacheVersionTypesIListCacheSetting.CacheVersionType

{

get { return cacheVersionType; }

}

 

private string areaCachePropertyName = null;

///<summary>

///緩存分區字段名稱

///</summary>

public string AreaCachePropertyName

{

get { return areaCachePropertyName; }

set { areaCachePropertyName = value; }

}

 

private object areaCachePropertyValue = null;

///<summary>

///緩存分區字段值

///</summary>

public object AreaCachePropertyValue

{

get { return areaCachePropertyValue; }

set { areaCachePropertyValue = value; }

}

#endregion

}

 

3)         可以自行定義的Repository使用以下代碼獲取CacheKey:

StringBuilder cacheKey = new StringBuilder(RealTimeCacheHelper.GetListCacheKeyPrefix(query));

if (query.UserId.HasValue)

cacheKey.AppendFormat("UserID-{0}:", query.UserId.Value);

 

cacheKey.AppendFormat("sb-{0}:", (int)query.SortBy);

return cacheKey.ToString();

 

4)         在Service中使用以下代碼構造DiscussQuestionQuery:

/// <summary>

/// 獲取我創建的問題

/// </summary>

public PagingDataSet<DiscussQuestion> GetMyQuestions(long userId, int pageIndex)

{

DiscussQuestionQuery query = new DiscussQuestionQuery(CacheVersionType.AreaVersion);

query.AreaCachePropertyName = "UserId";

query.AreaCachePropertyValue = userId;

query.UserId = userId;

 

return questionRepository.GetQuestions(query, QuestionPageSize, pageIndex);

}

(八)如何使用實體以外的屬性作為分區

 

使用實體以外的屬性作為分區時,無法依靠Repository自動維護對應分區緩存版本,需要通過代碼自行控制。

 

  1. 自行編寫代碼遞增分區緩存版本,例如:

 

/// <summary>

 

/// 把用戶加入到一組角色中

 

/// </summary>

 

public void AddUserToRoles(int userID, List<int> roleIDs)

 

{

 

    var sql_delete = PetaPoco.Sql.Builder.Append("DELETE FROM tn_UsersInRoles where UserID=@0", userID);

 

 

 

    List<PetaPoco.Sql> sql_inserts = new List<PetaPoco.Sql>();

 

    foreach (var roleID in roleIDs)

 

    {

 

        var sql_insert = PetaPoco.Sql.Builder.Append("INSERT INTO tn_UsersInRoles (UserID,RoleID) VALUES (@0,@1)", userID, roleID);

 

        sql_inserts.Add(sql_insert);

 

    }

 

 

 

    using (var scope = Database.GetTransaction())

 

    {

 

        Database.Execute(sql_delete);

 

        Database.Execute(sql_inserts);

 

        scope.Complete();

 

    }

 

 

 

    //遞增緩存分區版本號(UserID)

 

    RealTimeCacheHelper.IncreaseAreaVersion("UserID", userID);

 

}

 

 

 

  1. 借助RealTimeCacheHelper.GetListCacheKeyPrefix()獲得CacheKey,例如:

 

/// <summary>

 

///獲取用戶的角色

 

/// </summary>

 

public IEnumerable<Role> GetRolesOfUser(int userID)

 

{

 

string cacheKey = RealTimeCacheHelper.GetListCacheKeyPrefix(CacheVersionTypes.AreaVersion, "UserID", userID);

 

IEnumerable<Role> roles = CacheService.Get<IEnumerable<Role>>(cacheKey);

 

 if (roles == null)

 

{

 

var sql = PetaPoco.Sql.Builder

 

.Select("RoleID")

 

.From("tn_UsersInRoles")

 

.Where("UserID = @0", userID);

 

 

 

IList<object> roleIDs = Database.FetchFirstColumn(sql);

 

RoleRepository roleRepository = new RoleRepository();

 

roles = roleRepository.PopulateEntitiesByPrimaryKeys(roleIDs);

 

CacheService.Add(cacheKey, roles, CachingExpirationTypes.UsualObjectCollection);

 

}

 

return roles;

}

http://www.jinhusns.com/Products/Curriculum/?type=xcj


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com