方舟进化生存一个服务器好几个

方舟进化生存一个服务器好几个,第1张

方舟进化生存一个服务器在20-70元。方舟生存进化是可以开启私人服务器的,但是私人服务器需要有一定的花销,如果要开私人服务器的话一个月在20-70块钱左右。存进化如果开服务器的话,根据你开的服务器人数的多少,价格也是不一样的,30人左右的一个月需要200元左右,70人的1个月需要700元。

转载表面上看,是一套基于B/S方式实现的分布式管理系统,但其实背后的架构是基于C/S完成的。你以为他是一只鞋吗?其实他是一个吹风机。作为界面化的系统,浏览器框架是不可或缺的,但更加重要的东西在Socket上面。

一、需要解决中央控制端到各节点服务器之间的通信。

这个其实牵扯到一个通信协议的问题,各语言都有自己的socket,thread的库,直接调用即可。但是这个通信协议就需要自己来完成了。既不能太简单,太简单了,明码传输,如果别人获知了这个接口,就很容易执行一些令人讨厌的 *** 作。也不能太复杂,太复杂了等于是给自己找麻烦,所以简单的数据包编解码的工作或者用token验证的方式是需要的。通信协议起码要两种,一种是传输命令执行的协议,一种是传输文件的协议。

二、跨语言的socket通信

为什么要跨语言,主控端和代理端通信,用什么语言开发其实无所谓。但是为了给自己省事,尽可能使用服务器上已经有了的默认语言,Ambari前期采用phppuppet的方式管理集群,这不是不可以,puppet自己解决了socket通信协议和文件传输的问题,可你需要为了puppet在每台服务器上都安装ruby。我是个有点服务器和代码洁癖的人。光是为了一个puppet就装个ruby,我觉得心里特对不起服务器的资源。所以我自己写了一个python的代理端。python是不管哪个linux系统在安装的时候就都会有了。然后主控端的通信,可以用python实现,也可以用php实现,但是考虑到对于更多的使用者来说,改php可能要比改tornado简单许多,所以就没用python开发。hadoop分支版本众多,发布出去,用户要自己修改成安装适合自己的hadoop发行版,就势必要改源码,会php的明显比会python的多。php里面的model封装了所有的 *** 作,而python只是个 *** 作代理人的角色而已。

所以也延伸出一个问题,什么语言用来做这种分布式管理系统的代理端比较合适,我自己觉得,也就是python比较合适了, *** 作系统自带,原生的package功能基本够用。用java和php也可以写agent,但是你势必在各节点预先就铺设好jre或者php运行环境。这就跟为什么用python和java写mapred的人最多是一样的。没人拦着你用nodejs写mapred,也可以写,就是你得在每个节点都装v8的解释引擎,不嫌麻烦完全可以这样干。原理参看map/rece论文,不解释。perl也是 *** 作系统原生带的,但是perl的可维护性太差了,还是算了吧。

所以这就牵扯到一个跨语言的socket问题,理论上来说,这不存在什么问题。但这是理论上的,实际开发过程中确实存在问题,比如socket长连接,通信数据包在底层的封装方式不同。我没有使用xml-rpc的原因之一就是我听说php的xmlrpc跟其他语言的xmlrpc有不同的地方,需要修改才能用,我就没有用这种办法。最早是自己定义的 *** 作协议,这时就遇到了这些问题,所以后来直接采用了thrift方式。就基本不存在跨语言的socket通信问题了。

三、代理端执行结果的获取

无论命令还是文件是否在代理端执行成功,都需要获取到执行结果返回给中央端。所以这里也涉及一个读取节点上的stdout和stderr的问题。这个总体来说不是很难,都有现成的包。当然这个时候你需要的是阻塞执行,而不能搞异步回调。

还有个问题是,我要尽可能使用python默认就带的包,而尽量不让服务器去访问internet下载第三方的包。

还有代理端最重要的一点,就是python的版本兼容性。centos5用python24,centos6用python26,ubuntu基本默认都是27。所以一定要最大限度的保证语言的跨版本兼容性,要是每个 *** 作系统和每一个版本我都写一个代理,我一个人就累死了。

四、浏览器端的model,view,controller

这里面你要封装好所有的通信协议,以及需要在节点上面执行的脚本。发送文件的 *** 作和数据库 *** 作也要在model里面完成。

