存档

‘阅读’ 分类的存档

Daniel-Journey Weekly Dose -2012/5/20

2012年5月20日 admin 没有评论

JAVA

在非web应用的系统中怎样手动去销毁Spring容器

Java并发编程实践:CompletionService和Future的结合

Java程序执行超时——Future接口介绍

Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便可以从Future那儿取出结果。就相当于下了一张订货单,一段时间后可以拿着提订单来提货,这期间可以干别的任何事情。其中Future 接口就是订货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。

ThreadPoolExecutor几点使用建议

异步并行加载使用说明(asyncload)

SACALABILITY

Seven Secrets Every Architect Should Know

Exploit Processor Affinity For High And Predictable Performance

The idea is by assigning a thread to a particular CPU that when a thread is rescheduled to run on the same CPU, it can take advantage of the "accumulated  state in the processor, including instructions and data in the cache."  With multi-core chips the norm now, you may want to decide for yourself how to assign work to cores and not let the OS do it for you. The results are surprisingly strong.

The Right Read Optimization is Actually Write Optimization

微信架构的启示

Building High Performance Applications

Scalability lessons from Google, YouTube, Twitter, Amazon, eBay, Facebook and Instagram

Here are some common ideas I’ve noticed across all seven companies …

  1. Keep it simple – complexity will come naturally over time.
  2. Automate everything, including failure recovery.
  3. Iterate your solutions – be prepared to throw away a working component when you want to scale it up to the next level.
  4. Use the right tool for the job, but don’t be afraid to roll your own solution.
  5. Use caching, where appropriate.
  6. Know when to favor data consistency over data availability, and vice versa.

Goog

  • Reliable storage
  • Infrastructure as a competitive advantage
  • Build applications on top of a platform
  • Automation and recovery
  • Create a Darwinian infrastructure
  • Don’t ignore the Academy
  • Consider data compression

YouTube

  • Keep it simple

UML

UML 状态图

ARCHITECTURE

一些软件设计的原则

Unix Pipes 管道原稿

程序应该只关注一个目标,并尽可能把它做好。让程序能够互相协同工作。应该让程序处理文本数据流,因为这是一个通用的接口。

用Unix的设计思想来应对多变的需求

当你真正了解了Unix的设计思想后,你会觉得今天的很多东西都是对Unix设计思想的一种传承或是变种。这种东西就是:

1)解耦,解耦,解耦。尽量地让你的模块不要在实现上耦合,而是耦合某个规范,某个标准。

2)KISS,KISS,KISS。要做到高度解耦,你的模块就一定要很简单,当然不是说简单到只有几行代码,而是简单到只干一件事,并把这件事干到极致。然后通过某个标准拼装起来。

3)拼装,拼装,拼装。我想不起来是谁说的了,这句话是这样的,当我想用一个模块的时候,我直接调用就好了,没有必要像C或Java一样,还要编译。是的,拼装需要一个框架,需要一种标准协议,然后让所有的系统都耦合在这种规范上,各自独立运行,就像一个机器上的各个部件一样,当我觉得这个部件不爽,换了就是了。(例如,当我们在尝试不同的算法的时候)

All Java Architects: Read This

Adding layers is BAD.

Interfaces have a special purpose, you don’t need them for everything.

Beware of one size fit’s all solutions

系统设计黄金法则:简单之美

“The Rise of ‘Worse is Better”对比了以LISP系统为代表的麻省理工方法和以Unix/C为代表的新泽西(贝尔实验室)方法。Gabriel发现相比于LISP/CLOS系统完美的设计,Unix/C只是一味追求实现简单,但事实却证明Unix/C像终极计算机病毒那样快速蔓延,奠定了今天计算机系统的基础。

让我们来看看这两种不同的设计哲学。

1)MIT Approach

  • 简单性:设计必须简单,这既是对实现的要求,也是对接口的要求。接口的简单要比实现的简单更加重要。
  • 正确性:设计在任何值得注意的方面都要保证正确。不正确是绝对不允许的。
  • 一致性:设计必须保持一致兼容。设计可以允许轻微少量的不简单和不完整,来避免不一致。一致性和正确性同等重要。
  • 完整性:设计必须覆盖到实际应用的各种重要场景。所有可预料到的情况都必须覆盖到。简单性不能过度的损害完整性。

2)New Jersey Approach

  • 简单性:设计必须简单,这既是对实现的要求,也是对接口的要求。实现的简单要比接口的简单更加重要。简单是设计中需要第一重视的因素。
  • 正确性:设计在任何值得注意的方面都要求正确。为了简单性,正确性可以做轻微的让步。
  • 一致性:设计不能过度不兼容一致。为了简单,一致性可以在某些方面做些牺牲,但与其允许设计中的这些处理不常见情况的部分去增加实现的复杂性和不一致性,不如丢掉它们。
  • 完整性:设计必须覆盖到实际应用的各种重要场景。所有可预料到的情况都应该覆盖到。为了保证其它几种特征的品质,完整性可以作出牺牲。事实上,一旦简单性受到危害,完整性必须做出牺牲。一致性可以为实现的完整性作出牺牲;最不重要的是接口上的一致性。

