环信SDK与Apple Watch的结合系列讲解(1)

该系列是记录在apple watch上开发IM,用到了最近挺流行的环信IM SDK。
一、先来一段网上随处可查到的信息:

1、两种分辨率
1.65寸 312*390
1.5寸 272*340
2、开发环境
Xcode 6.2 or later
OS X 10.9.4 or later
Watchkit
3、三种展现类型
a>标准的watch app,拥有自身的界面和功能
b>Glances,纯信息浏览,样式也很固定。这一方式适合新闻、天气、股票、运动数据等信息。
c>Notification,用于显示用户的本地通知和远程通知,它包括 Short-Look 和 Long-Look 两种形式。
4、官方文档
https://developer.apple.com/li ... .html
5、怎么在工程中加入apple watch
关于这部分,网上的资料很多,在这外链一些不错的blog:
http://www.tuicool.com/articles/MFJFNny
http://blog.jobbole.com/79984/
 
二、WatchKit和环信SDK的结合

1、在工程中添加WatchKit扩展
你可以新建一个工程,在target上添加,也可以在已有的工程的target上添加,操作步骤是一样一样的。
为了记录的完整性,我新建了一个工程EMWatchOCDemo,看名字可以知道,这是一个ObjC写的工程。
21.png

2、EMWatchOCDemo是iphone的程序,先在这个target上接入环信SDK。
按照环信官网上的ios集成文档下载环信sdk,加入依赖库,配置好属性。我不准备实现实时语音,所以只用了lite.a。导入环信sdk之后的工程变成了这个样子
22.png

我比较习惯每个步骤都编译一下,如果编译通过,继续进行下边的步骤。
3、初始化环信SDK
环信SDK的初始化几乎都在AppDelegate.m中实现,如注册app,配置apns证书和昵称,进入前台和进入后台的操作,这些在环信官网的ios初始化文档中都有描述,不再赘述。
4、实现一些简单的功能
ConversationViewController 会话获取,展示。
FriendsViewController 好友获取,展示。
GroupsViewController 群组获取,展示。
HomeViewController是首页,Tab容器,实现了登录等操作。
DXEMIMHelper是IM的管理类,定义了全局的宏定义,包括默认登录账号KDEFAULT_USERNAME。
作者: 谢雅杰
环信SDK与Apple Watch的结合系列讲解(2)
环信SDK与Apple Watch的结合系列讲解(3)
继续阅读 »
该系列是记录在apple watch上开发IM,用到了最近挺流行的环信IM SDK。
一、先来一段网上随处可查到的信息:

1、两种分辨率
1.65寸 312*390
1.5寸 272*340
2、开发环境
Xcode 6.2 or later
OS X 10.9.4 or later
Watchkit
3、三种展现类型
a>标准的watch app,拥有自身的界面和功能
b>Glances,纯信息浏览,样式也很固定。这一方式适合新闻、天气、股票、运动数据等信息。
c>Notification,用于显示用户的本地通知和远程通知,它包括 Short-Look 和 Long-Look 两种形式。
4、官方文档
https://developer.apple.com/li ... .html
5、怎么在工程中加入apple watch
关于这部分,网上的资料很多,在这外链一些不错的blog:
http://www.tuicool.com/articles/MFJFNny
http://blog.jobbole.com/79984/
 
二、WatchKit和环信SDK的结合

1、在工程中添加WatchKit扩展
你可以新建一个工程,在target上添加,也可以在已有的工程的target上添加,操作步骤是一样一样的。
为了记录的完整性,我新建了一个工程EMWatchOCDemo,看名字可以知道,这是一个ObjC写的工程。
21.png

2、EMWatchOCDemo是iphone的程序,先在这个target上接入环信SDK。
按照环信官网上的ios集成文档下载环信sdk,加入依赖库,配置好属性。我不准备实现实时语音,所以只用了lite.a。导入环信sdk之后的工程变成了这个样子
22.png

我比较习惯每个步骤都编译一下,如果编译通过,继续进行下边的步骤。
3、初始化环信SDK
环信SDK的初始化几乎都在AppDelegate.m中实现,如注册app,配置apns证书和昵称,进入前台和进入后台的操作,这些在环信官网的ios初始化文档中都有描述,不再赘述。
4、实现一些简单的功能
ConversationViewController 会话获取,展示。
FriendsViewController 好友获取,展示。
GroupsViewController 群组获取,展示。
HomeViewController是首页,Tab容器,实现了登录等操作。
DXEMIMHelper是IM的管理类,定义了全局的宏定义,包括默认登录账号KDEFAULT_USERNAME。
作者: 谢雅杰
环信SDK与Apple Watch的结合系列讲解(2)
环信SDK与Apple Watch的结合系列讲解(3) 收起阅读 »

怎样在Apple Watch上集成环信SDK

本文简单的讲述下如何用Apple Watch Kit集成环信SDK.
首先:需要升级xcode到version 6.2,和 IOS SDK8.2
然后下载环信SDK从官网
打开XCode->new project->new target->选择WatchKit App
1.png

xcode 会自动给你创建几个targets,例如下图:
2.png

把EaseMobSDK文件夹拖拽到HxAppleWatchDemo Target里
3.png

选择target HXAppleWatchDemo,加入下图所有的Linked Frameworks and Libraries里的库文件
4.png

在HXAppleWatchDemo target 创建bridging header文件
5.png

设置bridging header文件
6.png

设置other linker flags 以保证SDK Lib category的扩展方法可用
7.png

所有环境设置都已完成,试着build下看有啥问题么
接着开始写代码:
1. 打开HXAppleWatchDemo WatchKit App 里的interface.storyboard然后加个button 叫load contacts
8.png

2. 找到HXAppleWatchDemo WatchKit Extension里的文件InterfaceController.swift,然后把上述的button关联到 @IBOutlet weakvar open:WKInterfaceButton!
InterfaceController.swift代码如下
//
// InterfaceController.swift
// HXAppleWatchDemo WatchKit Extension
//
// Created by youni on 15/4/1.
// Copyright (c) 2015年 youni. All rights reserved.
// 
 
import WatchKit
import Foundation
 
class InterfaceController: WKInterfaceController {
 
@IBOutlet weak var open: WKInterfaceButton!
 
@IBAction func openApp() {
InterfaceController.openParentApplication(["action":"getcontact"], reply: {(info:[NSObject : AnyObject]!, error:NSError!) -> Void in
if info != nil{
if info.count > 0{
self.getContacts(info!["contacts"] as [String])
}
}
})
}
 
func getContacts(contacts:[String]){
presentTextInputControllerWithSuggestions(contacts, allowedInputMode: WKTextInputMode.Plain, completion: {(result:[AnyObject]!)-> Void in
if result != nil{
var id:String = result[0] as String
var date:NSDate = NSDate()
var now:NSTimeInterval = date.timeIntervalSinceNow
 
self.sendMessage(id,text: now.description)
}
}
)
}
 
func sendMessage(id:String,text:String){
InterfaceController.openParentApplication(["action":"send","name":id,"message":text], reply: {(info:[NSObject : AnyObject]!, error:NSError!) -> Void in
 
})
}
 
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
 
// Configure interface objects here.
}
 
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
 
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
 
}
InterfaceController.openParentApplication是用来和IOS的程序通讯的接口,大部分的业务逻辑需要在parent application实现也就是上述说的HXAppleWatchDemo Target
我们看下HXAppleWatchDemo是如何实现和Apple Watch App通讯的
//
// AppDelegate.swift
// HXAppleWatchDemo
//
// Created by youni on 15/4/1.
// Copyright (c) 2015年 youni. All rights reserved.
// 
 
import UIKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,IChatManagerDelegate{
 
var window: UIWindow?
 
var callback:(([NSObject : AnyObject]!) -> Void)!
 
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let apnsCertName:String = "chatdemoui";
 
EaseMob.sharedInstance().registerSDKWithAppKey("easemob-demo#chatdemoui", apnsCertName: apnsCertName)
 
EaseMob.sharedInstance().chatManager.addDelegate(self, delegateQueue: nil)
 
EaseMob.sharedInstance().chatManager.asyncLoginWithUsername("tt1", password: "1", completion: { (loginInfo,error) -> Void in
 
NSLog("login callback : ")
 
HXSDKHelper.instance.sendTextMessage("uni3", textMessge:"test from")
}, onQueue: nil)
 
return true
}
 
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
 
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
 
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
 
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
 
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
 
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) {
 
if(userInfo != nil){
if userInfo!["action"] != nil{
var action:String = userInfo!["action"] as String
 
if action == "getcontact"{
reply!(["contacts":["uni3","uni5","tt2"]])
}else if action == "send"{
var name:String = userInfo!["name"] as String
var message:String = userInfo!["message"] as String
NSLog("name : " + name + "message : " + message)
HXSDKHelper.instance.sendTextMessage(name, textMessge:message)
callback = reply
}
}
}
}
 
func didSendMessage(message: EMMessage!, error: EMError!) {
if(error != nil){
callback!(["send":error!.errorCode.value])
}else{
callback!(["send":"ok"])
}
}
 
func didReceiveMessage(message: EMMessage!) {
 
}
}
这个就是和Apple WatchKit App实现通讯的接口:
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) { 
 
if(userInfo != nil){
if userInfo!["action"] != nil{
var action:String = userInfo!["action"] as String
 
if action == "getcontact"{
reply!(["contacts":["uni3","uni5","tt2"]])
}else if action == "send"{
var name:String = userInfo!["name"] as String
var message:String = userInfo!["message"] as String
NSLog("name : " + name + "message : " + message)
HXSDKHelper.instance.sendTextMessage(name, textMessge:message)
callback = reply
}
}
}
}
HXSDKHelper就是对环信一个简单的封装,现在里面只实现了一个函数
//
// HXSDKHelper.swift
// swittest
//
// Created by youni on 15/3/15.
// Copyright (c) 2015年 youni. All rights reserved.
// 
 
import Foundation
private var gInstance = HXSDKHelper()
 
class HXSDKHelper : NSObject{
class var instance:HXSDKHelper{
return gInstance
}
 
func sendTextMessage(to : String, textMessge : String){
var latestMessage:EMMessage = EMMessage()
var chatText:EMChatText = EMChatText(text: textMessge)
var txtBody:EMTextMessageBody = EMTextMessageBody(chatObject: chatText)
 
latestMessage.addMessageBody(txtBody);
latestMessage.to = to;
EaseMob.sharedInstance().chatManager.asyncSendMessage(latestMessage, progress: nil);
}
}
大功告成,完成以上步骤,你就能够做个简单的Watch App 可以用环信的SDK发消息了。
由于没有真机,以上都是在模拟器上测试通过。
如果需要工程代码请联系我:syyorient@outlook.com
或者从github上获取
https://github.com/youniworld/ ... anXin
如果其他问题可以登陆http://www.easemob.com/docs/gettingstart/
作者:隋云怡
继续阅读 »
本文简单的讲述下如何用Apple Watch Kit集成环信SDK.
首先:需要升级xcode到version 6.2,和 IOS SDK8.2
然后下载环信SDK从官网
打开XCode->new project->new target->选择WatchKit App
1.png

xcode 会自动给你创建几个targets,例如下图:
2.png

把EaseMobSDK文件夹拖拽到HxAppleWatchDemo Target里
3.png

选择target HXAppleWatchDemo,加入下图所有的Linked Frameworks and Libraries里的库文件
4.png

在HXAppleWatchDemo target 创建bridging header文件
5.png

设置bridging header文件
6.png

设置other linker flags 以保证SDK Lib category的扩展方法可用
7.png

所有环境设置都已完成,试着build下看有啥问题么
接着开始写代码:
1. 打开HXAppleWatchDemo WatchKit App 里的interface.storyboard然后加个button 叫load contacts
8.png

2. 找到HXAppleWatchDemo WatchKit Extension里的文件InterfaceController.swift,然后把上述的button关联到 @IBOutlet weakvar open:WKInterfaceButton!
InterfaceController.swift代码如下
//
// InterfaceController.swift
// HXAppleWatchDemo WatchKit Extension
//
// Created by youni on 15/4/1.
// Copyright (c) 2015年 youni. All rights reserved.
// 
 
import WatchKit
import Foundation
 
class InterfaceController: WKInterfaceController {
 
@IBOutlet weak var open: WKInterfaceButton!
 
@IBAction func openApp() {
InterfaceController.openParentApplication(["action":"getcontact"], reply: {(info:[NSObject : AnyObject]!, error:NSError!) -> Void in
if info != nil{
if info.count > 0{
self.getContacts(info!["contacts"] as [String])
}
}
})
}
 
func getContacts(contacts:[String]){
presentTextInputControllerWithSuggestions(contacts, allowedInputMode: WKTextInputMode.Plain, completion: {(result:[AnyObject]!)-> Void in
if result != nil{
var id:String = result[0] as String
var date:NSDate = NSDate()
var now:NSTimeInterval = date.timeIntervalSinceNow
 
self.sendMessage(id,text: now.description)
}
}
)
}
 
func sendMessage(id:String,text:String){
InterfaceController.openParentApplication(["action":"send","name":id,"message":text], reply: {(info:[NSObject : AnyObject]!, error:NSError!) -> Void in
 
})
}
 
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
 
// Configure interface objects here.
}
 
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
 
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
 
}
InterfaceController.openParentApplication是用来和IOS的程序通讯的接口,大部分的业务逻辑需要在parent application实现也就是上述说的HXAppleWatchDemo Target
我们看下HXAppleWatchDemo是如何实现和Apple Watch App通讯的
//
// AppDelegate.swift
// HXAppleWatchDemo
//
// Created by youni on 15/4/1.
// Copyright (c) 2015年 youni. All rights reserved.
// 
 
import UIKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,IChatManagerDelegate{
 
var window: UIWindow?
 
var callback:(([NSObject : AnyObject]!) -> Void)!
 
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let apnsCertName:String = "chatdemoui";
 
EaseMob.sharedInstance().registerSDKWithAppKey("easemob-demo#chatdemoui", apnsCertName: apnsCertName)
 
EaseMob.sharedInstance().chatManager.addDelegate(self, delegateQueue: nil)
 
EaseMob.sharedInstance().chatManager.asyncLoginWithUsername("tt1", password: "1", completion: { (loginInfo,error) -> Void in
 
NSLog("login callback : ")
 
HXSDKHelper.instance.sendTextMessage("uni3", textMessge:"test from")
}, onQueue: nil)
 
return true
}
 
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
 
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
 
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
 
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
 
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
 
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) {
 
if(userInfo != nil){
if userInfo!["action"] != nil{
var action:String = userInfo!["action"] as String
 
if action == "getcontact"{
reply!(["contacts":["uni3","uni5","tt2"]])
}else if action == "send"{
var name:String = userInfo!["name"] as String
var message:String = userInfo!["message"] as String
NSLog("name : " + name + "message : " + message)
HXSDKHelper.instance.sendTextMessage(name, textMessge:message)
callback = reply
}
}
}
}
 
func didSendMessage(message: EMMessage!, error: EMError!) {
if(error != nil){
callback!(["send":error!.errorCode.value])
}else{
callback!(["send":"ok"])
}
}
 
func didReceiveMessage(message: EMMessage!) {
 
}
}
这个就是和Apple WatchKit App实现通讯的接口:
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) { 
 
if(userInfo != nil){
if userInfo!["action"] != nil{
var action:String = userInfo!["action"] as String
 
if action == "getcontact"{
reply!(["contacts":["uni3","uni5","tt2"]])
}else if action == "send"{
var name:String = userInfo!["name"] as String
var message:String = userInfo!["message"] as String
NSLog("name : " + name + "message : " + message)
HXSDKHelper.instance.sendTextMessage(name, textMessge:message)
callback = reply
}
}
}
}
HXSDKHelper就是对环信一个简单的封装,现在里面只实现了一个函数
//
// HXSDKHelper.swift
// swittest
//
// Created by youni on 15/3/15.
// Copyright (c) 2015年 youni. All rights reserved.
// 
 
import Foundation
private var gInstance = HXSDKHelper()
 