如果对tcl/tk很熟,也可以写基于 *** 作系统界面方式的管理,不用浏览器就是了。

view对我来说是最痛苦的事,都是现学的jQuery怎么用,前端的工作太可怕了。关于这方面,没有太多可描述的,html和js带给我的只有痛苦的回忆,万恶的undefined。

五、跨 *** 作系统的安装文件封装。

要适应不同的 *** 作系统也是个很麻烦的事情,需要用agent提前获知 *** 作系统的发行分支,版本号。然后去找到对应的安装文件去执行。你不能保证一个分布式系统的集群中所有的节点都可以访问internet,更多的情况是这些节点都存在在一个安全的内网中。只有个别几个节点是可以访问外网的。所以,我势必要把所有的安装文件以及他们的依赖尽可能集中起来。我不确定安装 *** 作系统的lzo,yum或者apt-get会去下什么鬼东西,甚至无论是yum还是apt-get,里面都没有hadoop-lzo的库文件。所以,最好的办法是自己编译打包rpm和deb包。直接安装就好了,别去找repo下载什么。

这就是第五步工作,把需要的依赖的东西自己编译打包成rpm和deb。

deb包很好解决,但是rpm就没那么好办了,需要学习rpm的编译文件如何编写,这块是挺麻烦的,但是这玩意用好了还是挺不错的。现在我自制的安装包里面就已经包含了自己编译的lzo和snappy两种压缩库,以及hadoop-gpl-packaging的rpm和deb。下一个发布的easyhadoop将直接支持centos5,6,suse,以及ubuntu/debian的系统上安装hadoop。已经自带了lzo和snappy以及lzop和snzip。

六、把这些所有东西,整合到一个系统里面。

关联这些所有事情间的联系,整合到一个浏览器界面里面去。写一个分布式的管理脚本不难,写一个界面也不难,但是也许是我的水平不行,这两件事结合起来让他们协同工作还是有点难度的。对我来说,写界面的工作可能更难一点。

Cloudera可能是十来个人在写Manager的东西,ambari也是放到github和apachesvn上面,apache基金会的各种committer在写。easyhadoop没他们功能那么强大,一年来只有我一个人设计架构,功能,各种语言的编码,测试,发布。Fortheloveofgod,WhathaveIdone(英文部分请站在山顶仰天长啸)T_T。从前台到后台,到hadoop和生态系统以及他们的依赖软件的单独patch、编译打包。(系统yum或者apt-get的包不如自己打的好使。)

从时间上来看,全球第一款开源的hadoop部署管理系统应该还是属于ambari,2011年8月开始写的,2012年9月底进入apache的incubator。我是大概2012年8月开始写的easyhadoop,全球第一没赶上,估计国内第一个开源的hadoop管理系统还是可以排上的。

组件的生命周期

用程序组件都有一个生命周期,从响应Intent的Android实例开始到这个实例被销毁。在这期间,他们或许有效或许无效,有效时或许对用户可见或许
不可见。下面我们就来讨论四个基本组件的生命周期,包括在生命周期内的各种状态,以及状态之间的转换。这几种状态可能的结果是:进程让他们停止,
然后实例被销毁。
一、activity生命周期
一个activity有三个基本的状态:
@ 当activity在前台运行时(在activity当前任务的堆栈顶),为活动或者运行状态。这时activity会响应用户的 *** 作。
@

当activity失去焦点但是对用户仍然可见时为paused暂停状态。此时,别的activity在他的上面,透明或者备有被全部覆盖。所以其中一些
暂停的activity也可以被显示。一个暂停的activity是处于活动状态的(他维护着所有的状态保存着信息,并且依然附着在窗口管理器)。
@ 如果一个activity完全被另一个activity所掩盖那他会处于stop状态。但仍然保存着原来的状态和信息。然而,如果别的地方需要更多的内存而且这个activity仍一直处于隐藏状态,那么系统有可能会杀死他的进程。
如果一个activity是暂停或者停止状态,系统可以清理他们占用的内存,或者调用finish()方法,或者直接结束他的进程。当他再次显示给用户时,会完全的重新运行并且加载以前所存储的信息。
activity状态之间的转换,是通过以前的受保护方法完成的:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
这些都是钩子函数,你可以重写他们,当状态改变时做一些适当的处理。所有的activity在首次运行时必须实现onCreate()方法来初始化安装。activity可以实现onPause()来提交数据改变,然后准备停止与用户的交互。
调用超类
每一个实现的activity生命周期方法都会先调用一下父类的方法,例如:
view plaincopy to clipboardprint
protected void onPause() {
superonPause();

}
protected void onPause() {
superonPause();

}
通过这两者比较,这7个方法定义了一个activity的整个生命周期的方法。你可以实现并且监测这三个嵌套循环:
@ 整个生命周期

