本书的第一部分,讲解了分布式系统所需要的技术,如Remoting,XML Web Service,MSMQ,COM+和多线程.
这些是最基本,也是最好掌握的内容.
第二部分,才是本书精华.从本章起,作者,开始讲架构和设计要考虑的因素,和他的一些经验.
在这之前,大家要纠正两个不正确的编程观念:
- 不要用将OO的设计方法运用在分布式系统中
- 不要让对象有状态信息
为什么这么说呢?原因有两个:
- 远程对象不同于本地对象,因为它们需要跨进程和网络被访问.性能是最大的问题.虽然你感觉不到,但每次方法和属性调用,都是一次网络数据发送.底层是很复杂的.
- 远程对象是状态很难保持,就算可以,会占用服务器太多内存.且在将来做Load-Balancing扩展时,会有问题.
看个例子:
Public Class Account
' For simplicity's sake we use public variables instead of
' full property procedures.
Public AccountID As Integer
Public Balance As Decimal
Public Sub Update()
' (Update this record in the database.)
End Sub
Public Sub Insert()
' (Insert a new account record using the information in this
' class.)
End Sub
Public Sub Delete()
' (Delete the database record that matches this class.)
End Sub
Public Sub Fill()
' (Get the database record that matches this class.)
End Sub
End Class
如果你要在两个Account之间转帐,你会这么写:
Dim AccA As New Account(), AccB As New Account()
' Retrieve the balance for account 1001.
AccA.AccountID = 1001
AccA.Fill()
' Retrieve the balance for account 1002.
AccB.AccountID = 1002
AccB.Fill()
' Transfer the money.
Dim Transfer As Decimal = 150
AccA.Balance += Transfer
AccB.Balance -= Transfer
' Save both records.
AccA.Update()
AccB.Update()
这段这代码很好,也很直观.但它的效率非常低如果Account是一个远程对象.
- 总共会有8次Socket调用
- Account是有状态的.如果你的客户端数目小,所你感觉不到什么.但如果数据成倍增长,你的程序会有性能瓶颈
Update是原子的,但上面的代码并不能保证原子性
来看无状态的Account是什么样的.
Public Class AccountUtility
Public Sub UpdateAccount(accountID As Integer, balance As Decimal)
' (Update the account record in the database.)
End Sub
Public Sub InsertAccount(accountID As Integer, balance As Decimal)
' (Insert a new account record.)
End Sub
Public Sub Delete(accountID As Integer)
' (Delete the corresponding database record.)
End Sub
Public Sub TransferFunds(accountIDFrom As Integer, _
accountIDTo As Integer, transferAmount As Decimal)
' (Start a database transaction, and modify the two accounts.)
End Sub
End Class
现在如果要转帐,现要就这么写:
Dim AccUtility As New AccountUtility()
AccUtility.TransferFunds(1001, 1002, 150)
新版本的Account非常很像旧的面向过程式的编程方法,但它非常合分布式,因为:
- 只有一次调用,减少了网络调用的次数
- 服务器不保持任务的状态
- 转帐的逻辑在服务器,而不是客户端
当然,它也有它的不足,如果一个方法需要N个参数,调用全部要传过去,很麻烦.
Public Sub InsertCustomer(firstName As String, lastName As String, _ userID As String, password As String, email As String, _ streetAddress As String, city As String, postalCode As String, _ country As String)
' (Code omitted)
End Sub
这时,我们可以编写一个实体类(也就是前面说的Information Package),用来存放这些参数.
Public Class AccountDetails
Public AccountID As Integer
Public Balance As Integer
End Class