LINUX

《篡权的ss》-linux命令五分钟系列之三十一

ss是Socket Statistics的缩写。顾名思义,ss命令可以用来获取socket统计信息,它可以显示和netstat类似的内容。但ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息,而且比netstat更快速更高效。

场景一:我想查看当前服务器的网络连接统计

ss –s

【场景二:我想查看所有打开的网络端口】

ss –l

【场景三:我想查看这台服务器上所有的socket连接】

#ss –a

如果只想查看TCP sockets,那么使用-ta选项;
如果只想查看UDP sockets,那么使用-ua选项;
如果只想查看RAW sockets,那么使用-wa选项;
如果只想查看UNIX sockets,那么使用-xa选项。

JAVA

Java Thread CPU Analysis on Windows

Java程序执行超时——Future接口介绍

在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。 Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实 现,可以来进行异步计算。Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便可以从Future那儿取出结果。就相当于下了一张订货单,一段时间后可以拿着提订单来提货,这期间可以干别的任何事情。其中Future 接口就是订货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。

Future接口的方法介绍如下:

  • boolean cancel (boolean mayInterruptIfRunning) 取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束
  • boolean isCancelled () 任务是否已经取消,任务正常完成前将其取消,则返回 true
  • boolean isDone () 任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true
  • V get () throws InterruptedException, ExecutionException  等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException
  • V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计 算超时,将抛出TimeoutException

Daniel-Journey Weekly Dose -2012/5/12

2012年5月12日 admin 没有评论

Java

Java中的缓冲区(直接缓冲区、非直接缓冲区等)

java.nio类 Buffer

一种用于特定的基本类型数据的容器。

缓冲区是特定的基本类型元素的线性、有限序列。缓冲区的基本属性除其内容外还包括容量、限制和位置:

缓冲区的容量 是它所包含的元素的数量。缓冲区的容量永远不会为负并且从不会更改。

缓冲区的限制 是不应读取或写入的第一个元素的索引。缓冲区的限制永远不会为负,并且永远不会大于其容量。

缓冲区的位置 是下一个要读取或写入的元素的索引。缓冲区的位置永远不会为负,并且永远不会大于其限制。

每个非 boolean 基本类型都存在此类的一个子类。

ByteBuffer

 

NIO ByteBuffer 使用方法

缓冲区分配和包装

缓冲区分片

缓冲区份片和数据共享:缓冲区片对于促进抽象非常有帮助。可以编写自己的函数处理整个缓冲区,而且如果想要将这个过程应用于子缓冲区上,只需取主缓冲区的一个片,并将它传递给您的函数。这比编写自己的函数来取额外的参数以指定要对缓冲区的哪一部分进行操作更容易。

只读缓冲区:只读缓冲区非常简单 — 可以读取它们,但是不能向它们写入。可以通过调用缓冲区的 asReadOnlyBuffer() 方法,将任何常规缓冲区转换为只读缓冲区,这个方法返回一个与原缓冲区完全相同的缓冲区(并与其共享数据),只不过它是只读的。只读缓冲区对于保护数据很有用。在将缓冲区传递给某个对象的方法时,您无法知道这个方法是否会修改缓冲区中的数据。创建一个只读的缓冲区可以 保证 该缓冲区不会被修改。不能将只读的缓冲区转换为可写的缓冲区。

内存映射文件 I/O:内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。内存映射文件 I/O 是通过使文件中的数据神奇般地出现为内存数组的内容来完成的。这其初听起来似乎不过就是将整个文件读到内存中,但是事实上并不是这样。一般来说,只有文件中实际读取或者写入的部分才会送入(或者 映射 )到内存中。内存映射并不真的神奇或者多么不寻常。现代操作系统一般根据需要将文件的部分映射为内存的部分,从而实现文件系统。Java 内存映射机制不过是在底层操作系统中可以采用这种机制时,提供了对该机制的访问。尽管创建内存映射文件相当简单,但是向它写入可能是危险的。仅只是改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。

将文件映射到内存:

分散和聚集

异步 I/O

Java的移位运算符

左移位运算符(<<)能将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0)。
“有符号”右移位运算符(>>)则将运算符左边的运算对象向右移动运算符右侧指定的位数。“有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。
Java也添加了一种“无符号”右移位运算符(>>>),它使用了“零扩展”:无论正负,都在高位插入0。这一运算符是C或C++没有的。

若对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。只有右侧的5个低位才会用到。这样可防止我们在一个int数里移动不切实际的位数。若对一个long值进行处理,最后得到的结果也是long。此时只会用到右侧的6个低位,防止移动超过long值里现成的位数。但在进行“无符号”右移位时,也可能遇到一个问题。若对byte或short值进行右移位运算,得到的可能不是正确的结果(Java 1.0和Java 1.1特别突出)。它们会自动转换成int类型,并进行右移位。

