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

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

5、 架構使用說明 > 緩存 > 使用說明 > sql


 (一)基礎類庫介紹緩存

 

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

ICacheService方法說明:服務器

方法名稱網絡

成員修飾架構

說明分佈式

備註函數

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

public staticui

加入緩存項

 

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

相關文章
相關標籤/搜索