用onCreate()方法和onDestroy()之间称为一个activity的完整的生命周期。activity会在onCreate()里执行所
有的初始化安装,在onDestroy()方法里释放所有的剩余资源。例如:一个从网络下载程序的线程,就需要在onCreate()方法里创建,在
onDestroy()方法里销毁。
@ 可见生命周期

见生命周期是从onStart()方法到onStop()方法的时间。这段时间,用户会在屏幕上看到这个activity。尽管他可能不是在最顶层显示,
也没有和用户进行任何交互。这两个方法之间,你可以保持需要向用户显示的资源。例如:你可以在onStart()方法时注册一个
BroadcastReceiver检测某些变化来改变你的界面,当用户看不到这个activity的界面时可以在onStop()里注销这个
BroadcastReceiver。这两个方法可以被调用很多次,在可见和对用户隐藏时,作为候补的activity待命。
@ 前台显示周期

个activity从onResume()方法指导一个onPause()方法称为前台显示周期。此时他在其他的activity之上显示并且与用户交
互。一个activity可以频繁的在这两个方法之间过度,例如:当设备休眠或者另一个新的activity启动时,它会进入onPause()状态,当
一个activity运行结束或者新的接收到Intent请求时,activity的onResume()会被调用。因此,这两个方法里的代码量会很
少。
下图说明了上面说的几个循环,里面的箭头说明了两个状态之间是否可以相互转换。有色的椭圆是activity主要的几个状态。正方形和长方形代表activity在状态之间转变时我们可以实现的一些回调方法。

意killable这列,它指明了进程在调用方法返回后是否可以被系统杀死,而不执行其他的代码。onPause(), onStop(), and
onDestroy()这三个方法可以,因为onPause方法首先被执行,他是唯一一个一定会被调用的方法当进程被杀死时,但是onStop()和
onDestroy()方法不会。因此,你可以在onPause()方法里保存一些连续的数据,例如编辑。
killable
这列被标记成no的方法,保护activity防止他们被调用时,被进程杀死。例如:一个activity是处于可被杀死的状态,当activity从
onPause()方法跳转到onResume()方法时,在OnPause方法回调之前是不会被杀死的。
正如后面的章节:进程和生命周期,一个没有定义为“killable”的activity仍然可以被系统结束,但这时会发生在特殊情况下,比如没有其他资源时。
保存activity的状态
当系统(而不是用户)关闭一个activity来节省内存时,用户希望再次启动activity时会回到当时的状态。

了在activity被杀死之前捕获他的状态,你可以实现
onSaveInstanceState()方法,Android会在一个activity将要被关闭时调用这个方法,也就是在onPause()方法之
前。他回传递给方法一个Bandle对象,你可以用key-value的方式保存你的数据。当activity再次运行时。这个Bandle对象会传递给
onCreate()方法、onStart()方法、onRestoreInstanceState()方法。这几个方法都能重建当时的activity
状态。

