缓存和DB一致性问题

以下是从网络上摘取的一些缓存一致性方案,供参考。

产生原因

主要有两种情况,会导致缓存和 DB 的一致性问题:

  1. 并发的场景下,导致读取老的 DB 数据,更新到缓存中。
  2. 缓存和 DB 的操作,不在一个事务中,可能只有一个操作成功,而另一个操作失败,导致不一致。

当然,有一点我们要注意,缓存和 DB 的一致性,我们指的更多的是最终一致性。我们使用缓存只要是提高读操作的性能,真正在写操作的业务逻辑,还是以数据库为准。例如说,我们可能缓存用户钱包的余额在缓存中,在前端查询钱包余额时,读取缓存,在使用钱包余额时,读取数据库。

更新缓存的设计模式

1.Cache Aside Pattern(旁路缓存)

这是最常用最常用的pattern了。其具体逻辑如下:

  • 失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
  • 命中:应用程序从cache中取数据,取到后返回。
  • 更新:先把数据存到数据库中,成功后,再让缓存失效。

一个是查询操作,一个是更新操作的并发,首先,没有了删除cache数据的操作了,而是先更新了数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据,但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。而不会像文章开头的那个逻辑产生的问题,后续的查询操作一直都在取老的数据。

要么通过2PC或是Paxos协议保证一致性,要么就是拼命的降低并发时脏数据的概率,而Facebook使用了这个降低概率的玩法,因为2PC太慢,而Paxos太复杂。当然,最好还是为缓存设置上过期时间。

2.Read/Write Through Pattern

在上面的Cache Aside套路中,我们的应用代码需要维护两个数据存储,一个是缓存(Cache),一个是数据库(Repository)。所以,应用程序比较啰嗦。而Read/Write Through套路是把更新数据库(Repository)的操作由缓存自己代理了,所以,对于应用层来说,就简单很多了。可以理解为,应用认为后端就是一个单一的存储,而存储自己维护自己的Cache。

Read Through

Read Through 套路就是在查询操作中更新缓存,也就是说,当缓存失效的时候(过期或LRU换出),Cache Aside是由调用方负责把数据加载入缓存,而Read Through则用缓存服务自己来加载,从而对应用方是透明的。

Write Through

Write Through 套路和Read Through相仿,不过是在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库(这是一个同步操作)

下图自来Wikipedia的Cache词条。其中的Memory你可以理解为就是我们例子里的数据库。

3.Write Behind Caching Pattern

Write Behind 又叫 Write Back。write back就是Linux文件系统的Page Cache的算法

Write Back套路,一句说就是,在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库。

这个设计的好处就是让数据的I/O操作飞快无比(因为直接操作内存嘛 ),因为异步,write back还可以合并对同一个数据的多次操作,所以性能的提高是相当可观的。

但是,其带来的问题是,数据不是强一致性的,而且可能会丢失(我们知道Unix/Linux非正常关机会导致数据丢失,就是因为这个事)。在软件设计上,我们基本上不可能做出一个没有缺陷的设计,就像算法设计中的时间换空间,空间换时间一个道理,有时候,强一致性和高性能,高可用和高性性是有冲突的。软件设计从来都是取舍Trade-Off。

另外,Write Back实现逻辑比较复杂,因为他需要track有哪数据是被更新了的,需要刷到持久层上。操作系统的write back会在仅当这个cache需要失效的时候,才会被真正持久起来,比如,内存不够了,或是进程退出了等情况,这又叫lazy write。

在wikipedia上有一张write back的流程图,基本逻辑如下:

参照:左耳朵耗子《缓存更新的套路》 Continue reading “缓存和DB一致性问题”

ocelot brief

The article copyed from https://ocelot.readthedocs.io

Ocelot is aimed at people using .NET running a micro services / service orientated architecture that need a unified point of entry into their system.

In particular I want easy integration with IdentityServer reference and bearer tokens.

Ocelot is a bunch of middlewares in a specific order.

Ocelot manipulates the HttpRequest object into a state specified by its configuration until it reaches a request builder middleware where it creates a HttpRequestMessage object which is used to make a request to a downstream service. The middleware that makes the request is the last thing in the Ocelot pipeline. It does not call the next middleware. There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client. That is basically it with a bunch of other features.