class HXSDKHelper : NSObject{
class var instance:HXSDKHelper{
return gInstance
}
 
func sendTextMessage(to : String, textMessge : String){
var latestMessage:EMMessage = EMMessage()
var chatText:EMChatText = EMChatText(text: textMessge)
var txtBody:EMTextMessageBody = EMTextMessageBody(chatObject: chatText)
 
latestMessage.addMessageBody(txtBody);
latestMessage.to = to;
EaseMob.sharedInstance().chatManager.asyncSendMessage(latestMessage, progress: nil);
}
}
大功告成,完成以上步骤,你就能够做个简单的Watch App 可以用环信的SDK发消息了。
由于没有真机,以上都是在模拟器上测试通过。
如果需要工程代码请联系我:syyorient@outlook.com
或者从github上获取
https://github.com/youniworld/ ... anXin
如果其他问题可以登陆http://www.easemob.com/docs/gettingstart/
作者:隋云怡 收起阅读 »

IM客户端数据库加载过程优化

IM
IM通讯里面有两个重要的数据概念,一个是会话,一个是会话中的消息。
在系统初始化时,这两部分都要从数据库中加载到内存中。
11.png

数据组织结构是ConversatonManager包含多个会话,每个会话含有消息列表。
[datalist]
每次系统启动的时候,首先查询会话列表,然后对每一个会话加载其中的消息。对应的伪码
conversationList = db.loadConverstaions() 
FOR (conversation : conversationList) { 
db.loadMessages(conversation);
 }
因为每次查询都要涉及数据库操作,导致加载时间很长,而且大量的IO操作也会导致耗电量增加,
所以这部分加载过程,是我们优化的重点。
思路很简单:一条SQL语句做完所有事情,避免for循环,避免多次遍历数据库。
修改后的结构是:
conversationList = db.loadConverstaionsAndMessages()
这样大量的细节隐藏在SQL语句实现中。
这里面的实现有两种情况:
1. 一种是每个会话只加载一条消息记录。
2. 另一种是每个会话加载多条消息记录。
1. 每个会话只加载一条消息记录(假设是最后一条消息),这种情况可以使用关键字group by 处理:
select *, max(msgTime) from xxx_table group by conversation
这种情况比较好理解,而且网上类似的问题很多,很容易找到答案。
2. 对于每个会话要求加载多条消息的情况(消息按照时间排序),我的思路是在group by, order by, limit这些关键字中寻找答案。
先在网络上寻找答案,寻找一些类似的实现,可惜都不理想。
有的实现就是把for循环转移到sql语句中,利用游标的概念,但是计算的数量级并没有下降,使用我本地的较大的数据量进行试验,执行时间过长。
或者是看到oracle数据库中有解决方案,但是需要使用关键字partition,这个应该是oracle数据看到经常会有类似的问题而提出的专用关键字。
对于mysql, sqlite等常用数据库,没法移植该实现。
最终我使用的方法是,
select * from xxx_table order by conversation, msgTime desc.
这样整个表单进行排序,首先按照会话名称进行排序,然后按照消息时间排序。
还剩下一个条件没有满足,就是每个会话消息的限定个数。
把个数的遍历放在外面实现,通过一个while循环将会话中超出limit部分的消息剔除。
伪码:
 cursor = db.EXEC('select * from xxx_table order by conversation, msgTime desc');  
  while (cursor.NEXT()) {  
       msg = msgFrom(cursor)  
IF (! msg belong TO conversation) {  
    // 消息不属于当前的会话,所以  
    conversation = NEW Conversation();  
    conversation.ADD(msg);  
    continue;  
}  
 
IF (conversation.msgSize() < LIMIT && msg belong TO conversation) {  
    conversation.ADD(msg);  
} ELSE {  
    // 消息个数已经超过会话消息限制  
    continue;  
}  
  }
这种方法的缺点是cursor会把整个表单都返回到用户空间,然后把所有的数据在用户空间都遍历一遍,有多余的操作。
不属于最优实现。
优点是两次排序使用order by,可以由数据库实现,这部分执行效率比较高,然后一次遍历cursor就执行完剩余操作,执行效率在接受范围之内,和改动之前相比效率提升至少一个数量级。
测试结果:一万条消息记录,一千个会话,执行时间大概4秒
补充一下,对于非数据库专业人员来说,有一点需要注意:
group by, order by, limit这些关键字在sql语句中有强制的顺序要求,limit , order by,都不能写到group by前面。
下面是我在寻找这个问题过程中看到的一些帖子,第一行是文章标题,后面是我看后的感受。如有冒犯,敬请原谅。
[SQL中Group分组获取Top N方法实现]
游标方法可取,网上讨论说运行比较慢。
[]一条SQL语句搞定分组并且每组限定记录集的数量]
仅适用于oracle
[]mysql实现每组取前N条记录的sql,以及后续的组数据量限制]
好像是可以,没看明白
[]SQL--分组显示数据,显示每组的前几行数据]
http://blog.163.com/peng_peng1 ... 0379/
像是答案,效率好像很低
[取每组前几条记录的SQL写法]
http://blog.sina.com.cn/s/blog ... .html
该页面提供两种方法,都尝试过,效率太低,杀掉程序时还没执行完
作者:李楠
继续阅读 »
IM通讯里面有两个重要的数据概念,一个是会话,一个是会话中的消息。
在系统初始化时,这两部分都要从数据库中加载到内存中。
11.png

数据组织结构是ConversatonManager包含多个会话,每个会话含有消息列表。
[datalist]
每次系统启动的时候,首先查询会话列表,然后对每一个会话加载其中的消息。对应的伪码
conversationList = db.loadConverstaions() 
FOR (conversation : conversationList) { 
db.loadMessages(conversation);
 }
因为每次查询都要涉及数据库操作,导致加载时间很长,而且大量的IO操作也会导致耗电量增加,
所以这部分加载过程,是我们优化的重点。
思路很简单:一条SQL语句做完所有事情,避免for循环,避免多次遍历数据库。
修改后的结构是:
conversationList = db.loadConverstaionsAndMessages()
这样大量的细节隐藏在SQL语句实现中。
这里面的实现有两种情况:
1. 一种是每个会话只加载一条消息记录。
2. 另一种是每个会话加载多条消息记录。
1. 每个会话只加载一条消息记录(假设是最后一条消息),这种情况可以使用关键字group by 处理:
select *, max(msgTime) from xxx_table group by conversation
这种情况比较好理解,而且网上类似的问题很多,很容易找到答案。
2. 对于每个会话要求加载多条消息的情况(消息按照时间排序),我的思路是在group by, order by, limit这些关键字中寻找答案。
先在网络上寻找答案,寻找一些类似的实现,可惜都不理想。
有的实现就是把for循环转移到sql语句中,利用游标的概念,但是计算的数量级并没有下降,使用我本地的较大的数据量进行试验,执行时间过长。
或者是看到oracle数据库中有解决方案,但是需要使用关键字partition,这个应该是oracle数据看到经常会有类似的问题而提出的专用关键字。
对于mysql, sqlite等常用数据库,没法移植该实现。
最终我使用的方法是,
select * from xxx_table order by conversation, msgTime desc.
这样整个表单进行排序,首先按照会话名称进行排序,然后按照消息时间排序。
还剩下一个条件没有满足,就是每个会话消息的限定个数。
把个数的遍历放在外面实现,通过一个while循环将会话中超出limit部分的消息剔除。
伪码:
 cursor = db.EXEC('select * from xxx_table order by conversation, msgTime desc');  
  while (cursor.NEXT()) {  
       msg = msgFrom(cursor)  
IF (! msg belong TO conversation) {  
    // 消息不属于当前的会话,所以  
    conversation = NEW Conversation();  
    conversation.ADD(msg);  
    continue;  
}  
 
IF (conversation.msgSize() < LIMIT && msg belong TO conversation) {  
    conversation.ADD(msg);  
} ELSE {  
    // 消息个数已经超过会话消息限制  
    continue;  
}  
  }
这种方法的缺点是cursor会把整个表单都返回到用户空间,然后把所有的数据在用户空间都遍历一遍,有多余的操作。
不属于最优实现。
优点是两次排序使用order by,可以由数据库实现,这部分执行效率比较高,然后一次遍历cursor就执行完剩余操作,执行效率在接受范围之内,和改动之前相比效率提升至少一个数量级。
测试结果:一万条消息记录,一千个会话,执行时间大概4秒
补充一下,对于非数据库专业人员来说,有一点需要注意:
group by, order by, limit这些关键字在sql语句中有强制的顺序要求,limit , order by,都不能写到group by前面。
下面是我在寻找这个问题过程中看到的一些帖子,第一行是文章标题,后面是我看后的感受。如有冒犯,敬请原谅。
[SQL中Group分组获取Top N方法实现]
游标方法可取,网上讨论说运行比较慢。
[]一条SQL语句搞定分组并且每组限定记录集的数量]
仅适用于oracle
[]mysql实现每组取前N条记录的sql,以及后续的组数据量限制]
好像是可以,没看明白
[]SQL--分组显示数据,显示每组的前几行数据]
http://blog.163.com/peng_peng1 ... 0379/
像是答案,效率好像很低
[取每组前几条记录的SQL写法]
http://blog.sina.com.cn/s/blog ... .html
该页面提供两种方法,都尝试过,效率太低,杀掉程序时还没执行完
作者:李楠 收起阅读 »

io操作中常见的几个概念

1. 概述
web应用中,io这块是一个重点,不同的策略对系统的性能影响很大.
对于io操作来说,用户线程发起io请求,内核负责完成此请求,并反馈结果,这两个角色之间需要进行协调:
1. 系统挂起用户线程,操作完成之后,系统返回结果,唤醒用户线程
2. 系统返回状态码,用户线程轮询结果,直到操作完成.
3. 用户线程发起请求时附带回调信息,内核接受请求后返回,用户线程执行别的逻辑;系统会在操作完成之后回调,有的系统自动创建新用户线程完成io处理,有的系统会利用已有的用户线程执行处理逻辑
4. 用户系统注册一个大的信号处理线程,用户线程发起请求后直接返回,系统在操作完成之后发送信号,信号处理线程接手处理.
可以看出,有的方式会造成线程挂起等待,有的会造成线程空转;一个线程好不容易等到系统分配了时间片,却又无奈的交出自己的时间片,浪费系统资源,我们的目标就是尽量少的线程,尽量少浪费线程的时间片,尽量少的线程切换,要做到这点,还是先来说说io中较常见的同步、异步、阻塞和非阻塞这几个概念.
2. 同步
我理解的io同步是指线程做io请求时需要等待内核将数据准备好,浪费了自己的cpu时间片.比如read,如果数据没准备好则线程直接挂起,浪费了一次线程调度;如果数据准备好了,需要将数据从内核空间拷贝到用户空间,可能分给自己1ms,结果等待拷贝数据花了了0.5ms,,实际只花费了0.5ms在业务上.
也有人是从当前线程是否需要等待处理结果来考量,当前线程需要等待,那就是同步,这个和我的观点实际没差别,到了异步这儿就不太一样,我们下面说.
3. 异步
与同步模式相反,异步模式下用户线程只需要注册相关信息,操作系统在操作完成后,将数据从内核空间拷贝到用户空间,然后根据注册信息通知用户进程处理io结果.整个流程中无需用户线程干预,用户线程可以充分利用分配给自己的时间.
有的io调用返回的是状态码,用户线程再根据状态码做相应的处理,但实际去做io操作时还是要主动的发起系统调用去获取数据,这是同步模型;还有的io操作是通过信号驱动,内核在操作完成后发送信号通知用户进程处理,用户进程捕获到信号后再发起系统调用去读取数据,实际上还是同步模式.
回到前面的问题,当前线程不等待io的操作结果这是否可以认为是异步?
我是这样想的,io数据从内核空间拷贝到用户空间这一步所花费的时间,不花在这个用户线程就花在别的用户线程,,总是消耗了用户线程的cpu时间片,除非由内核来驱动用户线程.
4. 阻塞
阻塞是指进行io操作时是否引起线程挂起,挂起了就是阻塞模式.很多时候会把同步和阻塞混淆,主要是因为同步一般都是由阻塞实现的.仔细想想,非阻塞也可以是同步,创建socket时如果指定BLOCK为false,那所有的操作都变成非阻塞,此时可能还是同步模式.
阻塞模式既有有点又有缺点,因为会阻塞,在请求不活跃时会节约cpu;因为会阻塞,也就造成了线程切换,也就浪费了cpu.
5. 非阻塞
没啥好说的,线程一路畅通无阻,看起来挺好,可如果忙着做状态检测,那就极大的浪费了cpu资源.
5 四种理论模型
同步异步,阻塞非阻塞,交叉组合,共有四种模型
5.1 同步阻塞
最经典的使用方式,最简单的,最喜欢的....
io操作会引起线程阻塞,只有系统准备好了时才会有返回,可以说不会浪费任何cpu资源.一般会有少量的线程接入请求,再来一个线程池处理接入的请求,简单有效.如果你的系统处理的连接不多,或者大部分不活跃,不用犹豫就它了.
在请求频繁时,同步阻塞会放大线程调度的成本,如果总得连接数超过线程池大小还会造成请求排队,此时还是尽早调整策略.
5.2 同步非阻塞
建立socket时,可以指定no block,此时所有的操作都会立刻返回,线程再根据返回值做相应的处理,这是一种轮询的方案,相比于同步阻塞,会多出若干次的系统调用,很不合算.
另外还有一种多路复用的io模式,线程先向内核注册若干个感兴趣的事件,然后一直等待,在某个或若干个事件符合条件后,内核将其打包返回,线程接到返回值,再去处理事件.
相比于直接在read/write上block住,同步阻塞多了一个获取事件的调用,因此相比于同步阻塞会有额外的系统开销;不过,因为一个线程可以同时监听多个连接,也就能一次处理若干个连接,在连接数较多时可以节约线程调度的成本,优势明显.
5.3 异步阻塞
这个没啥说的,略
5.4 异步非阻塞
用户线程先发起io请求,内核立刻返回,于是用户线程就可以做其它的事.在数据准备好之后,内核会将数据拷贝到用户空间,再给用户线程发送操作完成的通知.这个模型下,可以每个事件一个线程,也可以每个连接一个线程,相比于其他模式,能够最大化的节省线程数;另外,由于用户线程不需要去主动检查,每个用户线程都能用满自己的时间片,整个系统的性能值得期待.
理论说得这么好可别轻易动心,能用够用省力气才是王道,一般的用个同步阻塞就够了.真要用异步io,最好测测,以前的linux的异步io实现的不是太好,不知道现在啥状况了.
6 java中的模型
jdk一开始仅支持bio模式,也就是同步阻塞模式,在1.4中提供了nio,支持多路复用,1.7中又引入了aio,支持异步io.
作者:李春进
继续阅读 »
1. 概述
web应用中,io这块是一个重点,不同的策略对系统的性能影响很大.
对于io操作来说,用户线程发起io请求,内核负责完成此请求,并反馈结果,这两个角色之间需要进行协调:
1. 系统挂起用户线程,操作完成之后,系统返回结果,唤醒用户线程
2. 系统返回状态码,用户线程轮询结果,直到操作完成.
3. 用户线程发起请求时附带回调信息,内核接受请求后返回,用户线程执行别的逻辑;系统会在操作完成之后回调,有的系统自动创建新用户线程完成io处理,有的系统会利用已有的用户线程执行处理逻辑
4. 用户系统注册一个大的信号处理线程,用户线程发起请求后直接返回,系统在操作完成之后发送信号,信号处理线程接手处理.
可以看出,有的方式会造成线程挂起等待,有的会造成线程空转;一个线程好不容易等到系统分配了时间片,却又无奈的交出自己的时间片,浪费系统资源,我们的目标就是尽量少的线程,尽量少浪费线程的时间片,尽量少的线程切换,要做到这点,还是先来说说io中较常见的同步、异步、阻塞和非阻塞这几个概念.
2. 同步
我理解的io同步是指线程做io请求时需要等待内核将数据准备好,浪费了自己的cpu时间片.比如read,如果数据没准备好则线程直接挂起,浪费了一次线程调度;如果数据准备好了,需要将数据从内核空间拷贝到用户空间,可能分给自己1ms,结果等待拷贝数据花了了0.5ms,,实际只花费了0.5ms在业务上.
也有人是从当前线程是否需要等待处理结果来考量,当前线程需要等待,那就是同步,这个和我的观点实际没差别,到了异步这儿就不太一样,我们下面说.
3. 异步
与同步模式相反,异步模式下用户线程只需要注册相关信息,操作系统在操作完成后,将数据从内核空间拷贝到用户空间,然后根据注册信息通知用户进程处理io结果.整个流程中无需用户线程干预,用户线程可以充分利用分配给自己的时间.
有的io调用返回的是状态码,用户线程再根据状态码做相应的处理,但实际去做io操作时还是要主动的发起系统调用去获取数据,这是同步模型;还有的io操作是通过信号驱动,内核在操作完成后发送信号通知用户进程处理,用户进程捕获到信号后再发起系统调用去读取数据,实际上还是同步模式.
回到前面的问题,当前线程不等待io的操作结果这是否可以认为是异步?
我是这样想的,io数据从内核空间拷贝到用户空间这一步所花费的时间,不花在这个用户线程就花在别的用户线程,,总是消耗了用户线程的cpu时间片,除非由内核来驱动用户线程.
4. 阻塞
阻塞是指进行io操作时是否引起线程挂起,挂起了就是阻塞模式.很多时候会把同步和阻塞混淆,主要是因为同步一般都是由阻塞实现的.仔细想想,非阻塞也可以是同步,创建socket时如果指定BLOCK为false,那所有的操作都变成非阻塞,此时可能还是同步模式.
阻塞模式既有有点又有缺点,因为会阻塞,在请求不活跃时会节约cpu;因为会阻塞,也就造成了线程切换,也就浪费了cpu.
5. 非阻塞
没啥好说的,线程一路畅通无阻,看起来挺好,可如果忙着做状态检测,那就极大的浪费了cpu资源.
5 四种理论模型
同步异步,阻塞非阻塞,交叉组合,共有四种模型
5.1 同步阻塞
最经典的使用方式,最简单的,最喜欢的....
io操作会引起线程阻塞,只有系统准备好了时才会有返回,可以说不会浪费任何cpu资源.一般会有少量的线程接入请求,再来一个线程池处理接入的请求,简单有效.如果你的系统处理的连接不多,或者大部分不活跃,不用犹豫就它了.
在请求频繁时,同步阻塞会放大线程调度的成本,如果总得连接数超过线程池大小还会造成请求排队,此时还是尽早调整策略.
5.2 同步非阻塞
建立socket时,可以指定no block,此时所有的操作都会立刻返回,线程再根据返回值做相应的处理,这是一种轮询的方案,相比于同步阻塞,会多出若干次的系统调用,很不合算.
另外还有一种多路复用的io模式,线程先向内核注册若干个感兴趣的事件,然后一直等待,在某个或若干个事件符合条件后,内核将其打包返回,线程接到返回值,再去处理事件.
相比于直接在read/write上block住,同步阻塞多了一个获取事件的调用,因此相比于同步阻塞会有额外的系统开销;不过,因为一个线程可以同时监听多个连接,也就能一次处理若干个连接,在连接数较多时可以节约线程调度的成本,优势明显.
5.3 异步阻塞
这个没啥说的,略
5.4 异步非阻塞
用户线程先发起io请求,内核立刻返回,于是用户线程就可以做其它的事.在数据准备好之后,内核会将数据拷贝到用户空间,再给用户线程发送操作完成的通知.这个模型下,可以每个事件一个线程,也可以每个连接一个线程,相比于其他模式,能够最大化的节省线程数;另外,由于用户线程不需要去主动检查,每个用户线程都能用满自己的时间片,整个系统的性能值得期待.
理论说得这么好可别轻易动心,能用够用省力气才是王道,一般的用个同步阻塞就够了.真要用异步io,最好测测,以前的linux的异步io实现的不是太好,不知道现在啥状况了.
6 java中的模型
jdk一开始仅支持bio模式,也就是同步阻塞模式,在1.4中提供了nio,支持多路复用,1.7中又引入了aio,支持异步io.
作者:李春进 收起阅读 »

