项目演化系列--开启分布式(分离数据层)

前言html

  本来上一篇是打算写分离数据层的,可是在思考的过程中发现分离数据层的时候,有一些操做是要依赖分布式锁的,所以先写了分布式锁。web

  对于有些项目的数据层提供的是业务接口的(返回业务所需的数据),那么当数据层压力逐渐增大的时候,如须要使用缓存的时候,就须要开发人员去修改相应的数据接口使其使用缓存,缓存和各类数据查询接口交错在一块儿,整个数据层的代码变得很是混乱,连重构都没法进行,只能推倒重作。因此不少的文章中,在讲解数据层的时候,都是使用统一的数据接口,如:Find、Add、Save等,那么当须要缓存的时候,就能够在Find中直接扩展使其支持缓存,甚至能够引入缓存配置管理,对于不一样的表之间进行可调度的缓存周期管理,使开发人员不须要知道缓存的存在,他们仍是使用原先的Find,可是速度却更快了,又或者冷热数据管理、搜索引擎等,这即是大神们在通过多年开发总结下来的经验。数据库

  将数据层从项目中分离出来成为一个独立的项目,并将其发布于独立的服务器,相对于单机系统而言,有以下几个优势:缓存

  一、便于整合各方资源服务器

  二、下降成本网络

  三、每一个层的性能更加优秀且可伸缩性强,在不断增长的负荷下,能够便利的增长节点数量。mvc

  四、某些次服务层出现错误的时候,不会致使项目的总体瘫痪。app

  五、不一样层次可用不一样语言实现框架

  有优势就有缺点,最大的缺点就是较单机系统而言,分布式系统更加复杂,不只系统自己结构会变得复杂,不一样组件间的网络会引入影响因素,调试困难等等。socket

  虽然有很多的缺点,可是不去实践是不会发现另外一番天地的,不去挑战看看永远都只是局限在单机系统上,也不用惧怕会遇到哪些问题,毕竟只有发现问题以后,才能想办法解决,这是从书上没法学习到的,那么咱们就开始今天的文章吧。

基础CRUD

  数据层是提供于数据库进行操做的中间件,最基础的功能就是CRUD,单机系统当中,调用CRUD接口的时候,要么经过拼接SQL要么经过ORM直接链接数据库,而因为如今是分布式的,所以原先的调用方式就须要经过通讯协议来实现了,假设原先的接口为:

public class DbResult
{
    public bool Error { get; set; }

    public object Data { get; set; }
}

public interface IDb
{
    DbResult Find(Dictionary<string, object> query);

    DbResult Add(object entity);

    DbResult Save(object entity);

    DbResult Remove(object entity);
}

  数据层那端的Find是以Query Object模式实现的,具体的格式能够查看此文章--《Query Object--查询对象模式(上)》、《Query Object--查询对象模式(下)》。

  这里的数据层项目,若是使用原先抽取的mvcHandler方式来实现,那么IService的派生类就须要使用HttpWebRequest来实现了,大体的实现思路就是将相应的方法最后转换成调用数据服务,Find实现代码以下:

public DbResult Find(Dictionary<string, object> query)
{
    var url = string.Format("{0}/{1}/{2}", ConnectionUri, this.table, "find");
    var req = (HttpWebRequest)HttpWebRequest.Create(url);
    req.Method = "Post";
    req.Accept = "text/plain, */*; q=0.01";
    req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
    req.Timeout = 1000 * 30;
    req.KeepAlive = true;
    try
    {
        byte[] bytes = Encoding.UTF8.GetBytes(
            JsonConvert.SerializeObject(query));
        req.ContentLength = bytes.Length;
        using (var reqStream = req.GetRequestStream())
        {
            Stream requestStream = req.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);
        }

        var res = new DbResult();
        using (var resp = (HttpWebResponse)req.GetResponse())
        {
            using (var respStream = resp.GetResponseStream())
            {
                using (var reader = new StreamReader(respStream, Encoding.UTF8))
                {
                    string respContent = reader.ReadToEnd();
                    return JsonConvert.DeserializeObject(respContent);
                }
            }
        }
    }
    catch
    {
        return new DbResult { Error = true };
    }
}

事务

  有了基础的CRUD之后,接下来就要实现事务了,若是参考单机系统来实现事务的话,那么开启事务之后,若是业务层出现问题致使主机重启或宕机,那么数据层的事务将会没法关闭,从而引起问题。

  所以须要使用其余的方式来实现,观察事务能够得出从事务开启到提交是一个总体,只有事务提交的时候才须要有状态来断定事务的执行状况,而事务开启时并能够不须要有执行结果的断定,所以能够将事务当作一个队列,而中间的每个CUD操做能够当作是它的元素,而每个操做须要知道对应的是哪一个表、执行哪一个操做以及相应的表数据便可,代码实现以下:

public class TransactionAction
{
    public string Table { get; set; }

    public string Name { get; set; }

    public object Data { get; set; }
}

//IDb
public interface IDb
{
    //其余省略

    void BeginTx();

    DbResult CommitTx();
}

//IDb实现
private List actions;

public void BeginTx()
{
    this.actions = new List();
}

public DbResult CommitTx()
{
    //http访问数据层并设置actions为null
}

public DbResult Add(object entity)
{
    if (this.actions != null)
    {
        this.actions.Add(new TransactionAction
        {
            Name = "add",
            Table = this.table,
            Data = entity
        });
    }
    else
    {
        //单个增长
    }
}

结束语

  到这里数据层的分离基本上就完成了,若是想要更高效的数据获取,能够将访问方式修改为socket,之因此不直接使用WPF或者webService是由于这都是基于C#来开发的,并且若是直接使用现成的框架来用的话,能学到的东西就很少了。

  就到这里了,若是有什么问题或者错误的话,请给我留言,谢谢。

相关文章
相关标签/搜索