像onPause()和刚才讨论的其他几个方法,onSaveInstanceState()和onRestoreInstanceState()方法不
是生命周期方法。不是不是总被调用。例如:Android在activity将要被系统销毁之前调用onSaveInstanceState()方法,当
activity实例被用户的 *** 作销毁时(例如按下Back键),是不会调用这个方法的。这种情况下没有理由保存他的状态。
Coordinating activities
当一个activity启动了另一个activity,他们都经历了生命周期的转换。一个暂停了或者结束了,其他的activity启动。一种情况你可能需要调节这些activity:
生命周期方法的回调顺序都是定义好的,尤其当两个activity在同一进程下:
1当前运行的activity的onPause()方法被调用。
2然后将要运行的activity的onCreate()、onStart()、onResume()方法被依次调用。
3然后,如果将要运行的activity不太可见,那么onstop()方法会被调用。
二、Service的生命周期:
有了 Service 类我们如何启动他呢,有两种方法:
• ContextstartService()
• ContextbindService()
1 在同一个应用任何地方调用 startService() 方法就能启动 Service 了,然后系统会回调 Service 类的
onCreate() 以及 onStart() 方法。这样启动的 Service 会一直运行在后台,直到
ContextstopService() 或者 selfStop() 方法被调用。另外如果一个 Service 已经被启动,其他代码再试图调用
startService() 方法,是不会执行 onCreate() 的,但会重新执行一次 onStart() 。
2 另外一种 bindService() 方法的意思是,把这个 Service 和调用 Service
的客户类绑起来,如果调用这个客户类被销毁,Service 也会被销毁。用这个方法的一个好处是,bindService() 方法执行后
Service 会回调上边提到的 onBind() 方发,你可以从这里返回一个实现了 IBind
接口的类,在客户端 *** 作这个类就能和这个服务通信了,比如得到 Service 运行的状态或其他 *** 作。如果 Service
还没有运行,使用这个方法启动 Service 就会 onCreate() 方法而不会调用 onStart()。
总结:
1 startService()的目的是回调onStart()方法,onCreate()
方法是在Service不存在的时候调用的,如果Service存在(例如之前调用了bindService,那么Service的onCreate方法
已经调用了)那么startService()将跳过onCreate() 方法。
2
bindService()目的是回调onBind()方法,它的作用是在Service和调用者之间建立一个桥梁,并不负责更多的工作(例如一个
Service需要连接服务器的 *** 作),一般使用bindService来绑定到一个现有的Service(即通过StartService启动的服
务)。
由于Service 的onStart()方法只有在startService()启动Service的情况下才调用,故使用onStart()的时候要注意这点。
与 Service 通信并且让它持续运行
如果我们想保持和 Service 的通信,又不想让 Service 随着 Activity 退出而退出呢?你可以先
startService() 然后再 bindService() 。当你不需要绑定的时候就执行 unbindService()
方法,执行这个方法只会触发 Service 的 onUnbind() 而不会把这个 Service 销毁。这样就可以既保持和 Service
的通信,也不会随着 Activity 销毁而销毁了。
提高 Service 优先级
Android
系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用。当系统觉得当前的资源非常有限的时候,为了保
证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存。这样就能保证真正对用户有用的程序仍然再运行。如果你的
Service 碰上了这种情况,多半会先被杀掉。但如果你增加 Service 的优先级就能让他多留一会,我们可以用
setForeground(true) 来设置 Service 的优先级。
为什么是 foreground 默认启动的 Service 是被标记为 background,当前运行的 Activity 一般被标记为
foreground,也就是说你给 Service 设置了 foreground 那么他就和正在运行的 Activity
类似优先级得到了一定的提高。当让这并不能保证你得 Service 永远不被杀掉,只是提高了他的优先级。
三、android的service的生命周期与activity类似,但是有一些不同:
onCreate和onStart是不同的

过从客户端调用ContextstartService(Intent)方法我们可以启动一个服务。如果这个服务还没有运行,Android将启动它并
且在onCreate方法之后调用它的onStart方法。如果这个服务已经在运行,那么它的onStart方法将被新的Intent再次调用。所以对于
单个运行的Service它的onStart方法被反复调用是完全可能的并且是很正常的。
onResume、onPause以及onStop是不需要的
回调一个服务通常是没有用户界面的,所以我们也就不需要onPause、onResume或者onStop方法了。无论何时一个运行中的Service它总是在后台运行。
onBind

果一个客户端需要持久的连接到一个服务,那么他可以调用ContextbindService方法。如果这个服务没有运行方法将通过调用
onCreate方法去创建这个服务但并不调用onStart方法来启动它。相反,onBind方法将被客户端的Intent调用,并且它返回一个
IBind对象以便客户端稍后可以调用这个服务。同一服务被客户端同时启动和绑定是很正常的。
onDestroy