崩溃引发的思考:怎样才算真正的互联网技术公司?

阿里、携程接力两天的服务故障,沸腾了整个码农界。
看热闹都不怕事儿大。光纤被挖,引得异地双活被嘲讽,逼着支付宝最后有人出来打保票,年底我们一定搞完异地双活;线上服务被删更是报复论、Bug论频频,还出现了异司双活的崇拜,携程只是道了个歉,但是各种开人、睡人的小道消息也没停下。
热闹之余,人民群众也没闲着,纷纷忆苦思甜,言必称曾经。
这个说,“曾经我把数据库truncate了,老大当时不给解决方案只给目标,修了一晚上,期间各种惊心动魄,第二天恢复了竟然没人发现”。
那个说,“曾经有个新员工,没分清线上环境和测试环境,把线上数据库Rebuild了,导致某网站下线几小时”。(注:此次携程下线8个小时,据公开资料显示,其每宕机一秒会损失人民币5000元)
。。。
就像说起苦日子,都是自己小时候家里穷,你说你吃过糠我就说挖过树皮。事实上,大多数互联网服务都是7x24的,线上问题肯定是天天有。@TimYang 更是写过一篇黑天鹅来表达这种见怪不怪,见 http://timyang.net/service/black-swan-of-service/
这些苦又有什么可说呢?用来在自己遇到问题的某一天,聊以自慰么?
我们经常说,“吃一堑,长一智”,而我在每个团队里都在说的是,“真正聪明的人,可以从别人的问题里学到东西”。在我看来,更重要的其实在后面,后来又发生了什么?
依携程现在流言四出的状况,公关已然疯掉,明确的事故报告是很难了。但这不妨碍我们思考,要是发生在自己身上会发生什么?如果分析出来原因是程序Bug,如果原因是人为操作失误,如果是故意操作,结果会有区别么?我会在文后回答这个问题。
8.jpg

@左耳朵耗子 说得很直接
“技术上出故障是必然的。能否体现一个公司是技术公司,重要看这几点:1)故障的恢复是否有技术含量,2)公司对故障的处理方式,如果是通过加更多的流程,或是通过加更多的权限管控,或是通过处罚犯错误的人,或是上升到员工意识形态上,而不是去用更好的技术来解决,那么这个公司不会是个技术公司。”
但是遗憾的是,增加流程基本上算是大多数国产公司的首选,来个层层审批,更有甚者,来个线下审批什么的,让你一夜回到有纸办公的原始社会。
说一个前几天的故事。
我们服务升级,灰度部署一台机器后,把一个存储集群搞挂了。这件事的直接原因,是改了一行代码,没有压测就上了线。
服务最后通过降级扶住了,但是大家还是各出了一身汗,于是开会总结。总结的目的肯定是,如何避免同类事情的再次发生?有人提建议说,增加产品经理来做最后一级上线审批吧?
我当然是拒绝的。
为什么?我当然也知道增加审批的好处。首先,后续措施如果是加流程,那其实在暗示整个事情的发生受累于流程缺失,其他原因可以不再深究。
其次,再加一道审批,说明以后也不怕出问题了,因为最大的责任总会落在最后一个人身上,即使后面还是问题不断。
最后一点,对领导更有交待,如果你只是说Fix了一个服务的Bug,总有可能显得对问题不太上心,听起来也不太可靠。比较而言,增加流程就让人放心多了。
但是,我们聚在一起是为了做事,而不是为逃避责任不是吗?但是但是,人又是懒惰的。Larry Wall说,“好的程序员有三个宝贵品德,懒惰、没耐心和骄傲”。这话经过了一个又一个优秀的程序员的验证。
你要做事,又很懒惰。那除了让事情更快更好地完成,似乎别无他法。
加流程让事情更快了么?明显没有。每次服务上线多一层沟通,沟通意味着要协商另一个人的时间,然后你向他解释当前的情况。如果对方再不了解背景,那就足以让你崩溃死机了。
加流程让事情更好了么?没有。它对真正问题毫无益处,不幸的是,它还让整件事情变得更坏了。问题的根本原因在加流程的掩盖下蒙混过关,然后蠢蠢欲动在未来的某一天重新爆发。到了那时候,你依然需要分析整个事情,不同的是已经有了惯例,而这个惯例又会带来新的流程。
这就像纸尿裤。一个小孩尿了裤子,可以给他穿上纸尿裤。但是,健康成年人有穿的么?更危险的还在于,你不知道什么时候可以脱下来,因为是别人给你穿的,别人才不管你什么时候可以自禁了。
这也是很多公司为什么流程越来越重的原因,取消一个流程比增加一个流程要难得多。如果你能证明不需要一个流程也许在最开始就可以通过证明不增加它了。
回到总结会,我们又继续讨论了下去。经过复盘确认,当时的情况是,压测环境创建耗时费力,开发进度一再推迟下,经过团队讨论觉得没有问题,于是就跳过了压测步骤。
为什么可以跳过?因为整个技术团队都讨论了,评估这个压测可以不做(为什么我后文会讲)。这也是我拒绝产品经理审核的一个原因,因为他肯定没有技术了解整个服务,而风险管控最大的依据在于技术团队的评估。如果技术评估没有风险,他再来也是不会对结果有所改变的。
为什么决定这个压测不做了呢?因为我们两个负责人(本来也只有两个人),其中看了一眼文档(你没有看错),然后跟对方说似乎有个性能改进。另一个听到对方这么说,于是也看了一眼文档,下意识觉得那肯定是妥妥的了嘛。
这是什么鬼?思维惰性导致的循环依赖啊。实际上,只要再看一眼源代码,就知道不应该做这个改动了。但是两个人都没有去看,真是群愚的又一个例子。
选择不做压测,还有个原因,压测过程迟迟不能开展,而服务又着急上线。压测进展慢,因为压测没有计划,且在功能回归之后才进行。压测环境部署没有自动化,全部服务部署一次需要近十个小时,再跑完压测基本需要额外一天。而服务着急上线,是因为服务交付日期延迟了一周又一周。归根到底,整个团队研发效率的低下,已经导致完整流程跑不完了。
所以最后会议的决定变成了:
1. 确定压测步骤的必要性,再少的代码改动都不可以绕过;
2. 明确上线责任,而不是让责任继续分散,开发人员自己需要对新版本性能负责;
3. 提前制定压测计划,在服务开发完后立即进行压测,与功能测试同时进行;
4. 自动化压测环境部署,我们在云上构建服务,主机初始化和服务部署都使用脚本或管理工具自动化;
就在本文截稿之时,经过运维同事的努力,我们从零完整部署基准压测环境(支持100w同时在线)的时间,已经缩短到两小时以内。整个压测回归可以在三个小时内搞定。压测再也不是一个负担了。
当然研发效率的提高也在改进中,这是一个更大的话题稍后有机会再展开。
从这方面看,我们算一个技术公司么?我觉得是的,因为这样的公司里,不管遇到什么问题,技术的总会归技术。因为我们都相信,技术问题都可以通过技术解决。这句话也是对开始问题的回复。
所以亲爱的兄弟姐妹们,那个故障之后,你们得到的是流程还是技术改进呢?你们还好么?
9.jpg

如果有一天,你忽然发现,增加了太多流程,却依然做不好服务。请不要忘记,我们欢迎你。
作者: 梁宇鹏
继续阅读 »
阿里、携程接力两天的服务故障,沸腾了整个码农界。
看热闹都不怕事儿大。光纤被挖,引得异地双活被嘲讽,逼着支付宝最后有人出来打保票,年底我们一定搞完异地双活;线上服务被删更是报复论、Bug论频频,还出现了异司双活的崇拜,携程只是道了个歉,但是各种开人、睡人的小道消息也没停下。
热闹之余,人民群众也没闲着,纷纷忆苦思甜,言必称曾经。
这个说,“曾经我把数据库truncate了,老大当时不给解决方案只给目标,修了一晚上,期间各种惊心动魄,第二天恢复了竟然没人发现”。
那个说,“曾经有个新员工,没分清线上环境和测试环境,把线上数据库Rebuild了,导致某网站下线几小时”。(注:此次携程下线8个小时,据公开资料显示,其每宕机一秒会损失人民币5000元)
。。。
就像说起苦日子,都是自己小时候家里穷,你说你吃过糠我就说挖过树皮。事实上,大多数互联网服务都是7x24的,线上问题肯定是天天有。@TimYang 更是写过一篇黑天鹅来表达这种见怪不怪,见 http://timyang.net/service/black-swan-of-service/
这些苦又有什么可说呢?用来在自己遇到问题的某一天,聊以自慰么?
我们经常说,“吃一堑,长一智”,而我在每个团队里都在说的是,“真正聪明的人,可以从别人的问题里学到东西”。在我看来,更重要的其实在后面,后来又发生了什么?
依携程现在流言四出的状况,公关已然疯掉,明确的事故报告是很难了。但这不妨碍我们思考,要是发生在自己身上会发生什么?如果分析出来原因是程序Bug,如果原因是人为操作失误,如果是故意操作,结果会有区别么?我会在文后回答这个问题。
8.jpg

@左耳朵耗子 说得很直接
“技术上出故障是必然的。能否体现一个公司是技术公司,重要看这几点:1)故障的恢复是否有技术含量,2)公司对故障的处理方式,如果是通过加更多的流程,或是通过加更多的权限管控,或是通过处罚犯错误的人,或是上升到员工意识形态上,而不是去用更好的技术来解决,那么这个公司不会是个技术公司。”
但是遗憾的是,增加流程基本上算是大多数国产公司的首选,来个层层审批,更有甚者,来个线下审批什么的,让你一夜回到有纸办公的原始社会。
说一个前几天的故事。
我们服务升级,灰度部署一台机器后,把一个存储集群搞挂了。这件事的直接原因,是改了一行代码,没有压测就上了线。
服务最后通过降级扶住了,但是大家还是各出了一身汗,于是开会总结。总结的目的肯定是,如何避免同类事情的再次发生?有人提建议说,增加产品经理来做最后一级上线审批吧?
我当然是拒绝的。
为什么?我当然也知道增加审批的好处。首先,后续措施如果是加流程,那其实在暗示整个事情的发生受累于流程缺失,其他原因可以不再深究。
其次,再加一道审批,说明以后也不怕出问题了,因为最大的责任总会落在最后一个人身上,即使后面还是问题不断。
最后一点,对领导更有交待,如果你只是说Fix了一个服务的Bug,总有可能显得对问题不太上心,听起来也不太可靠。比较而言,增加流程就让人放心多了。
但是,我们聚在一起是为了做事,而不是为逃避责任不是吗?但是但是,人又是懒惰的。Larry Wall说,“好的程序员有三个宝贵品德,懒惰、没耐心和骄傲”。这话经过了一个又一个优秀的程序员的验证。
你要做事,又很懒惰。那除了让事情更快更好地完成,似乎别无他法。
加流程让事情更快了么?明显没有。每次服务上线多一层沟通,沟通意味着要协商另一个人的时间,然后你向他解释当前的情况。如果对方再不了解背景,那就足以让你崩溃死机了。
加流程让事情更好了么?没有。它对真正问题毫无益处,不幸的是,它还让整件事情变得更坏了。问题的根本原因在加流程的掩盖下蒙混过关,然后蠢蠢欲动在未来的某一天重新爆发。到了那时候,你依然需要分析整个事情,不同的是已经有了惯例,而这个惯例又会带来新的流程。
这就像纸尿裤。一个小孩尿了裤子,可以给他穿上纸尿裤。但是,健康成年人有穿的么?更危险的还在于,你不知道什么时候可以脱下来,因为是别人给你穿的,别人才不管你什么时候可以自禁了。
这也是很多公司为什么流程越来越重的原因,取消一个流程比增加一个流程要难得多。如果你能证明不需要一个流程也许在最开始就可以通过证明不增加它了。
回到总结会,我们又继续讨论了下去。经过复盘确认,当时的情况是,压测环境创建耗时费力,开发进度一再推迟下,经过团队讨论觉得没有问题,于是就跳过了压测步骤。
为什么可以跳过?因为整个技术团队都讨论了,评估这个压测可以不做(为什么我后文会讲)。这也是我拒绝产品经理审核的一个原因,因为他肯定没有技术了解整个服务,而风险管控最大的依据在于技术团队的评估。如果技术评估没有风险,他再来也是不会对结果有所改变的。
为什么决定这个压测不做了呢?因为我们两个负责人(本来也只有两个人),其中看了一眼文档(你没有看错),然后跟对方说似乎有个性能改进。另一个听到对方这么说,于是也看了一眼文档,下意识觉得那肯定是妥妥的了嘛。
这是什么鬼?思维惰性导致的循环依赖啊。实际上,只要再看一眼源代码,就知道不应该做这个改动了。但是两个人都没有去看,真是群愚的又一个例子。
选择不做压测,还有个原因,压测过程迟迟不能开展,而服务又着急上线。压测进展慢,因为压测没有计划,且在功能回归之后才进行。压测环境部署没有自动化,全部服务部署一次需要近十个小时,再跑完压测基本需要额外一天。而服务着急上线,是因为服务交付日期延迟了一周又一周。归根到底,整个团队研发效率的低下,已经导致完整流程跑不完了。
所以最后会议的决定变成了:
1. 确定压测步骤的必要性,再少的代码改动都不可以绕过;
2. 明确上线责任,而不是让责任继续分散,开发人员自己需要对新版本性能负责;
3. 提前制定压测计划,在服务开发完后立即进行压测,与功能测试同时进行;
4. 自动化压测环境部署,我们在云上构建服务,主机初始化和服务部署都使用脚本或管理工具自动化;
就在本文截稿之时,经过运维同事的努力,我们从零完整部署基准压测环境(支持100w同时在线)的时间,已经缩短到两小时以内。整个压测回归可以在三个小时内搞定。压测再也不是一个负担了。
当然研发效率的提高也在改进中,这是一个更大的话题稍后有机会再展开。
从这方面看,我们算一个技术公司么?我觉得是的,因为这样的公司里,不管遇到什么问题,技术的总会归技术。因为我们都相信,技术问题都可以通过技术解决。这句话也是对开始问题的回复。
所以亲爱的兄弟姐妹们,那个故障之后,你们得到的是流程还是技术改进呢?你们还好么?
9.jpg