The following are configurations that you use when deploying Ocelot.

Basic Implementation

../_images/OcelotBasic.jpg

With IdentityServer

../_images/OcelotIndentityServer.jpg

Multiple Instances

../_images/OcelotMultipleInstances.jpg

Continue reading “ocelot brief”

代理模式 (Proxy Pattern)-结构型模式第四篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

过去的大半年时间,日子过的忙忙碌碌!今天奉献一篇设计模式系列的新文章,挑选再三,始终觉得Proxy模式是很好的选择,Let’s Go!

定义:

Proxy模式,简言之,它像一个代理人,或者说像一个包装盒,它用来封装、控制背后真实的对象,自己可以独立提供被外界访问的能力,它与背后真实的对象派生于相同的接口,但代理人通常会将对真实对象的调用更加简单化,以便外界更加容易的使用。在客户端看来,自己似乎是直接在操作被代理的真实对象,但事实是,所有的操作都经过代理人的封装、控制、包装,而这些额外的操作,对于客户端来说,似乎是透明的。

应用:

Proxy模式,透明了对原始真实对象的调用,使我们有能力在调用真实对象的前后执行额外的动作,所以我们可以将一些与业务无关的软件基础功能添加在前后的额外动作中。比如Exception Handling, Logging, Caching等。

倘若再结合一些DI/IoC容器、编译器,有能力动态或静态地创建真实对象的代理,便无须手动去编写代理类,此时若配合一些编程语言的语法元数据(比如Java 中的@Attribute,C#中的[Attribute]),便可以在调用真实对象的方法前后执行额外的动作(通常可以称之为Interceptor 或Filter),这便初步实现了AOP编程。

UML:

Proxy UML
UML

Continue reading “代理模式 (Proxy Pattern)-结构型模式第四篇”

export import default of ES(JS)

  • The Asynchronous Module Definition (AMD) format is used in browsers and uses a define function to define modules.
  • The CommonJS (CJS) format is used in Node.js and uses require and module.exports to define dependencies and modules. The npm ecosystem is built upon this format.
  • The ES Module (ESM) format. As of ES6 (ES2015), JavaScript supports a native module format. It uses an export keyword to export a module’s public API and an import keyword to import it.
  • The System.register format was designed to support ES6 modules within ES5.
  • The Universal Module Definition (UMD) format can be used both in the browser and in Node.js. It’s useful when a module needs to be imported by a number of different module loaders.

A background on modules

JavaScript programs started off pretty small — most of its usage in the early days was to do isolated scripting tasks, providing a bit of interactivity to your web pages where needed, so large scripts were generally not needed. Fast forward a few years and we now have complete applications being run in browsers with a lot of JavaScript, as well as JavaScript being used in other contexts (Node.js, for example).

It has therefore made sense in recent years to start thinking about providing mechanisms for splitting JavaScript programs up into separate modules that can be imported when needed. Node.js has had this ability for a long time, and there are a number of JavaScript libraries and frameworks that enable module usage (for example, other CommonJS and AMD-based module systems like RequireJS, and more recently Webpack and Babel).

The good news is that modern browsers have started to support module functionality natively, and this is what this article is all about. This can only be a good thing — browsers can optimize loading of modules, making it more efficient than having to use a library and do all of that extra client-side processing and extra round trips.

Introducing an example

To demonstrate usage of modules, we’ve created a simple set of examples that you can find on GitHub. These examples demonstrate a simple set of modules that create a <canvas> element on a webpage, and then draw (and report information about) different shapes on the canvas.

These are fairly trivial, but have been kept deliberately simple to demonstrate modules clearly.

Note: If you want to download the examples and run them locally, you’ll need to run them through a local web server.

Continue reading “export import default of ES(JS)”

AutoStartDesktop, 一个关系祖国未来的免费软件

[2020/03/02 V1.1.1]

更新:

  1. 支持新功能:应用图标
  2. 支持选择应用,你可以不用手动填写应用路径了
  3. 添加中英文双语支持

详细:

  1. 主界面

支持应用图标的显示

  1. 添加应用Add App
    1. 现在你可以不用手动填写应用路径了,点击按钮Choose App会打开文件选择对话框,然后找到你所需要的应用,应用图标也会一并显示在界面上

Continue reading “AutoStartDesktop, 一个关系祖国未来的免费软件”

适配器模式 (Adapter Pattern)-结构型模式第三篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

祖国母亲生病了,一场突如其来的新冠病毒让这个古老的中华民族正在经历一场全民参与、没有硝烟、却生离死别的战争。每每看到抖音里的那些感人场景虽然不至于声泪俱下,却也是感慨万千、悲愤不已。大家现在都蛰伏在家,等待时机成熟破茧化蝶。相信这个春节在很多人的记忆里永远再也无法抹去,只希望所有人都安好!岁岁平安!

想起抖音里某位才人拍摄的一段视频,视频里这位仁兄使用女用卫生巾夹在普通一次性口罩中混合使用,以提高过滤功效。感叹一句,此乃神人也,有才,不得不佩服!笑归笑,这里不禁想起了设计模式中一个称之谓适配器(Adapter)的模式,所谓Adapter模式简言之,适配器能够使原本两个不兼容的接口能够协同工作。这位才人他没有将卫生巾直接戴在嘴上、卡在脸上(那可不适配),而是通过一个一次性口罩进行了转换、隐藏、适配,然后交由一次性口罩来担负起对外的形象任务,抽象一点的说其实这也算是一个适配器模式的应用:)