关于java中char,byte,short的移位操作

Java 数据类型

类型 位数 字节数 取值范围
byte 8 1 负的2的7次方到2的7次方的整数
short 16 2 负的2的15次方到2的15次方的整数
int 32 4 负的2的31次方到2的31次方的整数
long 64 8 负的2的63次方到2的63次方的整数
float 32 4 负的2的31次方到2的31次方的实数
double 64 8 负的2的63次方到2的63次方的实数
char 16 2 负的2的15次方到2的15次方的整数
boolean 8 1 true ,false
分类: 阅读 标签: ,

Daniel-Journey Weekly Dose -2012/4/22

2012年4月23日 admin 没有评论

Daniel-Journey Weekly Dose -2012/4/14

2012年4月15日 admin 没有评论

JAVA

CyclicBarrier Java Doc

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

CyclicBarrier(int parties)
          创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个 barrier 上执行预定义的操作

CyclicBarrier(int parties, Runnable barrierAction)
          创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行

await()
          在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。

await(long timeout, TimeUnit unit)
          在所有参与者都已经在此屏障上调用 await 方法之前,将一直等待。

java.util.concurrent.CyclicBarrier

ReentrantLock和内部锁的性能对比(update)

再谈重入锁—ReentrantLock

它提供了lock()方法:
如果该锁定没有被另一个线程保持,则获取该锁定并立即返回,将锁定的保持计数设置为 1。
如果当前线程已经保持该锁定,则将保持计数加 1,并且该方法立即返回。
如果该锁定被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁定之前,该线程将一直处于休眠状态,此时锁定保持计数被设置为 1。

ReentrantLock

一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread()getHoldCount() 方法来检查此情况是否发生。此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。

SCALABILITY

隆重推荐!Instagram高速增长下的扩展性实践

[转]海量小文件存储

LINUX

磁盘IO满负荷性能分析

spinlock剖析与改进

linux目录文件数与IO性能

提升磁盘IO性能的几个技巧

NOSQL

转:Redis学习手册(内存优化)

BIT和Byte级别的操作:
    从Redis 2.2开始,Redis提供了GETRANGE/SETRANGE/GETBIT/SETBIT四个用于字符串类型Key/Value的命令。通过这些命 令,我们便可以像操作数组那样来访问String类型的值数据了。比如唯一标识用户身份的ID,可能仅仅是String值的其中一段子字符串。这样就可以 通过GETRANGE/SETRANGE命令来方便的提取。再有就是可以使用BITMAP来表示用户的性别信息,如1表示male,0表示female。 用这种方式来表示100,000,000个用户的性别信息时,也仅仅占用12MB的存储空间,与此同时,在通过SETBIT/GETBIT命令进行数据遍 历也是非常高效的。

Database

latch & lock

Latch是Oracle提供的轻量级锁资源,他用于快速,短时间的锁定资源,防止多个并发进程同时修改访问某个共享资源,他只工作在内存中,我们可以不大准确的说,内存中资源的锁叫latch,数据库对象(表,索引等)的锁叫Lock。比如数据缓存中的某个块要被读取,我们会获得这个块的latch,这个过程叫做pin,另外一个进程恰好要修改这个块,他也要pin这个块,此时他必须等待,当前一个进程释放latch后才能pin住,然后修改,如果多个进程同时请求的话,他们之间将出现竞争,没有一个入队机制,一旦前面进程释放所定,后面的进程就蜂拥而上,没有先来后到的概念,这个和Lock是有本质区别的,这一切都发生的非常快,因为Latch的特点是快而短暂,当然这个只是大致过程,细节部分在后面讨论
    先来看下Latch和Lock的区别,
1.    Latch是对内存数据结构提供互斥访问的一种机制,而Lock是以不同的模式来套取共享资源对象,各个模式间存在着兼容或排斥,从这点看出,Latch的访问,包括查询也是互斥的,任何时候,只能有一个进程能pin住内存的某一块,幸好这个过程是相当的短暂,否则系统性能将没的保障,现在从9I开始,允许多个进程同时查询相同的内存块,但性能并没有想象中的好。
2.    Latch只作用于内存中,他只能被当前实例访问,而L ock作用于数据库对象,在RAC体系中实例间允许Lock检测与访问
3.    Latch是瞬间的占用,释放,Lock的释放需要等到事务正确的结束,他占用的时间长短由事务大小决定
4.    Latch是非入队的,而Lock是入队的
5.    Latch不存在死锁,而Lock中存在(死锁在Oracle中是非常少见的)

Daniel-Journey Weekly Dose -2012/4/7

2012年4月7日 admin 1 条评论

算法

Adler32

用于计算数据流的 Adler-32 校验和的类。Adler-32 校验和几乎与 CRC-32 一样可靠,但是能够更快地计算出来。