如果有一天,你忽然发现,增加了太多流程,却依然做不好服务。请不要忘记,我们欢迎你。
作者: 梁宇鹏 收起阅读 »

回顾:电商抢滩618,Docker帮大忙!7个你不可错过的Docker分享!

618电商大战由来已久,巨大的数据和流量对于各电商平台来说,无疑是一项巨大挑战。如何在挑战中保证服务器的流畅和稳定,是这场大战胜负的关键性因素。Docker的出现正好能缓解这些因素,下边就盘点下几位全国顶级专家的Docker演讲,帮助你更全面系统的了解和学习Docker在云计算时代,开发者将应用转移到云上已经解决了硬件管理的问题,然而软件配置和管理相关的问题依然存在。Docker的出现正好能帮助软件开发者开阔思路,尝试新的软件管理方法来解决这个问题。通过掌握Docker,开发人员便可享受先进的自动化运维理念和工具,无需运维人员介入即可顺利运行于各种运行环境。
基于 Docker 的开发与运维一体化
1.png

平安健康互联网技术平台资深架构师 王延炯
Docker经过一段时间的发展,已快速进入以互联网公司为主的技术界。但对非互联网企业而言,传统业务复杂、IT设施薄弱、软件研发过程冗长,开发、测试、运维组织关系松散。应如何借鉴互联网企业经验,使得IT系统更好、更快速帮助企业开展业务、提升整体运营效率?本演讲将对比Docker与传统企业的IT过程,并以具体实践为参考,帮助传统企业向互联网化迈出探索性的一步。
基于Docker的云计算平台搭建实战
2.jpg

北京数人科技有限公司CTO 肖德时
CTO 肖德时在以往的云计算平台搭建过程,我们首选的解决方案是OpenStack解决方案,它非常成熟,让业界很放心。 随着新一代容器技术Docker生态圈的兴起,基于Docker的混合云计算平台搭建成为可能。我们为什么现在 这么需要容器技术,其原因是虚拟化计算已经把我们的网络环境从现实的物理机时代拉到虚拟机时代,部署在虚拟机上 的应用开始走向分布式架构,MicroService模式的应用越来越受到用户的喜爱。复杂的网络环境、软件环境让 开发者越来越无法承受。通过类似Docker技术,把内部构建、分发、部署都定制为统一的标准,正好是容器天然的优势。
Gaia—万台规模的Docker应用实战
3.jpg

腾讯数据平台部高级工程师 罗韩梅
作为底层的资源调度平台,Gaia(盖娅)能够让应用开发者像使用一台超级计算机一样使用整个集群,极大地简化了资源管理逻辑。Gaia提供高并发任务调度和资源管理,实现集群共享,具有高度可伸缩性和可靠性,能够支持MR等离线业务,甚至是实时计算、在线service业务。通过一系列的优化,Gaia可以支持到单cluster万台规模,毫秒级的作业下发效率以及更加完善的资源管理,同时,我们引入了弹性内存管理,增加了网络和磁盘带宽管理。Docker轻量、可移植、跨平台的特性将彻底改变程序的交付方式,并充分释放了虚拟化的威力,大有掀起一场容器革命之势。云计算、大数据经常意味着需要调动数据中心大量的资源,如何能够快速的匹配合适资源,需要一个聪明的“大脑”——Gaia。通过Docker on Gaia实现的Docker 云,将会让Docker的能量发挥到极致。
面向混合云的容器服务实践
4.jpg

IBM中国开发中心云平台服务部架构总监 杨博
演讲主要以企业应用与混合云的视角来审视容器技术,并分享IBM使用Docker容器技术来构建针对企业的混合云平台的实践与思考。通过本次分享将了解到企业应用在向云尤其是混合云迁移时会遇到哪些困难与挑战,而容器技术又是如何解决这些问题的,以及IBM云平台Bluemix里的容器服务是如何为用户带来提升的。
Docker在雪球的技术实践
5.png

球SRE团队高级工程师 高磊
基于Mesos和Docker的分布式计算
6.png

数人科技CEO 王璞
本次演讲主要介绍了如何基于Mesos和Docker搭建企业级分布式计算平台。Mesos和Docker都是最近非常热门的技术。国内企业使用Mesos的并不多,而国外主要是Twitter和Airbnb之类的新兴互联网公司在使用Mesos。Docker在2014年蓬勃发展,但是基于Docker真正开发企业应用的客户也并不多。基于Mesos和Docker打造的企业级分布式计算平台比Hadoop和Spark等常见分布式数据处理平台更具灵活性,能够处理实时请求、离线批处理请求、同构异构数据等等。
使用Docker构建项目
7.png

七牛任职七牛公司全栈架构师 李兆海
Docker的火热众所周知,那么到底该如何使用Docker来构建项目呢?本次演讲将分析利用Docker来构建项目可以解决哪些问题,以及分享七牛在使用Docker构建项目时的一些实践经验。
内容来源:StuQ
继续阅读 »
618电商大战由来已久,巨大的数据和流量对于各电商平台来说,无疑是一项巨大挑战。如何在挑战中保证服务器的流畅和稳定,是这场大战胜负的关键性因素。Docker的出现正好能缓解这些因素,下边就盘点下几位全国顶级专家的Docker演讲,帮助你更全面系统的了解和学习Docker在云计算时代,开发者将应用转移到云上已经解决了硬件管理的问题,然而软件配置和管理相关的问题依然存在。Docker的出现正好能帮助软件开发者开阔思路,尝试新的软件管理方法来解决这个问题。通过掌握Docker,开发人员便可享受先进的自动化运维理念和工具,无需运维人员介入即可顺利运行于各种运行环境。
基于 Docker 的开发与运维一体化
1.png

平安健康互联网技术平台资深架构师 王延炯
Docker经过一段时间的发展,已快速进入以互联网公司为主的技术界。但对非互联网企业而言,传统业务复杂、IT设施薄弱、软件研发过程冗长,开发、测试、运维组织关系松散。应如何借鉴互联网企业经验,使得IT系统更好、更快速帮助企业开展业务、提升整体运营效率?本演讲将对比Docker与传统企业的IT过程,并以具体实践为参考,帮助传统企业向互联网化迈出探索性的一步。
基于Docker的云计算平台搭建实战
2.jpg

北京数人科技有限公司CTO 肖德时
CTO 肖德时在以往的云计算平台搭建过程,我们首选的解决方案是OpenStack解决方案,它非常成熟,让业界很放心。 随着新一代容器技术Docker生态圈的兴起,基于Docker的混合云计算平台搭建成为可能。我们为什么现在 这么需要容器技术,其原因是虚拟化计算已经把我们的网络环境从现实的物理机时代拉到虚拟机时代,部署在虚拟机上 的应用开始走向分布式架构,MicroService模式的应用越来越受到用户的喜爱。复杂的网络环境、软件环境让 开发者越来越无法承受。通过类似Docker技术,把内部构建、分发、部署都定制为统一的标准,正好是容器天然的优势。
Gaia—万台规模的Docker应用实战
3.jpg

腾讯数据平台部高级工程师 罗韩梅
作为底层的资源调度平台,Gaia(盖娅)能够让应用开发者像使用一台超级计算机一样使用整个集群,极大地简化了资源管理逻辑。Gaia提供高并发任务调度和资源管理,实现集群共享,具有高度可伸缩性和可靠性,能够支持MR等离线业务,甚至是实时计算、在线service业务。通过一系列的优化,Gaia可以支持到单cluster万台规模,毫秒级的作业下发效率以及更加完善的资源管理,同时,我们引入了弹性内存管理,增加了网络和磁盘带宽管理。Docker轻量、可移植、跨平台的特性将彻底改变程序的交付方式,并充分释放了虚拟化的威力,大有掀起一场容器革命之势。云计算、大数据经常意味着需要调动数据中心大量的资源,如何能够快速的匹配合适资源,需要一个聪明的“大脑”——Gaia。通过Docker on Gaia实现的Docker 云,将会让Docker的能量发挥到极致。
面向混合云的容器服务实践
4.jpg

IBM中国开发中心云平台服务部架构总监 杨博
演讲主要以企业应用与混合云的视角来审视容器技术,并分享IBM使用Docker容器技术来构建针对企业的混合云平台的实践与思考。通过本次分享将了解到企业应用在向云尤其是混合云迁移时会遇到哪些困难与挑战,而容器技术又是如何解决这些问题的,以及IBM云平台Bluemix里的容器服务是如何为用户带来提升的。
Docker在雪球的技术实践
5.png

球SRE团队高级工程师 高磊
基于Mesos和Docker的分布式计算
6.png

数人科技CEO 王璞
本次演讲主要介绍了如何基于Mesos和Docker搭建企业级分布式计算平台。Mesos和Docker都是最近非常热门的技术。国内企业使用Mesos的并不多,而国外主要是Twitter和Airbnb之类的新兴互联网公司在使用Mesos。Docker在2014年蓬勃发展,但是基于Docker真正开发企业应用的客户也并不多。基于Mesos和Docker打造的企业级分布式计算平台比Hadoop和Spark等常见分布式数据处理平台更具灵活性,能够处理实时请求、离线批处理请求、同构异构数据等等。
使用Docker构建项目
7.png

七牛任职七牛公司全栈架构师 李兆海
Docker的火热众所周知,那么到底该如何使用Docker来构建项目呢?本次演讲将分析利用Docker来构建项目可以解决哪些问题,以及分享七牛在使用Docker构建项目时的一些实践经验。
内容来源:StuQ 收起阅读 »

传微软要收购Docker了,真的假的?