Activity一样,当一个服务被结束是onDestroy方法将会被调用。当没有客户端启动或绑定到一个服务时Android将终结这个服务。与很多
Activity时的情况一样,当内存很低的时候Android也可能会终结一个服务。如果这种情况发生,Android也可能在内存够用的时候尝试启动
被终止的服务,所以你的服务必须为重启持久保存信息,并且最好在onStart方法内来做。
--------------------------------------------------------------------------------------------------
activity的生命周期
oncreate(Bundle
savedInstanceState):在activity第一次被创建的时候调用。这里是你做所有初始化设置的地方──创建视图、绑定数据至列表等。
如果曾经有状态记录,则调用此方法时会传入一个包含着此activity以前状态的包对象做为参数
onRestart():在activity停止后,在再次启动之前被调用。
onStart():当activity正要变得为用户所见时被调用。
onResume():在activity开始与用户进行交互之前被调用。此时activity位于堆栈顶部,并接受用户输入。
onPause():当系统将要启动另一个activity时调用。此方法主要用来将未保存的变化进行持久化,停止类似动画这样耗费CPU的动作等。这一切动作应该在短时间内完成,因为下一个activity必须等到此方法返回后才会继续。
onStop():当activity不再为用户可见时调用此方法。这可能发生在它被销毁或者另一个activity(可能是现存的或者是新的)回到运行状态并覆盖了它。
onDestroy():在activity销毁前调用。这是activity接收的最后一个调用。这可能发生在activity结束(调用了它的 finish() 方法)或者因为系统需要空间所以临时的销毁了此acitivity的实例时。你可以用isFinishing() 方法来区分这两种情况。
协调activity
当一个activity启动了另外一个的时候,它们都会经历生命周期变化。一个会暂停乃至停止,而另一个则启动。这种情况下,你可能需要协调好这些activity:
生命周期回调顺序是已经定义好的,尤其是在两个activity在同一个进程内的情况下:
1 调用当前activity的 onPause() 方法。
2 接着,顺序调用新启动activity的onCreate()、 onStart()和onResume()方法。
3 然后,如果启动的activity不再于屏幕上可见,则调用它的onStop()方法。
总之:1、Activity 从创建到进入运行态所触发的事件 onCreate()-->onStart-->onResume()
2、从运行态到停止态所触发的事件 onPause()--->onStop()
3、从停止态到运行态所触发事件 onRestart()-->onStart()--->onResume()
4、从运行态到暂停态所触发事件 onPause()
5、从暂停态到运行态所触发事件 onResume()
横竖屏幕切换生命周期
1不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

2设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

3设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
service的生命周期
启动Service时可调用startService和bindService()方法来启动,用这两种方法启动的Service的生命周期是不同的。
Service的生命周期只有onCreate,onStart和onDestroy,没有onResume,onPause和onStop,大多
数时间Service都是运行的,但在严重的内存压力下它也可能被系统kill,如果被kill,系统会在稍后尝试重新启动这个Service
Service的调用
途径一:
调用ContextstartService()启动Service,调用ContextstopService()或ServicestopSelf()或ServicestopSelfResult()关闭Service的调用。
Service生命周期分析:
注:onCreate,onStart(),onDestroy()是Service生命周期相关的方法
当ContextstartService()启动Service时,如果Service本身没有运行,则调用
onCreate()->onStart()完成Service启动。如果Service已经运行,则只调用
onStart(),onStart()可以多次被调用。
Service关闭必须调用ContextstopService()或ServicestopSelf()或
ServicestopSelfResult()方法,关闭之前调用onDestroy()方法,否则如果Context直接退出而没有停止
Service的话,Service会一直在后台运行。该Service的调用者只能再启动后通过stopService关闭Service。
生命周期顺序为:onCreate()->onStart()->onDestroy()
途径二:
调用ContextbindService()进行初始化绑定,使用ContextunbindService()取消绑定,由于Service和Context是绑定关系,当Context退出或被销毁时,Service也会相应退出。
Service生命周期分析:
调用ContextbindService()时,Service会经历onCreate->onBind(),onBind将返回给客户端一个
IBind实例,IBind允许客户端回调服务的方法。此时Context和Service是绑定在一起的,Context退出了,Service调用
onUnbind()->onDestroy()相应退出。
生命周期顺序为:onCreate->onBind(只一次,不可多次绑定)->onUnbind->onDestroy()
BroadcastReceiver只能通过startService启动Service,因为广播本身生命周期很短,bind的话没有意义
果不是通过bindService创建的服务(但仍然通过bindService得到了服务对象),就可能unbindService后还在运行,否则应该是结束掉了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/13363248.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-22
下一篇 2023-07-22

发表评论

登录后才能评论

评论列表(0条)

保存