好吧,让我们来正式认识一下Adapter模式吧! Continue reading “适配器模式 (Adapter Pattern)-结构型模式第三篇”

SAP Business One

今天我们不说技术也不说设计,我们闲聊一下SAP B1,其实对于我这样一个门外汉来说,B1我是完全不懂的,但最近由于工作上的需要,也出于自己的一些兴趣,硬着头皮看了一些有关的B1的文档,总结出以下几点:

B1 SDK

B1的随行安装包中提供有能够进行二次开发的SDK工具包,提供的API主要分布在两个Namespace,分别为SAPbouiCOM和SAPbobsCOM,它们提供的功能分别是:

  1. SAPbouiCOM用来操作B1 Client UI,也就是我们平常所说的UI API,通过该命名空间下的API接口能够做什么呢?
    1. 粗略看来,在该命名空间下提供了丰富的interop接口,日常工作状态下,人类用鼠标可以操作的,似乎在该命名空间下都有相应的接口,比如打开一个PO,删除一行line,修改某个Comments等
    2. 此外除了可以操纵B1 Client以外,在该命名空间下,还内建了一些B1标准UI Controls,它们可以用来创建与B1 Client风格一致的UI界面
  2. 那么SAPbobsCOM,也即DI API,它又是用来干什么的呢?
    1. 我们知道任何UI的操作,最终是去操作data,无论是direct还是rpc,DI API封装了能够支撑B1 Client运行的所有业务逻辑,实际上,我们通过UI API去操作B1 Client,在其背后便是UI API去调用DI API来执行。
    2. 这便给了我们足够的能力,通过DI API来构建不同的服务或应用程序,比如在B1安装包中所附带的B1 Integration Framework,它对于B1的支持便是利用DI API来实现。

演示

下面通过一个简单的例子,来加深大家对于B1 SDK的理解。它使用了UI API来创建与B1 Client风格一致的用户界面,如果想自由定制,可以阅读我的另一篇文章(B1i Daily Issue Resolver它通过DI API创建了一个与B1 Client有相似功能的登陆界面),似乎如果你有足够的耐心,你能够通过DI API构建另一个B1

  1. 添加一个新的子菜单FormX到MRP菜单中
  2. 点击Foo Button,弹出消息对话框
  3. 将自定义的数据集显示在内建的Grid控件中
  4. 将B1的数据显示在内建的Matrix控件中(注意这里查询出的数据结果是由B1 API来实现,而并非直接通过SQL,即是说API提供了一定的条件筛选和查询能力,自然如果产生无法满足需求的状况,它也提供了备选策略:直接操作SQL的能力)
  5. 点击每行前的箭头,打开相应的Order

组合模式 (Composite Pattern)-结构型模式第二篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