传微软要收购Docker!以目前Docker的市值来看,微软收购Docker绝对是绰绰有余。但微软收购Docker之后的意义是什么了?对于Docker而言又意味着什么了?
如果微软能成功收购Docker对于微软的Azure服务来说会是一个很好的举措,可以同时提高其在开源领域与容器领域的声望。
当然,如果微软还没有着手收购Docker的话,可能它马上要行动了。
这个迷人而大胆的举措是上周末微软CEO Satya Nadella爆出来的,他正在努力让Azure云成为商业云的一个不错选择;同时,使Azure成为容器运行与开源项目托管的“头等选择”也是其努力实现的目标。
Docker是一个开源的容器技术,它可以让用户将其应用程序打包,并以轻量级的方式将其运行在不同的基础设施(infrastructure)之上,而且可以保持部署上的最小配置变化。同时也不要混淆了,Docker还是一个有融资背景的初创公司,它曾经叫DotCloud,并将Docker容器技术进行商业化运作,而如今它已经价值10亿美金。
商业界对容器技术——一种新的虚拟化技术十分热衷,因为容器技术让部署应用程序变得更为简单,同时也使数据中心的运维更为顺畅。
Docker与微软这两家公司都没有对这个收购传闻做出回应,但是“容器圈子”对此事的评价是:微软会从这个收购案中抢占到容器领域的制高点;同时也可以使微软在容器领域不再“落后”于Google;而后者在容器领域已经发布了自己的容器管理服务——Kubernetes。
“Google虽然在容器方面与其它公司进行了广泛的合作,但是它还是在努力独吞这个市场。如果微软成功收购Docker,保持Docker开源并为其打造一个高质量的编排服务,微软就能既在舆论上也能在技术上获取成功,”一位行业内人士透露,“微软也在用Kubernetes,但是其肯定不会将自己的未来赌在Google的开源技术上,毕竟这些都不是自己的。”
微软与Google在公有云市场上是竞争对手,但是他们又都想挑战这个行业的龙头Amazon Web Service;当然他们互相竞争的领域还包括移动操作系统与搜索。
虽然Docker与微软达成协议确保Docker能在Azure上运行,但是,Docker这个春季刚刚加入10亿美元估值俱乐部的公司,同样跟其他平台提供商有相似的协议。
据投资领域专家称,Docker愿意出售,但是投资商不会将其以低于35亿美金的价格出售。尽管如此,微软还是能轻松在这个价位上买下 Docker,毕竟这家科技巨擎的现金储备达到了953亿美金。相比四月传出的流言——微软将以500亿美金收购Saleforce来说,这个数目还是相当便宜的。
对于Docker来说,这笔交易未尝不可。Docker尽管在开发圈子里已经十分流行——它的源代码已经累计下载了3亿次;但是它的核心产品也是开源的,也就是免费的,从一个侧面来说,Docker存在商业模式盈利的潜在问题。
但是Docker也在研发付费版本,这个版本将在容器安全方面有增强功能,同时也会加入很多企业级用户关心的功能。这个版本还处于预览版阶段,但是将会在下周的Docker开发者大会上作大力度宣传。同时,Docker还将发布能使Docker容器更容易的在大规模集群下安装部署与管理的特性;这些容器编排服务将使用户能同时管理调度多个容器,并最终为客户节约运维成本。
在容器编排服务领域,Docker的竞争对手像CoreOS与Mesosphere,还有前面介绍的Google Kubernetes,都是开源且免费的产品,他们也提供相似的功能与产品。一些分析师认为他们的产品在某种程度上要优于Docker最开始的水准。
一个投资者在四月Docker完成D轮9500万美金融资后说,相对于其他免费的容器服务,Docker跟他们竞争会很难,Docker的这个风险也是广泛认同的。
“显然Docker在商业模式上的风险会更大些,”Insight Venture Partners公司的Jeff Horing在对Docker完成D轮融资时也说。
同样也有人说微软与Docker什么都不会发生;对收购持消极态度者称:微软并不需要买下Docker,只需要跟Docker合作就能得到其想要的;其他反对者也说微软在管理开源项目缺乏经验,同时微软也在为Windows服务器引入容器,并兼容Docker。
Janakiram & Associates的创始人Janakiram说:“Windows是商业领域Linux唯一的替代品,微软会推自己的容器服务来支持Docker而不会卖Linux操作系统。”
但是,微软在Docker估值不断增加的时候买下Docker真的好吗?而且IBM与Red Hat会随时跳出来横刀夺爱,毕竟Red Hat也表示过“会尽一切可能将Docker揽入怀里。”
这个传闻会有另一个结果。就像拍卖一样,大家都会对Docker进行轮番报价,Docker的价值水涨船高,对Docker来说何乐而不为呢?
继续阅读 »
传微软要收购Docker!以目前Docker的市值来看,微软收购Docker绝对是绰绰有余。但微软收购Docker之后的意义是什么了?对于Docker而言又意味着什么了?
如果微软能成功收购Docker对于微软的Azure服务来说会是一个很好的举措,可以同时提高其在开源领域与容器领域的声望。
当然,如果微软还没有着手收购Docker的话,可能它马上要行动了。
这个迷人而大胆的举措是上周末微软CEO Satya Nadella爆出来的,他正在努力让Azure云成为商业云的一个不错选择;同时,使Azure成为容器运行与开源项目托管的“头等选择”也是其努力实现的目标。
Docker是一个开源的容器技术,它可以让用户将其应用程序打包,并以轻量级的方式将其运行在不同的基础设施(infrastructure)之上,而且可以保持部署上的最小配置变化。同时也不要混淆了,Docker还是一个有融资背景的初创公司,它曾经叫DotCloud,并将Docker容器技术进行商业化运作,而如今它已经价值10亿美金。
商业界对容器技术——一种新的虚拟化技术十分热衷,因为容器技术让部署应用程序变得更为简单,同时也使数据中心的运维更为顺畅。
Docker与微软这两家公司都没有对这个收购传闻做出回应,但是“容器圈子”对此事的评价是:微软会从这个收购案中抢占到容器领域的制高点;同时也可以使微软在容器领域不再“落后”于Google;而后者在容器领域已经发布了自己的容器管理服务——Kubernetes。
“Google虽然在容器方面与其它公司进行了广泛的合作,但是它还是在努力独吞这个市场。如果微软成功收购Docker,保持Docker开源并为其打造一个高质量的编排服务,微软就能既在舆论上也能在技术上获取成功,”一位行业内人士透露,“微软也在用Kubernetes,但是其肯定不会将自己的未来赌在Google的开源技术上,毕竟这些都不是自己的。”
微软与Google在公有云市场上是竞争对手,但是他们又都想挑战这个行业的龙头Amazon Web Service;当然他们互相竞争的领域还包括移动操作系统与搜索。
虽然Docker与微软达成协议确保Docker能在Azure上运行,但是,Docker这个春季刚刚加入10亿美元估值俱乐部的公司,同样跟其他平台提供商有相似的协议。
据投资领域专家称,Docker愿意出售,但是投资商不会将其以低于35亿美金的价格出售。尽管如此,微软还是能轻松在这个价位上买下 Docker,毕竟这家科技巨擎的现金储备达到了953亿美金。相比四月传出的流言——微软将以500亿美金收购Saleforce来说,这个数目还是相当便宜的。
对于Docker来说,这笔交易未尝不可。Docker尽管在开发圈子里已经十分流行——它的源代码已经累计下载了3亿次;但是它的核心产品也是开源的,也就是免费的,从一个侧面来说,Docker存在商业模式盈利的潜在问题。
但是Docker也在研发付费版本,这个版本将在容器安全方面有增强功能,同时也会加入很多企业级用户关心的功能。这个版本还处于预览版阶段,但是将会在下周的Docker开发者大会上作大力度宣传。同时,Docker还将发布能使Docker容器更容易的在大规模集群下安装部署与管理的特性;这些容器编排服务将使用户能同时管理调度多个容器,并最终为客户节约运维成本。
在容器编排服务领域,Docker的竞争对手像CoreOS与Mesosphere,还有前面介绍的Google Kubernetes,都是开源且免费的产品,他们也提供相似的功能与产品。一些分析师认为他们的产品在某种程度上要优于Docker最开始的水准。
一个投资者在四月Docker完成D轮9500万美金融资后说,相对于其他免费的容器服务,Docker跟他们竞争会很难,Docker的这个风险也是广泛认同的。
“显然Docker在商业模式上的风险会更大些,”Insight Venture Partners公司的Jeff Horing在对Docker完成D轮融资时也说。
同样也有人说微软与Docker什么都不会发生;对收购持消极态度者称:微软并不需要买下Docker,只需要跟Docker合作就能得到其想要的;其他反对者也说微软在管理开源项目缺乏经验,同时微软也在为Windows服务器引入容器,并兼容Docker。
Janakiram & Associates的创始人Janakiram说:“Windows是商业领域Linux唯一的替代品,微软会推自己的容器服务来支持Docker而不会卖Linux操作系统。”
但是,微软在Docker估值不断增加的时候买下Docker真的好吗?而且IBM与Red Hat会随时跳出来横刀夺爱,毕竟Red Hat也表示过“会尽一切可能将Docker揽入怀里。”
这个传闻会有另一个结果。就像拍卖一样,大家都会对Docker进行轮番报价,Docker的价值水涨船高,对Docker来说何乐而不为呢? 收起阅读 »

解读:开发者可以使用Docker做什么?

有些开发者可能还是不明白 Docker 对自己到底有多大的用处,因此翻译 Docker 个人用例 这篇文章中来介绍 Docker 在普通开发者开发过程中的用例。
f_9c4bfbc389e72fe6e6fdc3bdb7e5ce0f.jpg

Docker 如今赢得了许多关注,很多人觉得盛名之下其实难副,因为他们仍然搞不清 Docker 和普通开发者到底有什么关系。许多开发者觉得 Docker 离自己很远,Docker 是生产环境中的工具,和自己无关。我也是花了很长时间才想清楚作为普通开发人员如何在自己的开发中使用 Docker。坦率地说,我仍处在学习的过程中。
这篇文章提供了一个 Docker 用例列表,我希望它能更好地帮助你理解 Docker 并引发你的思考。本文只是描述 Docker 在普通开发者日常的应用,并不提供完整的解决方案。
在介绍用例之前,我希望你能先记住这句话:“Docker 是一个便携的应用容器”。你可以不知道 Docker 所说的的“便携式容器”到底是什么意思,但是你必须清楚 Docker 在日常中能带来非常大的效率提升。
当你需要在容器内运行自己的应用(当然可以是任何应用),Docker 都提供了一个基础系统镜像作为运行应用时的基础系统。也就是说,只要是 Linux 系统上的应用都可以运行在 Docker 中。
可以在 Docker 里面运行数据库吗?当然可以。
可以在 Docker 里面运行 Node.js 网站服务器吗?当然可以。
可以在 Docker 里面运行 API 服务器吗?当然可以。
Docker 并不在乎你的应用程序是什么、做什么,Docker 提供了一组应用打包、传输和部署的方法,以便你能更好地在容器内运行任何应用。
下面的例子我自己经常使用,当然你有更好的案例也可以分享给我。
尝试新软件
对开发者而言,每天会催生出的各式各样的新技术都需要尝试,然而开发者却不太可能为他们一一搭建好环境并进行测试。时间非常宝贵,正是得益于 Docker,让我们有可能在一条或者几条命令内就搭建完环境。Docker 有一个傻瓜化的获取软件的方法,Docker 后台会自动获得环境镜像并且运行环境。
并不仅仅是新技术环境搭建用得到 Docker。如果你想快速在你的笔记本上运行一个 MySQL 数据库,或者一个 Redis 消息队列,那么使用 Docker 便可以非常容易地做到。例如 Docker 只需要一条命令便可以运行 MySQL 数据库:docker run -d -p 3306:3306 tutum/mysql。
译者注:虽然使用命令也能非常快地安装 MySQL 数据库,但是当用到最新的技术或者非常复杂的技术时,使用 Docker 便会是个非常好的选择,例如 Gitlab,普通用户大概需要一天的时间去搭建 Gitlab 平台,而 Docker 则只需要一条命令。
进行演示
现在我经常需要在周末用自己开发的成果对客户活着别人做一两个演示。搭建演示环境的过程非常麻烦。现在我发现 Docker 已经成为我演示这些工具的最合理的方式。同时,对于客户来说,我可以直接将 Docker 镜像提供给他们,而不必去做任何环境配置的工作,工作的效果也会和在他们演示中所看到的一模一样,同时不必担心他们的环境配置会导致我们的产品无法运行。
避免“我机器上可以运行”
无论是上一篇介绍的企业部署 Docker 还是本文的个人 Docker 用例,都提到了这个情况。因为环境配置不同,很多人在开发中也会遇到这个情况,甚至开发的软件到了测试人员的机器上便不能运行。但这都不是重点。重点是,如果我们有一个可靠的、可分发的标准开发环境,那么我们的开发将不会像现在这么痛苦。Docker 便可以解决这个问题。Docker 镜像并不会因为环境的变化而不能运行,也不会在不同的电脑上有不同的运行结果。可以给测试人员提交含有应用的 Docker 镜像,这样便不再会发生“在我机器上是可以运行的”这种事情,很大程度上减轻了开发人员测试人员互相检查机器环境设置带来的时间成本。
另一个 Docker 可以发挥用处的地方是培训班。除了 Docker 容器的隔离性之外,更能体会到 Docker 优势的地方在于环境搭建。培训班的新手每个人都要在环境搭建上花费很多时间,但是如果在这里应用到 Docker 的话,那么我们只需要把标准的运行环境镜像分发下去,然后就可以开始上课了。使用 Docker 和使用虚拟机一样简单,但是 Docker 要更方便、更轻量级。同时,我们也可以告诉学员:“在培训的同时,我们还将学到当下最流行的技术——Docker”,这种双赢的结局,何乐而不为呢。
学习 Linux 脚本
当然这个原因看起来可能很奇怪,但是对不不熟悉 Linux 操作系统和 Shell 脚本的人来说,确实是一个好机会。即便本文并不是在讲 Linux,Linux 的重要度仍然不言而喻。如果你用的是 Windows,那么我给你一个建议:从云主机提供商那儿租用一台云主机:我推荐使用 CoreOS 系统的云主机。虽然这样并不会让你成为专业的 Linux 运维,但是可以让你快速地学到 Linux 基础知识,爱上命令行操作,并且慢慢开始熟悉和欣赏 Linux。
更好地利用资源
虚拟机的粒度是“虚拟出的机器”,而 Docker 的粒度则是“被限制的应用”,相比较而言 Docker 的内存占用更少,更加轻量级。
对我来说这是 Docker 的一个优势:因为我经常在自己电脑中运行多个 Docker 应用,使用 Docker 比使用虚拟机更加简单,方便,粒度更细,也能持续地跟踪容器状态。
为微服务定制
如果你一直在关注科技新闻的话,那么你应该听说过“微服务(Microservices)”的概念。Docker 可以很好地和微服务结合起来。从概念上来说,一个微服务便是一个提供一整套应用程序的部分功能,Docker 便可以在开发、测试和部署过程中一直充当微服务的容器。甚至生产环境也可以在 Docker 中部署微服务。
在云服务提供商之间移植
大多数的云主机提供商已经全面支持 Docker。对于开发人员来说,这表示你可以很方便地切换云服务提供商,当然也可以很方便地将你本地的开发环境移动到云主机上,不需要本地上配置一次运行环境、在云主机上还配置一次运行环境。全面部署 Docker (Docker here and Docker there) 作为标准运行环境可以极大地减轻应用上线时的工作量和产生 BUG。
API 端
API 是应用之间的粘合剂,一个合格开发者肯定使用过别人提供的 REST API,或者自己开发过 REST API。需要指出的是,无论是客户端还是 API 提供端,在开发之前都需要先定义一组公共的 API 接口,写成文档,然后才能进行编码。如果服务端和客户端是共同开发的话,那么服务端通常会先实现能返回固定字符串的 API 接口,在以后的开发中再慢慢去实现 API 的功能。
虽然有人会认为在这里 Docker 被滥用了,完全可以用 sample.json 这种文件去实现虚拟 API,但是下面有个实例可以更好地解决前后端分离开发时的 API 问题。
为了更好地解释我的意思,给大家提供一个实例:JSON Server,一个用于提供 JSON 数据的 REST API。使用过这个容器的人就会知道,既然有这么好用的 Docker JSON Server,我们没有理由不用 Docker。
译者注:
运行示例的 JSON Server,同时使用示例中提供的 JSON 文件,只需执行一条命令便可以创建一个服务端的 API 应用。
使用 curl http://127.0.0.1:80/posts 即可获取示例文件中的 posts 段,这样在后端没有开发完 API 的时候,前端一样可以进行协同开发。
技术的创新
这点应该算不上是用例,但是我还是来写一下。Docker 正在快速发展,工具也在不断更新,没有人能预见到未来 Docker 会是什么样子的。你在复杂的系统中 Docker 使用的越多,越是可能会发现技术上的空白和未来技术发展的方向。现在还处在 Docker 的发展期,任何你使用 Docker 创建的工具都有可能成为社区关注的热点。这是 Docker 的机会,也是成就你自己的机会。
你的用例
最后一条便不再是我的用例了,而是 Docker 在你手中能发挥多大的作用。我也很希望看到你能提供更多使用 Docker 的方式,欢迎留言。
其他
还有两个技巧可以分享给你们。在学习 Docker 的过程中因为有了这两个的帮助,我才得意不断地提升自己。
一:Docker Hub Registry。这是 Docker 的官方镜像仓库,除了托管着 Docker 官方的镜像外,和 Github 一样,你可以在上面上传自己的镜像,也可以在上面搜寻其他有用的镜像,极大地节省自己的时间。例如 Oracle-XE-11g 镜像,所有的一切都是现成的,完全不需要自己去下载 Oracle XE 11g 安装。这样为你和团队节约了大量的时间成本。
如果你不太确定的话,可以去 Docker Hub 上搜有一下有没有自己用得到的镜像。大部分情况下你所需要的镜像在 Docker Hub 上都已经有人构建了。
二:多参考 IaaS 供应商的新闻,虽然我们不能像在他们会议室里那样完全了解他们的公司动态,但是仍然可以从新闻中可以了解到 Docker 最新的发展方向和技术趋势。可以肯定的是,容器化技术是未来的热点,我们不仅可以在本机运行 Docker,不仅仅在一家云服务提供商的主机上运行 Docker,未来所有的云服务提供商都会支持 Docker。
Docker 前景很明确,采用 Docker 只会让开发变得更方便。
内容来源:OPEN资讯
继续阅读 »
有些开发者可能还是不明白 Docker 对自己到底有多大的用处,因此翻译 Docker 个人用例 这篇文章中来介绍 Docker 在普通开发者开发过程中的用例。
f_9c4bfbc389e72fe6e6fdc3bdb7e5ce0f.jpg

