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 [email protected]", 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

时间: 2024-11-10 15:05:41

sns社区架构设计案例分享(二)的相关文章

web架构设计经验分享(转)

本人作为一位web工程师,着眼最多之处莫过于 性能与架构,本次幸得参与sd2.0大会,得以与同行广泛交流,于此二方面,有些心得,不敢独享,与众博友分享,本文是这次参会与众同撩交流的心得,有兴趣者可以查看视频 架构设计的几个心得: 一,不要过设计:never over design 这是一个常常被提及的话题,但是只要想想你的架构里有多少功能是根本没有用到,或者最后废弃的,就能明白其重要性了,初涉架构设计,往往倾向于设计大而化一的架构,希望设计出具有无比扩展性,能适应一切需求的增加架构,web开发领

架构设计案例分析-高速公路收费运营管理平台

本文旨在通过对某省高速公路联网收费运营管理平台的架构设计过程进行案例分析,描述架构设计的决策过程. 1.业务背景 某省的高速公路分为近百个路段,不同的路段归属不同的公司建设与运营,造成了车辆在跨越不同路段时,需要停经收费站缴费换卡,降低了高速公路的车辆通行效率. 随着信息化技术的发展,将全省的高速公路联网收费的条件成熟,改造后车辆在高速公路上行驶,在出发地上高速时领卡,到目的地出高速时全程只需缴费一次.随着信息化推进,未来车辆在全国范围内高速公路通行,均只需缴费一次. 为了适应全省联网收费系统改

[架构设计] 架构设计文章分享链接集合 —— 文章来源圣殿骑士博客

昨天在CNB的置顶推荐上看到了@圣殿骑士 的<架构设计分享之权限系统(看图说话)>这篇文章,大概的阅读完之后被@圣殿骑士强大功力惊呆了,记录一下他部分关于架构的文章链接 文章来源:圣殿骑士 架构设计分享之权限系统(看图说话) 架构设计(ASP.NET MVC+Knockout+Web API+SignalR) 31天重构学习笔记重新整理下载

SOA架构设计经验分享—架构、职责、数据一致性

阅读目录: 1.背景介绍 2.SOA的架构层次 2.1.应用服务(原子服务) 2.2.组合服务 2.3.业务服务(编排服务) 3.SOA化的重构 3.1.保留服务空间,为了将来服务的组合 4.运用DDD+GRASP进行分析和设计(防止主观的判断导致错误的假设) 5.SOA分布式下的数据一致性 5.1.分布式事务(基于DTC的分布式事务) 5.2.事务补偿(提供正向或反向的操作来让数据在业务上是一致的) 5.3.异步EDA(基于异步事件流来实现柔性的分布式事务) 6.总结 1.背景介绍 最近一段时

[转]SOA架构设计经验分享&mdash;架构、职责、数据一致性

阅读目录: 1.背景介绍 2.SOA的架构层次 2.1.应用服务(原子服务) 2.2.组合服务 2.3.业务服务(编排服务) 3.SOA化的重构 3.1.保留服务空间,为了将来服务的组合 4.运用DDD+GRASP进行分析和设计(防止主观的判断导致错误的假设) 5.SOA分布式下的数据一致性 5.1.分布式事务(基于DTC的分布式事务) 5.2.事务补偿(提供正向或反向的操作来让数据在业务上是一致的) 5.3.异步EDA(基于异步事件流来实现柔性的分布式事务) 6.总结 1.背景介绍 最近一段时

SOA架构设计案例分析

SOA,它是一个面向服务的体系结构,是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台.操作系统和编程语言,这使得构建在各种这样的系统中的服务可以以一种统一和通用的方式进行交互. SOA的核心主体是服务,所谓服务,从业务角度而言,即是一个可重复的经过标准,服务就像是一堆“元器件”,这些元器件通过封装形成标准服务,服务就像一堆“元器件”,这些元器件通过封装形成标准服务,他们有相同的接口和

Exchange 服务器 跨森林 邮件迁移案例分享 (二)

这一节,我们来讨论一下如何实现忙闲信息的查询. 首先,我们需要在两个系统之间建立关系,也就是所谓的 Organization Relationship.其次,能够查询信息的详细程度,和他们之间AD森林信任的程度也有关系.如果两边AD存在或者允许建立 双向信任,那么我们可以做 PerUserFB 查询较为详细的忙闲信息.如果只允许单向信任 (比如仅资源域信任账户域)或者没有域信任,那么只能做OrgWideFB 查询简单的忙闲信息. 我们需要运行命令 Add-AvailabilityAddressS

电商峰值系统架构设计--转载

1.1 系统架构设计目录 摘要:双11来临之际,<程序员>以“电商峰值系统架构设计”为主题,力邀京东.当当.小米.1号店.海尔商城.唯品会.蘑菇街.麦包包等电商企业,及商派.基调网络等服务公司,分享电商峰值系统架构设计的最佳技术实践. 自2009年11月11日,淘宝商城(现名天猫)拉开网购狂欢节的序幕,各大电商的促销浪潮此起彼伏.此时的电商大战不仅是价格之争,更是技术的较量.如何设计电商峰值系统来更好地满足用户蜂拥而至的访问,如何在海量数据处理中实时发现有效信息并转化为商机,成为众多电商企业密

Linux系统运维与架构设计

一 本章概览 介绍Linux系统运维与架构设计的方方面面 二 Linux基础入门 认识计算机核心硬件和服务器 Linux发展历史.系统组成.应用领域以及发行版 搭建运维环境:VMWareWorkStation.SecureCRT的使用 Linux系统的基本使用 Shell入门以及命令概述 三 Linux系统管理 文件目录管理 用户管理 权限管理 VIM编辑器的使用 文档压缩打包 程序包管理 网络管理 文件系统管理 内存管理 系统管理(监控.环境变量) 安全管理(selinux,iptables)