CRC32

硬件

MySQL数据库优化实践

RAID卡都有写cache(Battery Backed Write Cache),写cache对IO性能的提升非常明显,因为掉电会丢失数据,所以必须由电池提供支持。电池会定期充放电,一般为90天左右,当发现电量低于某个阀值时,会将写cache策略从writeback置为writethrough,相当于写cache会失效,这时如果系统有大量的IO操作,可能会明显感觉到IO响应速度变慢。目前,新的RAID卡内置了flash存储,掉电后会将写cache的数据写入flash中,这样就可以保证数据永不丢失,但依然需要电池的支持。

Linux有四种IO调度算法:CFQ,Deadline,Anticipatory和NOOP,CFQ是默认的IO调度算法。完全随机的访问环境下,CFQ与Deadline,NOOP性能差异很小,但是一旦有大的连续IO,CFQ可能会造成小IO的响应延时增加,所以数据库环境建议修改为deadline算法,表现更稳定。我们的环境统一使用deadline算法。

IO调度算法都是基于磁盘设计,所以减少磁头移动是最重要的考虑因素之一,但是使用Flash存储设备之后,不再需要考虑磁头移动的问题,可以使用NOOP算法。NOOP的含义就是NonOperation,意味着不会做任何的IO优化,完全按照请求来FIFO的方式来处理IO。

减少预读:/sys/block/sdb/queue/read_ahead_kb,默认128,调整为16

增大队列:/sys/block/sdb/queue/nr_requests,默认128,调整为512

LINUX

innodb_flush_method 与 Linux File I/O

和数据库性能密切相关的文件I/O操作的三个操作:

open 打开文件
write 写文件
fdatasync flush操作(将文件缓存刷到磁盘上)。

linux 设备IO 研究与数据库性能调优

了解IO协议栈

linux内核io调度算法(转)

IO调度器的总体目标是希望让磁头能够总是往一个方向移动,移动到底了再往反方向走,这恰恰就是现实生活中的电梯模型,所以IO调度器也被叫做电梯.(elevator)而相应的算法也就被叫做电梯算法.而Linux中IO调度的电梯算法有好几种,一个叫做as(Anticipatory),一个叫做cfq(Complete Fairness Queueing),一个叫做deadline,还有一个叫做noop(No Operation).具体使用哪种算法我们可以在启动的时候通过内核参数elevator来指定. 另一方面我们也可以单独的为某个设备指定它所采用的IO调度算法,这就通过修改在/sys/block/sda/queue/目录下面的scheduler文件.比如我们可以先看一下我的这块硬盘:
[root@localhost ~]# cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]
可以看到我们这里采用的是cfq.

Linux 2.6内核的四种IO调度算法总结

NOOP算法的全写为No Operation。该算法实现了最最简单的FIFO队列,所有IO请求大致按照先来后到的顺序进行操作。之所以说“大致”,原因是NOOP在FIFO的基础上还做了相邻IO请求的合并,并不是完完全全按照先进先出的规则满足IO请求。

CFQ算法的全写为Completely Fair Queuing。该算法的特点是按照IO请求的地址进行排序,而不是按照先来后到的顺序来进行响应。在传统的SAS盘上,磁盘寻道花去了绝大多数的IO响应时间。CFQ的出发点是对IO地址进行排序,以尽量少的磁盘旋转次数来满足尽可能多的IO请求。在CFQ算法下,SAS盘的吞吐量大大提高了。但是相比于NOOP的缺点是,先来的IO请求并不一定能被满足,可能会出现饿死的情况。Completely Fair Queuing (cfq, 完全公平队列) 在 2.6.18 取代了 Anticipatory scheduler 成为 Linux Kernel 默认的 IO scheduler 。cfq 对每个进程维护一个 IO 队列,各个进程发来的 IO 请求会被 cfq 以轮循方式处理。也就是对每一个 IO 请求都是公平的。这使得 cfq 很适合离散读的应用(eg: OLTP DB)。

DEADLINE在CFQ的基础上,解决了IO请求饿死的极端情况。除了CFQ本身具有的IO排序队列之外,DEADLINE额外分别为读IO和写IO提供了FIFO队列。读FIFO队列的最大等待时间为500ms,写FIFO队列的最大等待时间为5s。FIFO队列内的IO请求优先级要比CFQ队列中的高,,而读FIFO队列的优先级又比写FIFO队列的优先级高。优先级可以表示如下:FIFO(Read) > FIFO(Write) > CFQ