Docker 如今赢得了许多关注,很多人觉得盛名之下其实难副,因为他们仍然搞不清 Docker 和普通开发者到底有什么关系。许多开发者觉得 Docker 离自己很远,Docker 是生产环境中的工具,和自己无关。我也是花了很长时间才想清楚作为普通开发人员如何在自己的开发中使用 Docker。坦率地说,我仍处在学习的过程中。
这篇文章提供了一个 Docker 用例列表,我希望它能更好地帮助你理解 Docker 并引发你的思考。本文只是描述 Docker 在普通开发者日常的应用,并不提供完整的解决方案。
在介绍用例之前,我希望你能先记住这句话:“Docker 是一个便携的应用容器”。你可以不知道 Docker 所说的的“便携式容器”到底是什么意思,但是你必须清楚 Docker 在日常中能带来非常大的效率提升。
当你需要在容器内运行自己的应用(当然可以是任何应用),Docker 都提供了一个基础系统镜像作为运行应用时的基础系统。也就是说,只要是 Linux 系统上的应用都可以运行在 Docker 中。
可以在 Docker 里面运行数据库吗?当然可以。
可以在 Docker 里面运行 Node.js 网站服务器吗?当然可以。
可以在 Docker 里面运行 API 服务器吗?当然可以。
Docker 并不在乎你的应用程序是什么、做什么,Docker 提供了一组应用打包、传输和部署的方法,以便你能更好地在容器内运行任何应用。
下面的例子我自己经常使用,当然你有更好的案例也可以分享给我。
尝试新软件
对开发者而言,每天会催生出的各式各样的新技术都需要尝试,然而开发者却不太可能为他们一一搭建好环境并进行测试。时间非常宝贵,正是得益于 Docker,让我们有可能在一条或者几条命令内就搭建完环境。Docker 有一个傻瓜化的获取软件的方法,Docker 后台会自动获得环境镜像并且运行环境。
并不仅仅是新技术环境搭建用得到 Docker。如果你想快速在你的笔记本上运行一个 MySQL 数据库,或者一个 Redis 消息队列,那么使用 Docker 便可以非常容易地做到。例如 Docker 只需要一条命令便可以运行 MySQL 数据库:docker run -d -p 3306:3306 tutum/mysql。
译者注:虽然使用命令也能非常快地安装 MySQL 数据库,但是当用到最新的技术或者非常复杂的技术时,使用 Docker 便会是个非常好的选择,例如 Gitlab,普通用户大概需要一天的时间去搭建 Gitlab 平台,而 Docker 则只需要一条命令。
进行演示
现在我经常需要在周末用自己开发的成果对客户活着别人做一两个演示。搭建演示环境的过程非常麻烦。现在我发现 Docker 已经成为我演示这些工具的最合理的方式。同时,对于客户来说,我可以直接将 Docker 镜像提供给他们,而不必去做任何环境配置的工作,工作的效果也会和在他们演示中所看到的一模一样,同时不必担心他们的环境配置会导致我们的产品无法运行。
避免“我机器上可以运行”
无论是上一篇介绍的企业部署 Docker 还是本文的个人 Docker 用例,都提到了这个情况。因为环境配置不同,很多人在开发中也会遇到这个情况,甚至开发的软件到了测试人员的机器上便不能运行。但这都不是重点。重点是,如果我们有一个可靠的、可分发的标准开发环境,那么我们的开发将不会像现在这么痛苦。Docker 便可以解决这个问题。Docker 镜像并不会因为环境的变化而不能运行,也不会在不同的电脑上有不同的运行结果。可以给测试人员提交含有应用的 Docker 镜像,这样便不再会发生“在我机器上是可以运行的”这种事情,很大程度上减轻了开发人员测试人员互相检查机器环境设置带来的时间成本。
另一个 Docker 可以发挥用处的地方是培训班。除了 Docker 容器的隔离性之外,更能体会到 Docker 优势的地方在于环境搭建。培训班的新手每个人都要在环境搭建上花费很多时间,但是如果在这里应用到 Docker 的话,那么我们只需要把标准的运行环境镜像分发下去,然后就可以开始上课了。使用 Docker 和使用虚拟机一样简单,但是 Docker 要更方便、更轻量级。同时,我们也可以告诉学员:“在培训的同时,我们还将学到当下最流行的技术——Docker”,这种双赢的结局,何乐而不为呢。
学习 Linux 脚本
当然这个原因看起来可能很奇怪,但是对不不熟悉 Linux 操作系统和 Shell 脚本的人来说,确实是一个好机会。即便本文并不是在讲 Linux,Linux 的重要度仍然不言而喻。如果你用的是 Windows,那么我给你一个建议:从云主机提供商那儿租用一台云主机:我推荐使用 CoreOS 系统的云主机。虽然这样并不会让你成为专业的 Linux 运维,但是可以让你快速地学到 Linux 基础知识,爱上命令行操作,并且慢慢开始熟悉和欣赏 Linux。
更好地利用资源
虚拟机的粒度是“虚拟出的机器”,而 Docker 的粒度则是“被限制的应用”,相比较而言 Docker 的内存占用更少,更加轻量级。
对我来说这是 Docker 的一个优势:因为我经常在自己电脑中运行多个 Docker 应用,使用 Docker 比使用虚拟机更加简单,方便,粒度更细,也能持续地跟踪容器状态。
为微服务定制
如果你一直在关注科技新闻的话,那么你应该听说过“微服务(Microservices)”的概念。Docker 可以很好地和微服务结合起来。从概念上来说,一个微服务便是一个提供一整套应用程序的部分功能,Docker 便可以在开发、测试和部署过程中一直充当微服务的容器。甚至生产环境也可以在 Docker 中部署微服务。
在云服务提供商之间移植
大多数的云主机提供商已经全面支持 Docker。对于开发人员来说,这表示你可以很方便地切换云服务提供商,当然也可以很方便地将你本地的开发环境移动到云主机上,不需要本地上配置一次运行环境、在云主机上还配置一次运行环境。全面部署 Docker (Docker here and Docker there) 作为标准运行环境可以极大地减轻应用上线时的工作量和产生 BUG。
API 端
API 是应用之间的粘合剂,一个合格开发者肯定使用过别人提供的 REST API,或者自己开发过 REST API。需要指出的是,无论是客户端还是 API 提供端,在开发之前都需要先定义一组公共的 API 接口,写成文档,然后才能进行编码。如果服务端和客户端是共同开发的话,那么服务端通常会先实现能返回固定字符串的 API 接口,在以后的开发中再慢慢去实现 API 的功能。
虽然有人会认为在这里 Docker 被滥用了,完全可以用 sample.json 这种文件去实现虚拟 API,但是下面有个实例可以更好地解决前后端分离开发时的 API 问题。
为了更好地解释我的意思,给大家提供一个实例:JSON Server,一个用于提供 JSON 数据的 REST API。使用过这个容器的人就会知道,既然有这么好用的 Docker JSON Server,我们没有理由不用 Docker。
译者注:
运行示例的 JSON Server,同时使用示例中提供的 JSON 文件,只需执行一条命令便可以创建一个服务端的 API 应用。
使用 curl http://127.0.0.1:80/posts 即可获取示例文件中的 posts 段,这样在后端没有开发完 API 的时候,前端一样可以进行协同开发。
技术的创新
这点应该算不上是用例,但是我还是来写一下。Docker 正在快速发展,工具也在不断更新,没有人能预见到未来 Docker 会是什么样子的。你在复杂的系统中 Docker 使用的越多,越是可能会发现技术上的空白和未来技术发展的方向。现在还处在 Docker 的发展期,任何你使用 Docker 创建的工具都有可能成为社区关注的热点。这是 Docker 的机会,也是成就你自己的机会。
你的用例
最后一条便不再是我的用例了,而是 Docker 在你手中能发挥多大的作用。我也很希望看到你能提供更多使用 Docker 的方式,欢迎留言。
其他
还有两个技巧可以分享给你们。在学习 Docker 的过程中因为有了这两个的帮助,我才得意不断地提升自己。
一:Docker Hub Registry。这是 Docker 的官方镜像仓库,除了托管着 Docker 官方的镜像外,和 Github 一样,你可以在上面上传自己的镜像,也可以在上面搜寻其他有用的镜像,极大地节省自己的时间。例如 Oracle-XE-11g 镜像,所有的一切都是现成的,完全不需要自己去下载 Oracle XE 11g 安装。这样为你和团队节约了大量的时间成本。
如果你不太确定的话,可以去 Docker Hub 上搜有一下有没有自己用得到的镜像。大部分情况下你所需要的镜像在 Docker Hub 上都已经有人构建了。
二:多参考 IaaS 供应商的新闻,虽然我们不能像在他们会议室里那样完全了解他们的公司动态,但是仍然可以从新闻中可以了解到 Docker 最新的发展方向和技术趋势。可以肯定的是,容器化技术是未来的热点,我们不仅可以在本机运行 Docker,不仅仅在一家云服务提供商的主机上运行 Docker,未来所有的云服务提供商都会支持 Docker。
Docker 前景很明确,采用 Docker 只会让开发变得更方便。
内容来源:OPEN资讯 收起阅读 »

没有头像的发帖人不是好的开发者

有没有头像,是衡量提问者是否对回复者尊重的标志
有没有头像,是衡量提问者是否专业的标志
有没有头像,是衡量提问者是不是有耐心的标志
有没有头像,是衡量提问者是不是电脑里存了头像的标志
有没有头像,是衡量提问者有没有获得20积分的标志
 
(有人接下去么......)
继续阅读 »
有没有头像,是衡量提问者是否对回复者尊重的标志
有没有头像,是衡量提问者是否专业的标志
有没有头像,是衡量提问者是不是有耐心的标志
有没有头像,是衡量提问者是不是电脑里存了头像的标志
有没有头像,是衡量提问者有没有获得20积分的标志
 
(有人接下去么......) 收起阅读 »

基于Mesos和Docker的分布式计算平台

Docker及其相关技术的出现和发展,给大规模集群管理带来了新的想象空间。如何将二者进行有效地结合?本文将介绍数人科技基于Mesos和Docker的分布式计算平台的实践。
针对“互联网+”时代的业务增长、变化速度及大规模计算的需求,廉价的、高可扩展的分布式x86集群已成为标准解决方案,如Google已经在几千万台服务器上部署分布式系统。Docker及其相关技术的出现和发展,又给大规模集群管理带来了新的想象空间。如何将二者进行有效地结合?本文将介绍数人科技基于Mesos和Docker的分布式计算平台的实践。
分布式系统设计准则可伸缩性
首先分布式系统一定是大规模的系统,有很好的Scalability。出于成本的考虑,很多大规模的分布式系统一般采用廉价的PC服务器,而不是大型的高性能服务器。没有单点失效
廉价的PC服务器在大规模使用中经常会遇到各种各样的问题,PC服务器的硬件不可能是高可靠的,比如Google的数据中心每天都会有大量的硬盘失效,所以分布式系统一定要对硬件容错,保证没有任何的单点失效。在这种很不稳定、很不可靠的硬件计算环境下,搭建一个分布式系统提供高可靠服务,必须要通过软件来容错。分布式系统针对不允许有单点失效的要求有两方面的设计考虑,一种是服务类的企业级应用,每个服务后台实例都要有多个副本,一两台硬件故障不至于影响所有服务实例;另外一种数据存储的应用,每份数据也必须要有多个备份,保证即使某几个硬件坏掉了数据也不会丢失。
高可靠性
除了单点失效,还要保证高可靠性。在分布式环境下,针对企业级服务应用,要做负载均衡和服务发现来保证高可靠性;针对数据服务,为了做到高可靠性,首先要按照某种算法来把整体数据分片(因为一台服务器装不下),然后按照同样的算法来进行分片查找。
数据本地性
再一个分布式设计理念是数据本地性,因为网络通信开销是分布式系统的瓶颈,要减少网络开销,应当让计算任务去找数据,而不是让数据去找计算。
分布式系统与Linux操作系统的比较
由于纵向拓展可优化空间太小(单台服务器的性能上限很明显),分布式系统强调横向扩展、横向优化,当分布式集群计算资源不足时,就要往集群里面添加服务器,来不停地提升分布式集群的计算能力。分布式系统要做到统一管理集群的所有服务器,屏蔽底层管理细节,诸如容错、调度、通信等,让开发人员觉得分布式集群在逻辑上是一台服务器。
和单机Linux操作系统相比,虽然分布式系统还没有成熟到成为“分布式操作系统”,但它和单机Linux一样要解决五大类操作系统必需的功能,即资源分配、进程管理、任务调度、进程间通信(IPC)和文件系统,可分别由Mesos、Docker、Marathon/Chronos、RabbitMQ和HDFS/Ceph来解决,对应于Linux下的Linux Kernel、Linux Kernel、init.d/cron、Pipe/Socket和ext4,如图1所示。
1.jpg

图1 分布式系统与Linux操作系统的比较 
基于Mesos的分布式计算平台
Mesos资源分配原理
目前我们的Mesos集群部署在公有云服务上,用100多台虚拟机组成Mesos集群。Mesos不要求计算节点是物理服务器还是虚拟服务器,只要是Linux操作系统就可以。Mesos可以理解成一个分布式的Kernel,只分配集群计算资源,不负责任务调度。基于Mesos之上可以运行不同的分布式计算平台,如Spark、Storm、Hadoop、Marathon和Chronos等。Spark、Storm和Hadoop这样的计算平台有任务调度功能,可以直接使用Mesos SDK跟Mesos请求资源,然后自行调度计算任务,并对硬件容错。Marathon针对服务型分布式应用提供任务调度,比如企业网站等这类需要长时间运行的服务。通常网站应用程序没有任务调度和容错能力,因为网站程序不太会处理某个后台实例挂掉以后要在哪台机器上重新恢复等这类复杂问题。这类没有任务调度能力的服务型分布式应用,可以由Marathon来负责调度。比如,Marathon调度执行了网站服务的一百个后台实例,如果某个实例挂掉了,Marathon会在其他服务器上把这个实例恢复起来。Chronos是针对分布式批处理应用提供任务调度,比如定期处理日志或者定期调Hadoop等离线任务。
Mesos最大的好处是能够对分布式集群做细粒度资源分配。如图2所示,左边是粗粒的资源分配,右边是细粒的资源分配。
2.jpg

图2 Mesos资源调度的两种方式
图2左边有三个集群,每个集群三台服务器,分别装三种分布式计算平台,比如上面装三台Hadoop,中间三台是Spark,下面三台是Storm,三个不同的框架分别进行管理。右边是Mesos集群统一管理9台服务器,所有来自Spark、Hadoop或Storm的任务都在9台服务器上混合运行。Mesos首先提高了资源冗余率。粗粒资源管理肯定带来一定的浪费,细粒的资源提高资源管理能力。Hadoop机器很清闲,Spark没有安装,但Mesos可以只要任何一个调度马上响应。最后一个还有数据稳定性,因为所有9台都被Mesos统一管理,假如说装的Hadoop,Mesos会集群调度。这个计算资源都不共享,存储之间也不好共享。如果这上面跑了Spark做网络数据迁移,显然很影响速度。然后资源分配的方法就是resource offers,是在窗口的可调度的资源自己去选,Mesos是Spark或者是Hadoop等等。这种方法,Mesos的分配逻辑就很简单,只要不停地报告哪些是可用资源就可以了。Mesos资源分配方法也有一个潜在的缺点,就是无中心化的分配方式,所以有可能不会带来全局最优的方式。但这个数据资源缺点对目前来讲并不是很严重。现在一个计算中心资源贡献率很难达到50%,绝大部分计算中心都是很闲的状态。
Mesos资源分配示例
下面具体举例说明怎么用Mesos资源分配。如图3所示,中间是Mesos Master,下面是Mesos Slave,上面是Spark和Hadoop运行在Mesos之上。Mesos Master把可用资源报告给Spark或Hadoop。假定Hadoop有一个任务想运行,Hadoop从Mesos Master上报的可用资源中选择某个Mesos Slave节点,然后这个任务就会在这个Mesos Slave节点上执行,这是任务完成一次资源分配,接下来Mesos Master继续进行资源分配。
3.jpg

任务调度
Mesos只做一件事情,就是分布式集群资源分配,不管任务调度。Marathon和Chonos是基于Mesos来做任务调度。如图4所示,Mesos集群混合运行来自Marathon和Chronos的不同类型的任务。Marathon和Chonos基于Mesos做任务调度时,一定是动态调度,也就是每个任务在执行之前是不知道它将来在哪一台服务器上执行和绑定哪一个端口。如图5所示,9台服务器组成的Mesos集群上混合运行各种Marathon调度的任务,中间一台服务器坏掉以后,这台服务器上的两个任务就受影响,然后Marathon把这两个任务迁移到其他服务器上,这就是动态任务调度带来的好处,非常容易实现容错。
4.jpg

图4 Mesos集群运行不同类型的任务
5.jpg