静悄悄中时间飞逝,感叹一句最近TMD真忙真累,好在天生坚强性格阳光,不吹不黑,下面开始讲结构型模式(Structural patterns)的第2篇,Composite Pattern,中文称之为组合或复合模式。

定义:

Composite模式,能够灵活地实现循环、递归、部分-整体类的结构,使外部世界能够以一致的方式处理单体或集合。

解决的问题:

  1. 就像定义中所提及的那样,如何使客户端能够以一致的方式去访问某个单体或者集合,以使结构更加简洁
  2. 如何优雅的表达一个树形结构

怎么去解决(包含叶子Leaf的实现方式):

  1. 通过定义一个接口代表集合与个体所拥有的相同属性与行为,如IComponent
  2. 通过定义一个类Composite,它继承自IComponent,同时通过组合的方式它拥有一个名称为Components的属性,它代表着一个IComponent集合
  3. Composite有能力将一个实现了IComponent接口的对象加入到Components中
  4. 对于Composite的任何请求,都会被重定向到属性Components中的每个个体分别去执行
  5. 通过定义一个类Leaf,它继承自IComponent,代表着不可再分割的个体

举个栗子,在一个树状结构中,树杆、树枝、树叉皆由Composite来表示,而Leaf代表的是末端的每片树叶。

怎么去解决(进一步抽象):

通过分析我们能够发现在上面的解决方式中,如果有能力分辨一个IComponent是树杆还是树叶,便可以将Composite和Leaf合并为一个类型,于是我们为IComponent引入一个新的属性HasChild,并且给它换一个更贴切的名字INode,如果HasChild为True,则代表它是Composite,反之则代表它是Leaf Continue reading “组合模式 (Composite Pattern)-结构型模式第二篇”

Visual Studio Code的设计亮点

本文转自网络,原文网址 https://zhuanlan.zhihu.com/p/35303567

Visual Studio Code(VS Code)近年来获得了爆炸式增长,成为广大开发者工具库中的必备神器。它作为一个开源项目,也吸引了无数第三方开发者和终端用户,成为顶尖开源项目之一。它在功能上做到了够用,体验上做到了好用,更在拥有海量插件的情况下做到了简洁流畅,实属难能可贵。

我是VS Code用户,同时也为它开发插件,插件市场里的众多Java插件基本都是我们团队的作品,所以我在日常工作中观察到不少VS Code在工程方面的亮点,下面就来逐一探讨。

简洁而聚焦的产品定位,贯穿始终

你知道VS Code的开发团队人数不多吗?难以相信吧,大家都觉得VS Code无所不能,如此强大的工具那么几个人怎么做得出来。实际上功能丰富是个美好的错觉,因为大部分针对特定编程语言和技术的功能都是第三方插件提供的,VS Code的核心始终非常精简,这很考验产品团队的拿捏能力:做多了,臃肿,人手也不够;做少了,太弱,没人用。他们团队选择了专注于核心功能的开发,为用户提供简洁流畅的体验,并将该思路贯穿在产品开发的每个环节。在我看来,这就是第一个亮点。 Continue reading “Visual Studio Code的设计亮点”

装饰者模式 (Decorator Pattern)-结构型模式第一篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

本篇是结构型模式(Structural patterns)的第一篇,之所以选择Decorator模式第一个出场,是由于抓揪随机的结果。Decorator模式能够为行为带来灵活的组合,减少子类的数量,希望文章能够给大家带来一点帮助。

定义:

Decorator模式,能够将行为动态地添加到一个类型实例,而不会影响其它的实例。

解决的问题:

  1. 如何在运行时给一个对象添加新的行为
  2. 如何减少子类的数量
    1. 我们知道通过新建一个子类,也能够为类型添加新的行为,但是它存在一个明显的缺陷:随着新行为数目的不断增加,需要增加更多数目的子类,并且行为之间无法组合使用

怎么去解决:

  1. 通过定义一个接口代表原始对象本身,如IComponent
  2. 通过定义一个接口IDecorator,它继承自IComponent,同时通过组合的方式它拥有IComponent
  3. 对于IDecorator的任何请求,都会被重定向到IComponent,并且在重定向前后我们有能力添加新的行为

UML:


Continue reading “装饰者模式 (Decorator Pattern)-结构型模式第一篇”