Anticipatory scheduler. CFQ和DEADLINE考虑的焦点在于满足零散IO请求上。对于连续的IO请求,比如顺序读,并没有做优化。为了满足随机IO和顺序IO混合的场景,Linux还支持ANTICIPATORY调度算法。ANTICIPATORY的在DEADLINE的基础上,为每个读IO都设置了6ms 的等待时间窗口。如果在这6ms内OS收到了相邻位置的读IO请求,就可以立即满足Anticipatory scheduler(as) 曾经一度是 Linux 2.6 Kernel 的 IO scheduler 。Anticipatory 的中文含义是”预料的, 预想的”, 这个词的确揭示了这个算法的特点,简单的说,有个 IO 发生的时候,如果又有进程请求 IO 操作,则将产生一个默认的 6 毫秒猜测时间,猜测下一个 进程请求 IO 是要干什么的。这对于随即读取会造成比较大的延时,对数据库应用很糟糕,而对于 Web Server 等则会表现的不错。这个算法也可以简单理解为面向低速磁盘的,因为那个”猜测”实际上的目的是为了减少磁头移动时间。

 

Architecture

星巴克不适用两阶段提交 Gregor Hohpe 之 异常处理

一笔勾销

重试

补救

数据库

数据库通用基础实现技术—多进程共享信息

数据库如何抵抗随机IO:问题、方法与现实

Nosql

深入浅出BDB的批量操作

Berkeley DB Java Edition 高可用性介绍

BDB的Btree结构以及影响Btree性能的各种配置和方法

Berkeley DB(以下简称BDB)支持四种访问方法,Btree,hash,queue,recno。BTree访问方法使用多叉BTree存储数据,hash访问方法使用可动态扩展的哈希表存储数据,queue访问方法支持顺序或逻辑记录数访问定长数据,recno访问方法支持顺序或逻辑记录数访问定长或者非定长数据,其中Btree应用最为广泛

Btree有五种类型的结点(页),元数据结点,中间结点,叶子结点,溢出结点和重复结点

Berkeley DB持久化和高速缓存

解密Redis持久化

  1. 客户端向服务端发送写操作(数据在客户端的内存中)
  2. 数据库服务端接收到写请求的数据(数据在服务端的内存中)
  3. 服务端调用write(2) 这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)
  4. 操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)
  5. 磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)

    通过上面5步的了解,可能我们会希望搞清下面一些问题:

    • 数据库多长时间调用一次write(2),将数据写到内核缓冲区
    • 内核多长时间会将系统缓冲区中的数据写到磁盘控制器
    • 磁盘控制器又在什么时候把缓存中的数据写到物理介质上

    对于第一个问题,通常数据库层面会进行全面控制。而对第二个问题,操作系统有其默认的策略,但是我们也可以通过POSIX API提供的fsync系列命令强制操作系统将数据从内核区写到磁盘控制器上。对于第三个问题,好像数据库已经无法触及,但实际上,大多数情况下磁盘缓存是被设置关闭的。或者是只开启为读缓存,也就是写操作不会进行缓存,直接写到磁盘。建议的做法是仅仅当你的磁盘设备有备用电池时才开启写缓存。

    所谓数据损坏,就是数据无法恢复,上面我们讲的都是如何保证数据是确实写到磁盘上去,但是写到磁盘上可能并不意味着数据不会损坏。比如我们可能一次写请求会进行两次不同的写操作,当意外发生时,可能会导致一次写操作安全完成,但是另一次还没有进行。如果数据库的数据文件结构组织不合理,可能就会导致数据完全不能恢复的状况出现。

    这里通常也有三种策略来组织数据,以防止数据文件损坏到无法恢复的情况:

    • 第一种是最粗糙的处理,就是不通过数据的组织形式保证数据的可恢复性。而是通过配置数据同步备份的方式,在数据文件损坏后通过数据备份来进行恢复。实际上MongoDB在不开启journaling日志,通过配置Replica Sets时就是这种情况。
    • 另一种是在上面基础上添加一个操作日志,每次操作时记一下操作的行为,这样我们可以通过操作日志来进行数据恢复。因为操作日志是顺序追加的方式写的,所以不会出现操作日志也无法恢复的情况。这也类似于MongoDB开启了journaling日志的情况。
    • 更保险的做法是数据库不进行老数据的修改,只是以追加方式去完成写操作,这样数据本身就是一份日志,这样就永远不会出现数据无法恢复的情况了。实际上CouchDB就是此做法的优秀范例。

Java

JVM那些事

ConcurrentHashMap是如何提高并发时的吞吐性能(一)

java使用bdb手记(Berkeley DB Java api记录)

用java操作bdb的方法记录二

JMM(Java内存模型)中的核心概念

从 Java 代码到 Java 堆

Daniel-Journey Weekly Dose -2012/3/25

2012年3月25日 admin 没有评论

Architecture

多版本并发控制(MVCC)在分布式系统中的应用

Concurrency

多线程编程的设计模式 不变模式(二)

OpenSource

最近关注过的一些项目

zookeeper

TimeTunnel