图5 Marathon动态任务调度
为了减少硬件故障对应用服务的影响,应用程序要尽量做到无状态。无状态的好处是在程序受到影响时不需要进行任何恢复,这样这个程序只要重新调度起来就可以。无状态要求把状态数据放到存储服务器或者是消息队列里面,这样的好处是容错时恢复起来会变得很方便。
服务类的高可靠性
对于服务类型的任务,分布式环境保证服务的高可靠性,这需要负载均衡和服务发现。在分布式环境下做负载均衡有一个难点就是后台这些实例有可能发生动态变化,比如说某一个节点坏掉了,这个节点上的实例会受到影响,然后迁移到其他节点上。然而传统负载均衡器的后台实例地址端口都是静态的。所以在分布式环境下,为了做负载均衡一定要做服务发现。比如,某个服务之前有四个事例,现在新添加了两个实例,需要告诉负载均衡器新增加的实例的地址和端口。服务发现的过程是由几个模块配合完成,比如说Marathon给某个服务增加了新的实例,把新调度的实例地址端口写到Zookeeper,然后Bamboo把Zookeeper里存放的该服务新的实例的地址端口信息告诉负载均衡器,这样负载均衡器就知道新的实例地址端口,完成了服务发现。
数据类的高可靠性
对于服务类型的应用,分布式系统用负载均衡器和服务发现来保证高可靠性的服务。对于数据类型的应用,分布式系统同样要保证高可靠的数据服务。首先要做数据分片,一台服务器存不下所有数据就分成多份来存,但对数据进行分片必须按照某个规则来进行分片,后面查找时要按照同样的规则来进行分片查找,就是一致性。假定最原始的方案我们用Hash计算做成方法,在线性空间上分了三份以后,我要在数据分成三块机器来存,三台机器都存满了时,再把数据进行分配的时候不再把它分配到直线线性空间上,而是把它分配到环状空间上,把起点和终点连接起来,连成一个数据环,如图6所示,这样相应的数据点就放在这一块。如果要添加一个新的数据中心就在环上新切出来这块,这样很方便,切出来这一部分代表这一部分数据都应该放到新的芯片上,所以把原来子数据分片挪到嵌入式的分片上。
6.jpg

图6 数据分片
还有可能删除数据,我们把黄色的数据放到红色的数据上,这是环的好处。实际为了做到高可靠性,任何一个数据可能假定映射到黄色部分以后,这些黄色的部分只要映射到任何一个黄色的区域都会存在同一片机器上,同一片机器底层会有多个副本和做数据的备份,这是实际数据分片的一个实例。这是怎么做数据的高可靠性。这些数据分片,还有负载均衡,都是为了对应分布式分片硬件带来的不可靠和失效,这是我们用分布式系统最大的特点。
基于Docker的分布式计算平台
Docker工作流
我们主要用Docker来做分布式环境下的进程管理。Docker工作流如图7所示,我们不仅把Docker应用到生产阶段,也应用到开发阶段,所以我们每天编辑Dockerfile,提升Docker Images,测试上线,发Docker镜像,在我们内部私有Docker regis里面,再调到我们Docker集群生产环境里面,这和其他的Docker工作流没有什么区别。
7.jpg

在Mesos提交Docker任务
因为Mesos和Docker已经是无缝结合起来。通过Marathon和Chronos提交服务型应用和批处理型应用。Marathon和Chronos通过RESTful的方式提交任务,用JSON脚本设定应用的后台实例个数、应用的参数、以及Docker Images的路径等等。
分布式环境下的进程通信
在分布式环境下应用服务之间通信,是用分布式消息队列来做,我们用的是RabbitMQ。RabbitMQ也是一个分布式系统,它也要保证高可靠性、解决容错的问题。首先RabbitMQ也有集群,如图8所示,六个节点组成了一个RabbitMQ的集群,每个节点之间是互为备份的关系,任何一个坏掉,其他五个还可以提供服务,通过冗余来保证RabbitMQ的高可靠性。
8.jpg

图8 RabbitMQ集群
其次,RabbitMQ也有数据分片机制。因为消息队列有可能很长,长到所有的消息不可能都放到一个节点上,这时就要用分片,把很长的消息队列分为几段,分别放到不同的节点上。如图9所示是RabbitMQ的联盟机制,把一个消息队列打成两段,一段放在上游一段放在下游,假定下游消息队列的消息被消费完了就自动把上游消息队列里的消息移到下游,这样一个消息队列变成非常长的时候也不怕,分片到多个节点上即可。
9.jpg

图9 消息队列分片
分布式文件系统
最后讲一下分布式文件系统HDFS和Ceph。Hadoop文件系统HDFS,如图10所示,每个数据块有三个备份,必须放在不同的服务器上,而且三个备份里面每个机架最多放两份,这么做也是为了容错。Ceph是另一种流行的开源分布式文件系统。Ceph把网络存储设备抽象成一张逻辑硬盘,然后“挂载”到分布式集群的每台服务器上,原理上非常像是Linux操作系统Mount一块物理硬盘。这样一来,用户程序访问Ceph的文件系统就跟访问Linux本地路径一样,非常方便。
10.jpg

分布式环境下的监控
分布式环境下,程序不是运行在本地,而是在集群上面,没有监控就等于程序运行在黑盒子下,无法调优,必须要有监控。分布式环境下的监控分为两个部分,一是性能监控,另一个是报警。性能监控要知道每个应用程序运行状态是什么样,即每一个应用程序占了多少CPU内存、服务的请求处理延迟等。我们是用Graphite来做应用程序性能监控;还有其他系统,比如MongoDB、Hadoop等开源系统,我们用Ganglia来做性能监控,比如CPU内存硬盘的使用情况等。报警是要在关键服务出现故障时,通知开发运维人员及时排解故障,我们用Zabbix来做报警。(责编/周建丁)
内容来源:《程序员》
继续阅读 »
Docker及其相关技术的出现和发展,给大规模集群管理带来了新的想象空间。如何将二者进行有效地结合?本文将介绍数人科技基于Mesos和Docker的分布式计算平台的实践。
针对“互联网+”时代的业务增长、变化速度及大规模计算的需求,廉价的、高可扩展的分布式x86集群已成为标准解决方案,如Google已经在几千万台服务器上部署分布式系统。Docker及其相关技术的出现和发展,又给大规模集群管理带来了新的想象空间。如何将二者进行有效地结合?本文将介绍数人科技基于Mesos和Docker的分布式计算平台的实践。
分布式系统设计准则可伸缩性
首先分布式系统一定是大规模的系统,有很好的Scalability。出于成本的考虑,很多大规模的分布式系统一般采用廉价的PC服务器,而不是大型的高性能服务器。没有单点失效
廉价的PC服务器在大规模使用中经常会遇到各种各样的问题,PC服务器的硬件不可能是高可靠的,比如Google的数据中心每天都会有大量的硬盘失效,所以分布式系统一定要对硬件容错,保证没有任何的单点失效。在这种很不稳定、很不可靠的硬件计算环境下,搭建一个分布式系统提供高可靠服务,必须要通过软件来容错。分布式系统针对不允许有单点失效的要求有两方面的设计考虑,一种是服务类的企业级应用,每个服务后台实例都要有多个副本,一两台硬件故障不至于影响所有服务实例;另外一种数据存储的应用,每份数据也必须要有多个备份,保证即使某几个硬件坏掉了数据也不会丢失。
高可靠性
除了单点失效,还要保证高可靠性。在分布式环境下,针对企业级服务应用,要做负载均衡和服务发现来保证高可靠性;针对数据服务,为了做到高可靠性,首先要按照某种算法来把整体数据分片(因为一台服务器装不下),然后按照同样的算法来进行分片查找。
数据本地性
再一个分布式设计理念是数据本地性,因为网络通信开销是分布式系统的瓶颈,要减少网络开销,应当让计算任务去找数据,而不是让数据去找计算。
分布式系统与Linux操作系统的比较
由于纵向拓展可优化空间太小(单台服务器的性能上限很明显),分布式系统强调横向扩展、横向优化,当分布式集群计算资源不足时,就要往集群里面添加服务器,来不停地提升分布式集群的计算能力。分布式系统要做到统一管理集群的所有服务器,屏蔽底层管理细节,诸如容错、调度、通信等,让开发人员觉得分布式集群在逻辑上是一台服务器。
和单机Linux操作系统相比,虽然分布式系统还没有成熟到成为“分布式操作系统”,但它和单机Linux一样要解决五大类操作系统必需的功能,即资源分配、进程管理、任务调度、进程间通信(IPC)和文件系统,可分别由Mesos、Docker、Marathon/Chronos、RabbitMQ和HDFS/Ceph来解决,对应于Linux下的Linux Kernel、Linux Kernel、init.d/cron、Pipe/Socket和ext4,如图1所示。
1.jpg

图1 分布式系统与Linux操作系统的比较 
基于Mesos的分布式计算平台
Mesos资源分配原理
目前我们的Mesos集群部署在公有云服务上,用100多台虚拟机组成Mesos集群。Mesos不要求计算节点是物理服务器还是虚拟服务器,只要是Linux操作系统就可以。Mesos可以理解成一个分布式的Kernel,只分配集群计算资源,不负责任务调度。基于Mesos之上可以运行不同的分布式计算平台,如Spark、Storm、Hadoop、Marathon和Chronos等。Spark、Storm和Hadoop这样的计算平台有任务调度功能,可以直接使用Mesos SDK跟Mesos请求资源,然后自行调度计算任务,并对硬件容错。Marathon针对服务型分布式应用提供任务调度,比如企业网站等这类需要长时间运行的服务。通常网站应用程序没有任务调度和容错能力,因为网站程序不太会处理某个后台实例挂掉以后要在哪台机器上重新恢复等这类复杂问题。这类没有任务调度能力的服务型分布式应用,可以由Marathon来负责调度。比如,Marathon调度执行了网站服务的一百个后台实例,如果某个实例挂掉了,Marathon会在其他服务器上把这个实例恢复起来。Chronos是针对分布式批处理应用提供任务调度,比如定期处理日志或者定期调Hadoop等离线任务。
Mesos最大的好处是能够对分布式集群做细粒度资源分配。如图2所示,左边是粗粒的资源分配,右边是细粒的资源分配。
2.jpg

图2 Mesos资源调度的两种方式
图2左边有三个集群,每个集群三台服务器,分别装三种分布式计算平台,比如上面装三台Hadoop,中间三台是Spark,下面三台是Storm,三个不同的框架分别进行管理。右边是Mesos集群统一管理9台服务器,所有来自Spark、Hadoop或Storm的任务都在9台服务器上混合运行。Mesos首先提高了资源冗余率。粗粒资源管理肯定带来一定的浪费,细粒的资源提高资源管理能力。Hadoop机器很清闲,Spark没有安装,但Mesos可以只要任何一个调度马上响应。最后一个还有数据稳定性,因为所有9台都被Mesos统一管理,假如说装的Hadoop,Mesos会集群调度。这个计算资源都不共享,存储之间也不好共享。如果这上面跑了Spark做网络数据迁移,显然很影响速度。然后资源分配的方法就是resource offers,是在窗口的可调度的资源自己去选,Mesos是Spark或者是Hadoop等等。这种方法,Mesos的分配逻辑就很简单,只要不停地报告哪些是可用资源就可以了。Mesos资源分配方法也有一个潜在的缺点,就是无中心化的分配方式,所以有可能不会带来全局最优的方式。但这个数据资源缺点对目前来讲并不是很严重。现在一个计算中心资源贡献率很难达到50%,绝大部分计算中心都是很闲的状态。
Mesos资源分配示例
下面具体举例说明怎么用Mesos资源分配。如图3所示,中间是Mesos Master,下面是Mesos Slave,上面是Spark和Hadoop运行在Mesos之上。Mesos Master把可用资源报告给Spark或Hadoop。假定Hadoop有一个任务想运行,Hadoop从Mesos Master上报的可用资源中选择某个Mesos Slave节点,然后这个任务就会在这个Mesos Slave节点上执行,这是任务完成一次资源分配,接下来Mesos Master继续进行资源分配。
3.jpg

任务调度
Mesos只做一件事情,就是分布式集群资源分配,不管任务调度。Marathon和Chonos是基于Mesos来做任务调度。如图4所示,Mesos集群混合运行来自Marathon和Chronos的不同类型的任务。Marathon和Chonos基于Mesos做任务调度时,一定是动态调度,也就是每个任务在执行之前是不知道它将来在哪一台服务器上执行和绑定哪一个端口。如图5所示,9台服务器组成的Mesos集群上混合运行各种Marathon调度的任务,中间一台服务器坏掉以后,这台服务器上的两个任务就受影响,然后Marathon把这两个任务迁移到其他服务器上,这就是动态任务调度带来的好处,非常容易实现容错。
4.jpg

图4 Mesos集群运行不同类型的任务
5.jpg

图5 Marathon动态任务调度
为了减少硬件故障对应用服务的影响,应用程序要尽量做到无状态。无状态的好处是在程序受到影响时不需要进行任何恢复,这样这个程序只要重新调度起来就可以。无状态要求把状态数据放到存储服务器或者是消息队列里面,这样的好处是容错时恢复起来会变得很方便。
服务类的高可靠性
对于服务类型的任务,分布式环境保证服务的高可靠性,这需要负载均衡和服务发现。在分布式环境下做负载均衡有一个难点就是后台这些实例有可能发生动态变化,比如说某一个节点坏掉了,这个节点上的实例会受到影响,然后迁移到其他节点上。然而传统负载均衡器的后台实例地址端口都是静态的。所以在分布式环境下,为了做负载均衡一定要做服务发现。比如,某个服务之前有四个事例,现在新添加了两个实例,需要告诉负载均衡器新增加的实例的地址和端口。服务发现的过程是由几个模块配合完成,比如说Marathon给某个服务增加了新的实例,把新调度的实例地址端口写到Zookeeper,然后Bamboo把Zookeeper里存放的该服务新的实例的地址端口信息告诉负载均衡器,这样负载均衡器就知道新的实例地址端口,完成了服务发现。
数据类的高可靠性
对于服务类型的应用,分布式系统用负载均衡器和服务发现来保证高可靠性的服务。对于数据类型的应用,分布式系统同样要保证高可靠的数据服务。首先要做数据分片,一台服务器存不下所有数据就分成多份来存,但对数据进行分片必须按照某个规则来进行分片,后面查找时要按照同样的规则来进行分片查找,就是一致性。假定最原始的方案我们用Hash计算做成方法,在线性空间上分了三份以后,我要在数据分成三块机器来存,三台机器都存满了时,再把数据进行分配的时候不再把它分配到直线线性空间上,而是把它分配到环状空间上,把起点和终点连接起来,连成一个数据环,如图6所示,这样相应的数据点就放在这一块。如果要添加一个新的数据中心就在环上新切出来这块,这样很方便,切出来这一部分代表这一部分数据都应该放到新的芯片上,所以把原来子数据分片挪到嵌入式的分片上。
6.jpg

图6 数据分片
还有可能删除数据,我们把黄色的数据放到红色的数据上,这是环的好处。实际为了做到高可靠性,任何一个数据可能假定映射到黄色部分以后,这些黄色的部分只要映射到任何一个黄色的区域都会存在同一片机器上,同一片机器底层会有多个副本和做数据的备份,这是实际数据分片的一个实例。这是怎么做数据的高可靠性。这些数据分片,还有负载均衡,都是为了对应分布式分片硬件带来的不可靠和失效,这是我们用分布式系统最大的特点。
基于Docker的分布式计算平台
Docker工作流
我们主要用Docker来做分布式环境下的进程管理。Docker工作流如图7所示,我们不仅把Docker应用到生产阶段,也应用到开发阶段,所以我们每天编辑Dockerfile,提升Docker Images,测试上线,发Docker镜像,在我们内部私有Docker regis里面,再调到我们Docker集群生产环境里面,这和其他的Docker工作流没有什么区别。
7.jpg