TimeTunnel你可以理解成一个消息中间件,它整个设计跟我们的产品相当接近,但是两者的目的完全不同,tt强调的是高吞吐量,而notify强调的则是可靠性。TT的通讯层直接采用Facebook的thrift,并且利用zookeeper做集群管理和路由。TT的代码质量很好,有兴趣可以拉出来看一下,并且对zookeeper的应用也是一个典型的案例。TT在高可用性上的方案也很有特色,所有的服务器节点形成一个环,两两相互主辅备份,一个节点挂了,后续节点仍然可以提供服务直到主节点回来,有点类似一致性哈希的概念。节点的主从关系和顺序也是通过zookeeper保证。消息顺序的实现是通过称为router的路由到固定节点做传输,router默认是策略不是固定而是RR。TT的数据存储优先放在内存,并设置了一个内存状况监视的组件,当发现内存放不下的时候,swap到磁盘文件缓存,实现类似内存换页的功能。正常情况数据都应该在内存,当然如果可靠级别要求高的话可以先存磁盘再传输。

kafka

kafka的开发者们认为不需要在内存里缓存什么数据,操作系统的文件缓存已经足够完善和强大,只要你不搞随机写,顺序读写的性能是非常高效的。kafka的数据只会顺序append,数据的删除策略是累积到一定程度或者超过一定时间再删除。Kafka另一个独特的地方是将消费者信息保存在客户端而不是MQ服务器,这样服务器就不用记录消息的投递过程,每个客户端都自己知道自己下一次应该从什么地方什么位置读取消息,消息的投递过程也是采用客户端主动pull的模型,这样大大减轻了服务器的负担。Kafka还强调减少数据的序列化和拷贝开销,它会将一些消息组织成Message Set做批量存储和发送,并且客户端在pull数据的时候,尽量以zero-copy的方式传输,利用sendfile(对应java里的 FileChannel.transferTo/transferFrom)这样的高级IO函数来减少拷贝开销。

Design Pattern

设计模式之State

一个状态模式的小改进

设计模式之Visitor

LINUX

iostat来对linux硬盘IO性能进行了解

rrqm/s:   每秒进行 merge 的读操作数目.即 delta(rmerge)/s
wrqm/s:  每秒进行 merge 的写操作数目.即 delta(wmerge)/s
r/s:           每秒完成的读 I/O 设备次数.即 delta(rio)/s
w/s:         每秒完成的写 I/O 设备次数.即 delta(wio)/s
rsec/s:    每秒读扇区数.即 delta(rsect)/s
wsec/s:  每秒写扇区数.即 delta(wsect)/s
rkB/s:      每秒读K字节数.是 rsect/s 的一半,因为每扇区大小为512字节.(需要计算)
wkB/s:    每秒写K字节数.是 wsect/s 的一半.(需要计算)
avgrq-sz: 平均每次设备I/O操作的数据大小 (扇区).delta(rsect+wsect)/delta(rio+wio)
avgqu-sz: 平均I/O队列长度.即 delta(aveq)/s/1000 (因为aveq的单位为毫秒).
await:    平均每次设备I/O操作的等待时间 (毫秒).即 delta(ruse+wuse)/delta(rio+wio)
svctm:   平均每次设备I/O操作的服务时间 (毫秒).即 delta(use)/delta(rio+wio)
%util:      一秒中有百分之多少的时间用于 I/O 操作,或者说一秒中有多少时间 I/O 队列是非空的.即 delta(use)/s/1000 (因为use的单位为毫秒)

如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘
可能存在瓶颈.
idle小于70% IO压力就较大了,一般读取速度有较多的wait.

同时可以结合vmstat 查看查看b参数(等待资源的进程数)和wa参数(IO等待所占用的CPU时间的百分比,高过30%时IO压力高)
另外 await 的参数也要多和 svctm 来参考.差的过高就一定有 IO 的问题.
avgqu-sz 也是个做 IO 调优时需要注意的地方,这个就是直接每次操作的数据的大小,如果次数多,但数据拿的小的话,其实 IO 也会很小.如果数据拿的大,才IO 的数据会高.也可以通过 avgqu-sz × ( r/s or w/s ) = rsec/s or wsec/s.也就是讲,读定速度是这个来决定的.

svctm 一般要小于 await (因为同时等待的请求的等待时间被重复计算了),svctm 的大小一般和磁盘性能有关,CPU/内存的负荷也会对其有影响,请求过多也会间接导致 svctm 的增加.await 的大小一般取决于服务时间(svctm) 以及 I/O 队列的长度和 I/O 请求的发出模式.如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明 I/O 队列太长,应用得到的响应时间变慢,如果响应时间超过了用户可以容许的范围,这时可以考虑更换更快的磁盘,调整内核 elevator 算法,优化应用,或者升级 CPU.
队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标,但由于 avgqu-sz 是按照单位时间的平均值,所以不能反映瞬间的 I/O 洪水.

Java

From Java code to Java heap

DelayQueue在容错时的使用

Batch Insert In Java – JDBC

Reducing Java Memory Usage and Garbage Collections with the UseCompressedOops VM Option

Java 内存调整技巧

垃圾回收通常占用正常运行的应用程序总执行时间的 5% 到 20%。如果不进行管理,那么垃圾回收会是应用程序的一个最大的瓶颈。

如果信息表明产生了垃圾回收瓶颈,那么有两种方法清除瓶颈。最划算的方法是优化应用程序以实现对象高速缓存和池。使用 Java 概要分析程序确定目标对象。如果您无法优化应用程序,那么添加内存、处理器和克隆可能会有帮助。添加的内存允许每个克隆保持合理的堆大小。添加的处理器允许克隆并行运行。

  • 垃圾回收调用次数
  • 一次垃圾回收调用的平均持续时间
  • 一次垃圾回收调用的工作时间长度和两次垃圾回收调用之间的平均时间之间的比率

Daniel-Journey Weekly Dose -2012/3/21

2012年3月21日 admin 没有评论

Java

BerkleyDB for Java概述

LIGHTWEIGHT FAST PERSISTENT QUEUE IN JAVA USING BERKLEY DB

设计模式之不变模式(Immutable Pattern)分析

 

理解ThreadLocal

  线程首次调用ThreadLocal.get方法时,会请求initialValue提供一个初始化值。概念上,你可以将ThreadLocal<T> 看作Map<Thread,T>它存储了线程相关的值,不过事实上它并非这样实现的。与线程相关的值存储在线程对象自身中,线程终止后,这些值会被垃圾回收。

关于Java中的final

当你在类中定义变量时,在其前面加上final关键字,那便是说,这个变量一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变,但引用变量所指向的对象中的内容还是可以改变的

其初始化可以在三个地方,
一是其定义处,也就是说在final变量定义时直接给其赋值,
二是在构造函数中。而且在Java1.1以前,只能是在定义时给值
三是在初如化代码块中{} 或者 static{}

安全发布的模式

如果一个对象不是不可改变的,它就必须被安全的发布,通常发布线程与消费线程都必须同步化。

为了安全地发布对象,对象的引用以及对象的状态必须同时对其他线程可见。为了创建一个正确的对象可以通过以下条件安全的发布:

  1. 通过静态初始化器初始化对象的引用。
  2. 将他的引用存储到Volatile域或AutomicReference;
  3. 将他的引用存储到正确创建的对象的final域中
  4. 或者将它的引用存储到有锁正确保护的域中

 

分类: 阅读 标签:

Daniel-Journey Weekly Dose -2012/3/24

2012年3月21日 admin 没有评论

ARCHITECTURE

谈谈 Event & Thread

Event/thread之争由来已久,有人说event好 [1],也有人说thread好 [2],但更早前人说了两个具有duality,其实一样好 [3]。

先从thread structure和context switch入手理解thread model(以后找机会再谈谈0号1号进程,这是解剖OS的肯綮),培养对control flow的直观认识,进而熟悉event-driven,培养起event=logical thread的认识。然后辨识non-blocking/asynchronous/continuation/delegation等等概念。如果还是一知半解,没有关系,software engineer有个法宝,无往而不利。就是modeling/simualting,然后iterate

Eventing带来了很多问题,你得把思维掰碎了再重组。如果你不理解,建议看看“低俗小说”,昆汀·塔伦蒂诺通过event-driven完成了对以前multi-threading电影结构的颠覆。

简单来说,event/thread只是形式,更重要的是二者反映出的异步/同步思想。虽然thread也能做成异步,event也可同步,但毕竟这不是自然的行为。很多时候形式很重要,它可以引导用户采用你的模型/理念。你会很自豪,因为这不是你强制的,但这也带来了压力,不好的形式将在很长时间后引爆问题——这也是为什么写基础库比写application需要深厚得多的功力的原因。

异步理念带来了系统结构深刻的变化,更多的资源、数据结构和控制点暴露出来了,也使得控制流得以在更细粒度上分片。归结为两个好处:1) 执行的可调度性;2) 资源分配的动态性;从而也使调速、限流等手段得以实现。这其实也就使得以前的layering被打破了,使得mechanism/policy彻底解耦成为可能,使得底层可以更简单、上层可以充分利用它的intelligence,从而带来了application-controlled extension。其实这可以用一张图片形象描述,就是鲜奶要保温而火腿需冷藏那个 [figure1]。

 

LINUX

Fio压测工具和io队列深度理解和误区

应用使用IO通常有二种方式:同步和异步。 同步的IO一次只能发出一个IO请求,等待内核完成才返回,这样对于单个线程iodepth总是小于1,但是可以透过多个线程并发执行来解决,通常我们会用16-32根线程同时工作把iodepth塞满。 异步的话就是用类似libaio这样的linux native aio一次提交一批,然后等待一批的完成,减少交互的次数,会更有效率。

【原创翻译】《Linux 性能及调优指南》2.3.10 pmap

在输出结果的最后一行显示了一些重要的信息,如下:

mapped :映射到文件的内存数量

writable/private :进程所占用的私有地址空间数量