在Mesos提交Docker任务
因为Mesos和Docker已经是无缝结合起来。通过Marathon和Chronos提交服务型应用和批处理型应用。Marathon和Chronos通过RESTful的方式提交任务,用JSON脚本设定应用的后台实例个数、应用的参数、以及Docker Images的路径等等。
分布式环境下的进程通信
在分布式环境下应用服务之间通信,是用分布式消息队列来做,我们用的是RabbitMQ。RabbitMQ也是一个分布式系统,它也要保证高可靠性、解决容错的问题。首先RabbitMQ也有集群,如图8所示,六个节点组成了一个RabbitMQ的集群,每个节点之间是互为备份的关系,任何一个坏掉,其他五个还可以提供服务,通过冗余来保证RabbitMQ的高可靠性。
8.jpg

图8 RabbitMQ集群
其次,RabbitMQ也有数据分片机制。因为消息队列有可能很长,长到所有的消息不可能都放到一个节点上,这时就要用分片,把很长的消息队列分为几段,分别放到不同的节点上。如图9所示是RabbitMQ的联盟机制,把一个消息队列打成两段,一段放在上游一段放在下游,假定下游消息队列的消息被消费完了就自动把上游消息队列里的消息移到下游,这样一个消息队列变成非常长的时候也不怕,分片到多个节点上即可。
9.jpg

图9 消息队列分片
分布式文件系统
最后讲一下分布式文件系统HDFS和Ceph。Hadoop文件系统HDFS,如图10所示,每个数据块有三个备份,必须放在不同的服务器上,而且三个备份里面每个机架最多放两份,这么做也是为了容错。Ceph是另一种流行的开源分布式文件系统。Ceph把网络存储设备抽象成一张逻辑硬盘,然后“挂载”到分布式集群的每台服务器上,原理上非常像是Linux操作系统Mount一块物理硬盘。这样一来,用户程序访问Ceph的文件系统就跟访问Linux本地路径一样,非常方便。
10.jpg

分布式环境下的监控
分布式环境下,程序不是运行在本地,而是在集群上面,没有监控就等于程序运行在黑盒子下,无法调优,必须要有监控。分布式环境下的监控分为两个部分,一是性能监控,另一个是报警。性能监控要知道每个应用程序运行状态是什么样,即每一个应用程序占了多少CPU内存、服务的请求处理延迟等。我们是用Graphite来做应用程序性能监控;还有其他系统,比如MongoDB、Hadoop等开源系统,我们用Ganglia来做性能监控,比如CPU内存硬盘的使用情况等。报警是要在关键服务出现故障时,通知开发运维人员及时排解故障,我们用Zabbix来做报警。(责编/周建丁)
内容来源:《程序员》 收起阅读 »

【经验分享】教你写Android网络框架之基本架构

前言
在开发过程中,网络是我们很重要的一部分,因此我们就以网络框架或者说网络模块开始。在这个框架开发过程中,我会整理开发思路、以及遇到一些设计问题时会有怎么样的考虑、解决方案,当然这只是我个人的观点,大家也可以有自己的实现。除了网络框架,后续的系列还想更新ImageLoader框架、ORM框架,如果有时间也会增加动画框架和微博开发的系列文章。当然这些框架只是一些简单的框架基础,本人水平、时间有限,而且已经有现成、成熟的很多框架,我们在这里只是以重复造轮子的态度去学习轮子构建过程,从而达到能够造轮子的地步。至于很多细节的问题,我们这里就不过多讨论了,如果有兴趣,各位可以自行研究。
最后,我们暂且把这个框架命名为SimpleNet,下面我们一起进入主题吧。
基本结构
1.jpg

图1 ( SimpleNet的基本结构 )
SimpleNet框架的基本结构类似于Volley,包括一些命名上也有跟Volley一致。它主要分为四个部分,最上面的部分为Request,即各种请求类型。例如返回的数据类型为json的对应为JsonRequest,返回数据字符串的为StringRequest,如果需要上传文件,那么你需要使用MultipartRequest,该请求只支持小文件的上传,如果上传的文件过大则会产生OOM。

第二部分为消息队列,消息队列维护了提交给网络框架的请求列表,并且根据相应的规则进行排序。默认情况下更具优先级和进入队列的顺序来执行,该队列使用的是线程安全的PriorityBlockingQueue,因为我们的队列会被并发的访问,因此需要保证访问的原子性。

第三部分是Executor,也就是网络的执行者。该Executor继承自Thread,在run方法中循环访问第二部分的请求队列,请求完成之后将结果投递给UI线程。为了更好的控制请求队列,例如请求排序、取消等操作,这里我们并没有使用线程池来操作,而是自行管理队列和Thread的形式,这样整个结构也变得更为灵活。

第四部分则是Response投递类,在第三部分的Executor中执行网络请求,Executor是Thread,但是我们并不能在主线程中更新UI,因此我们使用
ResponseDelivery来封装Response的投递,保证Response执行在UI线程。
每个部分职责都相对单一,这样便于日后的升级和维护。
框架分析
图1中看起来有点像是分层架构,其实不是,这个图更多的是表达了它的逻辑顺序,而不是结构。而在我们的应用开发中,分层架构是一个重要的手段,如图2所示。
2.png

但在开发过程中,我们往往会把UI和业务层耦合起来,因为它们的关系太密切了,分解起来并不是那么容易。高手能够把复杂的事情简单化,而分解就是简单化的重要手段,分解这个过程在开发过程中我们成为重构。

那么我们就引入了一个分层概念,为了便于理解你也可以按照如图1的结构来加深理解。那么分层有什么优缺点呢?
优点:
复杂问题分解简单化,每一层负责自己的实现,并向外提供服务;
职责分离,复杂的系统都有很多人员进行开发,这些功能开发的管理和集成是个很严重的问题,分层设计实现之后,每层只需定义好自己的对外接口,其他依赖层服务的就可以进行开发;
每一层对其他层都是独立的,对外隐藏实现细节,上层无需知道下层的细节,只需调用接口即可;
有利于标准化。
缺点:
分层之后对于领域业务的修改有可能需要修改很多层;
过多的层次影响性能。
如上所说,我们的SimpleNet并不是分层的,而是简单的模块化,但是理论基础都是类似的,依赖于抽象而不依赖于实现、单一职责……这里引入分层的概念,这是便于理解,同时也是希望大家在开发过程中能够尽量保证模块的内聚性、耦合性。
再看SimpleNet,Request是一个抽象的泛型类,泛型类型就是返回的Response类型,例如StringRequest就是继承自Request。第二部分的RequestQueue依赖于Request,Request是抽象的,因此任何Request的子类都可以传递到请求队列中来,它依赖的是抽象Request,而不是具体的某个实现,因此保证了可扩展性。你可以自己实现自己所需的Request,例如大文件的上传Request。同理,第三部分的NetworkExecutor也只是依赖于Request抽象,但这里又引入了一个类型HttpStack,这个网络请求的真正执行者,有HttpClientStack和HttpUrlConnStack,两者分别为Apache的HttpClient和java的HttpURLConnection,关于这两者的区别请参考:Android访问网络,使用HttpURLConnection还是HttpClient?。HttpStack也是一个抽象,具体使用HttpClient还是HttpURLConnection则由运行系统版本来定,HttpStackFactory会根据系统版本给框架返回对应的HttpStack。最后的ResponseDelivery比较简单了,只是通过Handler将结果投递给UI线程执行,也就是执行RequestListener的onComplete方法,此时网络执行完成,用户即可在该方法中更新UI或者相关的其他的操作。
下面我们再看看SimpleNet的工程结构,如图3所示。
3.jpg

图3
这就是SimpleNet框架的基本结构了~
 
继续阅读 »
前言
在开发过程中,网络是我们很重要的一部分,因此我们就以网络框架或者说网络模块开始。在这个框架开发过程中,我会整理开发思路、以及遇到一些设计问题时会有怎么样的考虑、解决方案,当然这只是我个人的观点,大家也可以有自己的实现。除了网络框架,后续的系列还想更新ImageLoader框架、ORM框架,如果有时间也会增加动画框架和微博开发的系列文章。当然这些框架只是一些简单的框架基础,本人水平、时间有限,而且已经有现成、成熟的很多框架,我们在这里只是以重复造轮子的态度去学习轮子构建过程,从而达到能够造轮子的地步。至于很多细节的问题,我们这里就不过多讨论了,如果有兴趣,各位可以自行研究。
最后,我们暂且把这个框架命名为SimpleNet,下面我们一起进入主题吧。
基本结构
1.jpg

图1 ( SimpleNet的基本结构 )
SimpleNet框架的基本结构类似于Volley,包括一些命名上也有跟Volley一致。它主要分为四个部分,最上面的部分为Request,即各种请求类型。例如返回的数据类型为json的对应为JsonRequest,返回数据字符串的为StringRequest,如果需要上传文件,那么你需要使用MultipartRequest,该请求只支持小文件的上传,如果上传的文件过大则会产生OOM。

第二部分为消息队列,消息队列维护了提交给网络框架的请求列表,并且根据相应的规则进行排序。默认情况下更具优先级和进入队列的顺序来执行,该队列使用的是线程安全的PriorityBlockingQueue,因为我们的队列会被并发的访问,因此需要保证访问的原子性。

第三部分是Executor,也就是网络的执行者。该Executor继承自Thread,在run方法中循环访问第二部分的请求队列,请求完成之后将结果投递给UI线程。为了更好的控制请求队列,例如请求排序、取消等操作,这里我们并没有使用线程池来操作,而是自行管理队列和Thread的形式,这样整个结构也变得更为灵活。

第四部分则是Response投递类,在第三部分的Executor中执行网络请求,Executor是Thread,但是我们并不能在主线程中更新UI,因此我们使用
ResponseDelivery来封装Response的投递,保证Response执行在UI线程。
每个部分职责都相对单一,这样便于日后的升级和维护。
框架分析
图1中看起来有点像是分层架构,其实不是,这个图更多的是表达了它的逻辑顺序,而不是结构。而在我们的应用开发中,分层架构是一个重要的手段,如图2所示。
2.png

但在开发过程中,我们往往会把UI和业务层耦合起来,因为它们的关系太密切了,分解起来并不是那么容易。高手能够把复杂的事情简单化,而分解就是简单化的重要手段,分解这个过程在开发过程中我们成为重构。

那么我们就引入了一个分层概念,为了便于理解你也可以按照如图1的结构来加深理解。那么分层有什么优缺点呢?
优点:
复杂问题分解简单化,每一层负责自己的实现,并向外提供服务;
职责分离,复杂的系统都有很多人员进行开发,这些功能开发的管理和集成是个很严重的问题,分层设计实现之后,每层只需定义好自己的对外接口,其他依赖层服务的就可以进行开发;
每一层对其他层都是独立的,对外隐藏实现细节,上层无需知道下层的细节,只需调用接口即可;
有利于标准化。
缺点:
分层之后对于领域业务的修改有可能需要修改很多层;
过多的层次影响性能。
如上所说,我们的SimpleNet并不是分层的,而是简单的模块化,但是理论基础都是类似的,依赖于抽象而不依赖于实现、单一职责……这里引入分层的概念,这是便于理解,同时也是希望大家在开发过程中能够尽量保证模块的内聚性、耦合性。
再看SimpleNet,Request是一个抽象的泛型类,泛型类型就是返回的Response类型,例如StringRequest就是继承自Request。第二部分的RequestQueue依赖于Request,Request是抽象的,因此任何Request的子类都可以传递到请求队列中来,它依赖的是抽象Request,而不是具体的某个实现,因此保证了可扩展性。你可以自己实现自己所需的Request,例如大文件的上传Request。同理,第三部分的NetworkExecutor也只是依赖于Request抽象,但这里又引入了一个类型HttpStack,这个网络请求的真正执行者,有HttpClientStack和HttpUrlConnStack,两者分别为Apache的HttpClient和java的HttpURLConnection,关于这两者的区别请参考:Android访问网络,使用HttpURLConnection还是HttpClient?。HttpStack也是一个抽象,具体使用HttpClient还是HttpURLConnection则由运行系统版本来定,HttpStackFactory会根据系统版本给框架返回对应的HttpStack。最后的ResponseDelivery比较简单了,只是通过Handler将结果投递给UI线程执行,也就是执行RequestListener的onComplete方法,此时网络执行完成,用户即可在该方法中更新UI或者相关的其他的操作。
下面我们再看看SimpleNet的工程结构,如图3所示。
3.jpg

图3
这就是SimpleNet框架的基本结构了~
  收起阅读 »

新版imgeek.org社区公测

各位geekers,

我们重新输理和构建了了imgeek.org开发者社区,邀请各位测试,现在的样子看起来有点像stackoverflow.

对于新用户,直接注册即可进入
对于已经注册的用户,由于你的密码是加密存放的,我们无法迁移你的密码, 你需要通过"找回密码"进入:http://www.imgeek.org/?/account/find_password/

fat1

---------------------------------------------
2015.6.16  imgeek.org release note
 . 调整问题及回复的展现形式
 . 增加发布“文章”功能
 . 新增“活动”功能
 . 新增“工单功能
 . 增强提醒功能
 . 新增“知识库”/“帮助”功能
 . 新增提问前“问题提示”功能
 . 新增“简历”功能及实名认证功能
 . 增加“个人空间”及用户信誉体系
 . 增加与客服对接的交换格式
 . 增强搜索功能
 . 更好的手机端访问体验
 . .......(更多好功能等你体验)

to do list :
1. 社交账号(微博、微信、QQ、facebook ,twitter,google)登录
2. "活动"板块优化
3. "话题"/标签优化
4. 提醒功能优化
5. 推出英文版本
6. 开源项目托管协作托管平台

原来的社区站仍然可以通过:http://www.imgeek.org/bbs 访问
 
 
继续阅读 »
各位geekers,

我们重新输理和构建了了imgeek.org开发者社区,邀请各位测试,现在的样子看起来有点像stackoverflow.

对于新用户,直接注册即可进入
对于已经注册的用户,由于你的密码是加密存放的,我们无法迁移你的密码, 你需要通过"找回密码"进入:http://www.imgeek.org/?/account/find_password/

fat1

---------------------------------------------
2015.6.16  imgeek.org release note
 . 调整问题及回复的展现形式
 . 增加发布“文章”功能
 . 新增“活动”功能
 . 新增“工单功能
 . 增强提醒功能
 . 新增“知识库”/“帮助”功能
 . 新增提问前“问题提示”功能
 . 新增“简历”功能及实名认证功能
 . 增加“个人空间”及用户信誉体系
 . 增加与客服对接的交换格式
 . 增强搜索功能
 . 更好的手机端访问体验
 . .......(更多好功能等你体验)

to do list :
1. 社交账号(微博、微信、QQ、facebook ,twitter,google)登录
2. "活动"板块优化
3. "话题"/标签优化
4. 提醒功能优化
5. 推出英文版本
6. 开源项目托管协作托管平台

原来的社区站仍然可以通过:http://www.imgeek.org/bbs 访问
 
  收起阅读 »

Meteor 获 2000 万美元融资,Galaxy 是新重点

JavaScript 开发框架 Meteor 的开发团队 Meteor Development Group (简称 MDG)为它的框架堆栈、Web 开发工具和 JavaScript 移动应用融资 2000 万美元。此轮融资由经纬创投、安德森·霍洛维茨基金和 Trinity 风险投资领导,并提供了 MDG 开发开源框架所需要的资源。

MDG 的 CEO Geoff Schmidt 表示,下一步的重点是 Galaxy,它是基于谷歌开源项目 Kubernetes 的 Meteor 运行应用程序的系统。另外,Meteor 也增加处理 UI 的库,比如对 Angular 和 React 的支持。
继续阅读 »
JavaScript 开发框架 Meteor 的开发团队 Meteor Development Group (简称 MDG)为它的框架堆栈、Web 开发工具和 JavaScript 移动应用融资 2000 万美元。此轮融资由经纬创投、安德森·霍洛维茨基金和 Trinity 风险投资领导,并提供了 MDG 开发开源框架所需要的资源。

MDG 的 CEO Geoff Schmidt 表示,下一步的重点是 Galaxy,它是基于谷歌开源项目 Kubernetes 的 Meteor 运行应用程序的系统。另外,Meteor 也增加处理 UI 的库,比如对 Angular 和 React 的支持。 收起阅读 »