shared :与其它进程共享的地址空间数量

pmap : 理解linux的进程内存占用

RSS 就是这个process 实际占用的物理内存

VSZ 就是process 的虚拟内存,就是process 现在没有使用但未来可能会分配的内存大小。

而 pmap 的输出中,writeable/private: 19208K ,这个就是yakuake 这个程序真正占用的物理内存,不包含shared libraries 。在这里,它只有19208K,而ps 的RSS 是34416K。

linux之pmap命令!

Address:00378000-0038d000 进程所占的地址空间
Kbytes 该虚拟段的大小
RSS 设备号(主设备:次设备)
Anon 设备的节点号,0表示没有节点与内存相对应
Locked 是否允许swapped
Mode 权限:r=read, w=write, x=execute, s=shared, p=private(copy on write)
Mapping: bash 对应的映像文件名

了解Linux的进程与线程

pmap -x <pid> 可以查看进程的内存占用信息

lsof -a -p <pid> 可以查看一个进程打开的文件信息

ps -Lf <pid> 可以查看进程的线程数。

procfs也是一个分析进程结构的好地方。procfs是一个虚拟的文件系统,它把系统中正在运行的进程都显现在/proc/<pid>目录下。

DATABASE

ORACLE ERROR CODE代表的意思

分类: 阅读 标签: , ,

Daniel-Journey Weekly Dose -2012/3/18

2012年3月19日 admin 没有评论

Database

Berkeley DB Performance Tuning

The database cache is global for all databases in a particular environment and needs to be allocated at the time that environment is created. Most of the time this is done programmaticaly. The issue of course is that, the optimal cache size is directly related to the size of the data set, which is not always known at application design time. Many BerkeleyDB applications end up storing considerably more data than originally envisioned. Even worse, some applications do not explicitly specify a cache size at all, so the default cache size of 256KB is allocated – which far too low for many applications.

Java

JVM学习之-栈

Java Anti-Patterns

    1. String concatenation
    2. Lost StringBuffer performance
    3. Testing for string equality
    4. Converting numbers to Strings
    5. Not taking advantage of immutable objects
    6. XML parsers are for sissies
    7. Assembling XML with String operations
    8. The XML encoding trap
    9. char is not int
    10. Undefined encoding
    11. Unbuffered streams
    12. Infinite heap
    13. Infinite time
    14. Assuming a cheap timer call
    15. Catch all: I don’t know the right runtime exception
    16. Exceptions are annoying
    17. Re-wrapping RuntimeException
    18. Not properly propagating the exception
    19. Catching to log
    20. Incomplete exception handling
    21. The exception that never happens
    22. The transient trap
    23. Overkill initialization
    24. Log instances: static or not?
    25. Chosing the wrong class loader
    26. Poor use of reflection
    27. Synchronization overkill
    28. Wrong list type
    29. The HashMap size trap
    30. Hashtable, HashMap and HashSet are overrated
    31. Lists are overrated
    32. Object arrays are soooo flexible
    33. Premature object decomposition
    34. Modifying setters
    35. Unnecessary Calendar
    36. Relying on the default TimeZone
    37. Time zone "conversion"
    38. Using Calendar.getInstance()
    39. Dangerous Calendar manipulation
    40. Calling Date.setTime()
    41. Assuming SimpleDateFormat was thread-safe
    42. Having a global Configuration/Parameters/Constants class
    43. Not noticing overflows
    44. Using == with float or double
    45. Storing money in floating point variables
    46. Not freeing resources in a finally block
    47. Abusing finalize()
    48. Involuntarily resetting Thread.interrupted
    49. Spawning thread from static initializers
    50. Canceled timer tasks that keep state
    51. Holding strong references to ClassLoaders and unflushable caches
分类: 阅读 标签: ,

Daniel-Journey Weekly Dose -2012/3/4

2012年3月5日 admin 2 条评论

Investment

基金定投五大法宝

第一,定投不必太在意择时,长期坚持更重要。

第二,必须遵守“小跌小补仓,大跌大补仓”原则。

第三,由于市场通常都是风水轮流转,因此,所定投的标的品种也需要轮流换。

第四,及时锁定收益,落袋为安。

第五,以基养基,用基金定投所获取收益来定投别的基金。

牛市和熊市的操作思维不同,熊市是反弹10%就准备跑,牛市是下跌10%就准备买。

Programming

转:结对编程的误区

Architecture

Event Sourcing

Java

Using a memory mapped file for a huge matrix

Annotation入门实例,一分钟了解Annotation

spring中bean的高级属性之list, set, map以及props元素(含举例)

How to develop and monitor Thread Pool Services by using Spring

Network

How To Optimize Your Site With HTTP Caching

Caching Method 1: Last-Modified

Caching Method 2: ETag

Caching Method 3: Expires

Caching Method 4: Max-Age

 

Windows

如何压缩 Outlook PST 和 OST 文件