分享自己的页游运维架构

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

简单画了个图:

wKiom1T5SaGhOLMgAATkhf2Qem8539.jpg


首先,后端程序及客户端都是分成三个版本:内部测试版,线上测试版,线上稳定版。线上测试版是小范围更新,经过一天测试没问题,然后再推到线上稳定版,更新其他服,一般游戏也都是按这个流程来更新的。


运维管理后台,记录了区服信息,提供各种简单API接口给各脚本使用。


然后批量维护脚本,create_list.py是根据运维管理后台提供的API,根据输入的参数(平台,区服范围)生成一份cqbyupdate.py需要使用的iplist文件,然后cqbyupdate.py根据这份ip文件执行相应的操作。


saltstack,是用于全服修改一些配置使用,例如批量修改zabbix的配置,批量修改nginx的配置 等等。


rsync,用于数据同步,例如给游戏服拉取最新版本。


游戏服最关键的只有一个control.py脚本,该脚本集成了管理单个游戏区服的所有操作,根据传进去的版本参数及动作参数执行对应的操作。


整套架构的优点是全服维护可用cqbyupdate.py脚本操作,如果临时游戏服上想做些什么更新,可用单服脚本control.py操作,比较灵活;缺点是对中心机依赖比较高,万一中心机岩了,就麻烦大了,所以搞了一台备份中心机。这套架构已经上线开服3000+


control.py单服维护脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
#!/usr/bin/python
#coding=utf-8
 
import  subprocess
import  shutil
import  os
import  sys
reload (sys)
sys.setdefaultencoding( 'utf-8' )
import  optparse
import  ConfigParser
import  time
import  jinja2
import  urllib2
import  json
import  socket
try :
     import  fcntl
except :
     pass
import  struct
import  MySQLdb
 
def  get_ip_address(ifname):
     =  socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     return  socket.inet_ntoa(fcntl.ioctl(
         s.fileno(),
         0x8915 ,   # SIOCGIFADDR
         struct.pack( '256s' , ifname[: 15 ])
     )[ 20 : 24 ])
 
 
class  Cqby:
 
     def  __init__( self , version, platform, platformid,  id ):
         self .version  =  version
         self .platform  =  platform
         self .platformid  =  platformid
         self . id  =  id
 
         #工作目录:
         self .workdir  =  '/data/init'
 
         #定义游戏程序目录:
         self .gamedir  =  '/data/game/game%s'  %  self . id
         try :
             os.makedirs( '/data/game' )
         except :
             print  "目录已存在"
 
         #当前游戏聊天监控目录:
         self .chatdir  =  '/data/game/chat%s'  %  self . id
 
         #定义游戏端口:
         if  int ( self . id ) >  50000 :
             self .gameport  =  str ( self . id )
         else :
             self .gameport  =  20000  +  int ( self . id )
             self .gameport  =  str ( self .gameport)
 
         try :
             self .localip = get_ip_address( 'eth0' )
         except :
             self .localip = get_ip_address( 'em1' )
 
         #定义数据库名称:
         self .dbname  =  'game%s'  %  self . id
 
         #定义管理员使用的数据库帐号密码:
         self .admindbuser  =  'root'
         self .admindbpass  =  '123456'
 
         #定义备份目录:
         self .backup  =  '/data/backup'
         try :
             os.makedirs( self .backup)
         except :
             print  "目录已经存在"
 
         #建立日志目录:
         self .gamelogdir  =  '/data/gamelogs/chuanqi/%s/S%s'  %  ( self .platform,  self . id )
         if  not  os.path.isdir( self .gamelogdir):
             os.makedirs( self .gamelogdir)
         subprocess.call( 'chown www:www -R /data/gamelogs' ,shell = True )
 
         #程序配置文件模板:
         self .binConfigDir  =  '%s/bin'  %  self .gamedir
         self .binConfigFiles  =  [ 'socket.jinja2' ]
 
         self .confConfigDir  =  '%s/conf'  %  self .gamedir
         self .confConfigFiles  =  [ 'jade.cfg.jinja2' ]
 
         self .independentConfigDir  =  '%s/conf/independent'  %  self .gamedir
         self .independentConfigFiles  =  [
             'auth.properties.jinja2' ,
             'debug.properties.jinja2' ,
             'fcm.properties.jinja2' ,
             'gm.properties.jinja2' ,
             'net.properties.jinja2' ,
             'server.properties.jinja2' ,
             'whiteList.properties.jinja2' ,
             'onlineLimit.properties.jinja2' ,
         ]
 
         self .miscConfigDir  =  '%s/conf/config/common'  %  self .gamedir
         self .miscConfigFiles  =  [
             'misc.properties.jinja2' ,
         ]
 
         #数据库权限:
         baselist  =  [ '127.0.0.1' ,]
         payIPListAll  =  {
             '37wan' : [],
             'liebao' : [],
             '2345' : [],
             'yilewan' : [],
             'renrenwang' : [],
             '6711' : [],
             '1360' : [],
             'duowan' : [],
             'baidu' : [],
             'lianyun' : [],
             'tencent' : []
         }
         try :
             self .platformPayList  =  payIPListAll[ self .platform]
         except :
             self .platformPayList  =  payIPListAll[ 'lianyun' ]
 
         self .payList  =  baselist  +  self .platformPayList
 
         self .mergelist  =  self .__getMerge()
 
     def  __getMerge( self ):
         '''获取合服列表'''
         =  0
         while  True :
             try :
                 if  i > =  3 :
                     print  "请求超时!!!!!!"
                     sys.exit( 2 )
                 url  =  'http://yw.admin.xxx.com/yunwei/api/getmergetarget/%s/%s/'  %  ( self .platform,  self . id )
                 request  =  urllib2.urlopen(url)
                 response  =  request.read().split( ',' )
             except  Exception, e:
                 print  "请求合服信息失败:"  +  str (e)
                 print  "正在重试。。。"
                 =  +  1
             else :
                 break
         return  response
 
     def  createDatabase( self ):
         '''创建数据库'''
         try :
             print  "正在创建数据库:%s"  %  self .dbname
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "create database %s DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci" '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname)
             ret  =  subprocess.call(cmd,shell = True )
             print  "执行状态:%s"  %  ret
             if  ret:
                 print  "创建数据库失败,请确认!"
                 sys.exit( 2 )
         except  Exception,e:
             print  "捕捉到异常:" ,e
             sys.exit( 2 )
 
     def  updateDB( self , filename):
         ''' 导入数据库文件 '''
         try :
             print  "正在导入SQL文件:%s"  %  filename
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' %s < %s '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname, filename)
             ret  =  subprocess.call(cmd, shell = True )
             print  "执行状态:%s"  %  ret
         except  Exception,e:
             print  "捕捉到异常:" ,e
             sys.exit( 2 )
 
     def  dumpDatabase( self ):
         ''' 备份数据库 '''
         try :
             print  "正在备份数据库:%s"  %  self .dbname
             curTime  =  time.strftime( '%Y%m%d%H%M%S' , time.localtime(time.time()))
             cmd  =  ''' /usr/local/mysql/bin/mysqldump -u'%s' -p'%s' %s > %s '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname, ' % s / % s - % s.sql'  %  ( self .backup,curTime, self .dbname))
             ret  =  subprocess.call(cmd, shell = True )
             print  "执行状态:%s"  %  ret
         except  Exception,e:
             print  "捕捉到异常:" ,e
 
     def  dropDatabase( self ):
         ''' 删除数据库 '''
         try :
             print  "正在删除数据库:%s"  %  self .dbname
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "drop database %s" '''  %  ( self .admindbuser,  self .admindbpass,  self .dbname)
             ret  =  subprocess.call(cmd, shell = True )
             print  "执行状态:%s"  %  ret
         except  Exception,e:
             print  "捕捉到异常:" ,e
 
     def  createGameDir( self ):
         ''' 创建游戏目录 '''
         try :
             print  "正在检测目录是否存在:%s"  %  self .gamedir
             if  os.path.isdir( self .gamedir):
                 print  "目录已存在,请检查参数!"
                 sys.exit( 2 )
             else :
                 print  "正在复制程序文件至:%s"  %  self .gamedir
                 shutil.copytree( '%s/%s/server'  %  ( self .workdir,  self .version),  self .gamedir)
         except  Exception,e:
             print  "捕捉到异常:" ,e
             sys.exit( 2 )
 
     def  dropGameDir( self ):
         ''' 清理游戏目录 '''
         try :
             print  "正在删除游戏目录:%s"  %  self .gamedir
             if  os.path.isdir( self .gamedir):
                 shutil.rmtree( self .gamedir)
         except  Exception,e:
             print  "遇到错误:" ,e
 
     def  dropGameLogDir( self ):
         ''' 清理游戏日志目录 '''
         try :
             print  "正在删除日志目录:%s"  %  self .gamelogdir
             if  os.path.isdir( self .gamelogdir):
                 shutil.rmtree( self .gamelogdir)
         except  Exception,e:
             print  "遇到错误:" ,e
 
     def  createConfig( self , configdir, configlist):
         '''创建程序配置'''
         try :
             print  "正在生成配置文件:%s"  %  configdir
             url  =  'http://yw.admin.xxx.com/yunwei/api/getmem/%s/%s'  %  ( self .platform,  self . id )
             response  =  urllib2.urlopen(url)
             mem  =  response.read()
             env  =  jinja2.Environment(loader = jinja2.FileSystemLoader(configdir))
             for  gateconfig  in  configlist:
                 print  gateconfig
                 template  =  env.get_template(gateconfig)
                 =  open ( '%s/%s'  %  (configdir,gateconfig.rstrip( '.jinja2' )),  'w' )
                 f.write(
                     template.render(
                         version = self .version,
                         platformid = self .platformid,
                         platform = self .platform,
                         gameid = self . id ,
                         gameport = self .gameport,
                         gamedir = self .gamedir,
                         dbuser = 'game' ,
                         dbpass = 'game123456' ,
                         dbname = self .dbname,
                         paylist = self .platformPayList,
                         mem = mem,
                         mergelist = self .mergelist,
                     )
                 )
                 f.close()
         except  Exception,e:
             print  "生成配置文件遇到错误:" ,e
             sys.exit( 2 )
 
     def  updateconfig( self ):
         self .createConfig( self .binConfigDir,  self .binConfigFiles)
         os.chmod( '%s/bin/socket'  %  self .gamedir, 0755
         self .createConfig( self .confConfigDir,  self .confConfigFiles)
         self .createConfig( self .independentConfigDir,  self .independentConfigFiles)
         #self.createConfig(self.miscConfigDir, self.miscConfigFiles)
 
     def  updategame( self ):
         print  "正在更新游戏程序。。。"
         cmd  =  ''' rsync -avzP --exclude="socket" --exclude="log"  --exclude="onlineLimit.properties" --exclude="jade.cfg" --exclude="auth.properties" --exclude="debug.properties" --exclude="fcm.properties" --exclude="gm.properties" --exclude="net.properties" --exclude="server.properties" --exclude="whiteList.properties"  %s/%s/server/  %s/ '''  %  ( self .workdir, self .version, self .gamedir)
         print  cmd
         result  =  subprocess.call(cmd, shell = True )
         return  result
 
     def  start( self ):
         print  "给JSVC添加执行权限:"
         os.chmod( '%s/bin/jsvc'  %  self .gamedir, 0755 )
         print  "正在启动服务:"
         cmd  =  '''cd %s/bin ; ./socket  start '''  %  self .gamedir
         result  =  subprocess.call(cmd, shell = True )
         return  result
  
     def  stop( self ):
         print  "正在关闭服务:"
         cmd  =  '''cd %s/bin ; ./socket  stop '''  %  self .gamedir
         result  =  subprocess.call(cmd, shell = True )
         return  result
 
     def  clearnow( self ):
 
         self .dumpDatabase()
 
         self .updateDB( '%s/%s/server/sql/database.sql'  %  ( self .workdir, self .version))
 
         self .dropGameLogDir()
 
     def  clear( self ):
         try :
             conn  =  MySQLdb.connect(user = self .admindbuser, passwd = self .admindbpass, host = 'localhost' , db = self .dbname, unix_socket = '/tmp/mysql.sock' )
             cursor  =  conn.cursor(cursorclass  =  MySQLdb.cursors.DictCursor)
             sql  =  ''' select * from Player '''
             sum  =  cursor.execute(sql)
             cursor.close()
             conn.close()
             print  "数据库Player表有:%s"  %  sum
             if  int ( sum ) >  30 :
                 print  "Player表记录总数大于30!请确认后再执行清档操作!!!"
                 sys.exit( 2 )
             else :
                 print  "Player表记录总数小于30,可以执行清档操作!"
                 self .stop()
                 self .clearnow()
                 self .start()
         except  Exception,e:
             print  "连接数据库错误:%s"  %  e
             sys.exit( 2 )
 
 
     def  create( self ):
         '''一键搭服'''
         self .createDatabase()
         self .updateDB( '%s/%s/server/sql/database.sql'  %  ( self .workdir, self .version))
         self .mysqlgrant()
         self .createGameDir()
         self .updateconfig()
         self .createchat()
         self .nginxlogs()
 
     def  drop( self ):
         self .dumpDatabase()
         self .dropDatabase()
         self .dropGameDir()
         self .dropGameLogDir()
         self .dropchat()
 
     def  onekey( self ):
         '''一键更新'''
         self .stop()
         time.sleep( 10 )
         self .updategame()
         self .start()
 
     def  mysqlgrant( self ):
         '''添加数据库授权'''
         print  "正在添加数据库授权:"
 
         for  ip  in  self .payList:
             print  "正在添加%s权限"  %  ip
             cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "grant all privileges on *.* to game@'%s' Identified by 'cqbygame'" '''  %  ( self .admindbuser,  self .admindbpass, ip)
             subprocess.call(cmd, shell = True )
 
         cmd  =  ''' /usr/local/mysql/bin/mysql -u'%s' -p'%s' -e "grant select on *.* to db@'119.131.244.178' identified by 'lizhenjie';" '''  %  ( self .admindbuser,  self .admindbpass)
         subprocess.call(cmd, shell = True )
 
if  __name__  = =  "__main__" :
     active_list  =  [ 'create' 'drop' 'updateconfig' 'start' 'stop' 'clear' 'updategame' 'updateDB' , 'onekey' , 'mysqlgrant' , 'clearnow' ]
     gamever_list  =  [ 'test' , '37dev' , '37stable' ]
 
     usage  =  ''' usage: %prog -p platform
                        %prog -v version -i id -a action
                        %prog -v version -i id -a updateDB -s sqlfile
     '''
     parser  =  optparse.OptionParser(
         usage    =  usage,
         version  =  "%prog 2.0"
     )
 
     setplat_opts  =  optparse.OptionGroup(
         parser,  '设置服务器平台标识' ,
         '一台硬件服务器设置一次即可。'
     )
 
     setplat_opts.add_option(
         '-p' , '--platform' ,
         dest = "platform" ,
         help = "平台名称"
     )
 
     parser.add_option_group(setplat_opts)
 
     tools_opts  =  optparse.OptionGroup(
         parser,  '服务器日常功能' ,
     )
 
     tools_opts.add_option(
         '-v' , '--ver' ,
         dest = "ver" ,
         help = "版本目录" ,
         type = "choice"  ,
         choices = gamever_list,
         default = gamever_list[ 1 ]
     )
     tools_opts.add_option(
         '-i' , '--id' ,
         dest = 'id' ,
         help = "服务器ID"
     )
     tools_opts.add_option(
         '-a' , '--action' ,
         dest = 'action' ,
         help = "执行动作" ,
         type = "choice"  ,
         choices = active_list
     )
     tools_opts.add_option(
         '-s' , '--sql' ,
         dest = 'sql' ,
         help = "SQL文件(可选,配合updateDB使用)"
     )
 
     parser.add_option_group(tools_opts)
 
     options, args  =  parser.parse_args()
 
     err_msg  =  '参数不对,请输--help查看详细说明!'
 
     ini  =  'platform.ini'
     if  options.platform:
         apiurl  =  'http://yw.admin.xxx.com/yunwei/api/getplatforminfo/'
         ini  =  'platform.ini'
         result  =  urllib2.urlopen(apiurl)
         response  =  json.loads(result.read())
         for  code,  id  in  response.items():
             if  options.platform  = =  code:
                 platformid  =  id
                 print  "正在设置服务器标识为:%s-%s"  %  (platformid, options.platform)
                 cfd  =  open (ini,  'w' )
                 conf  =  ConfigParser.ConfigParser()
                 conf.add_section( 'platforminfo' )
                 conf. set ( 'platforminfo' , 'name' ,options.platform)
                 conf. set ( 'platforminfo' , 'id' ,platformid)
                 conf.write(cfd)
                 cfd.close()
                 break
         sys.exit( 0 )
 
     if  options. id  and  options.ver  and  options.action:
 
         cf  =  ConfigParser.ConfigParser()
         cf.read(ini)
         platform  =  cf.get( 'platforminfo' , 'name' )
         platformid  =  cf.get( 'platforminfo' , 'id' )
 
         cqby  =  Cqby(options.ver, platform, platformid, options. id )
         run_function  =  getattr (cqby,options.action)
 
         if  options.action  in  [ 'updateDB' ,]:
             run_function( '%s/server/sql/%s'  %  (options.ver,options.sql))
         else :
             run_function()
     else :
         parser.error(err_msg)


cqbyupdate.py批量维护脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/python
#coding:utf-8
 
import  threading
import  Queue
import  subprocess
import  optparse
import  logging
import  logging.config
import  datetime
import  os
import  sys
 
reload (sys)
sys.setdefaultencoding( 'utf-8' )
 
#test:
import  time
 
 
#logging.basicConfig(level = logging.DEBUG,format='(%(threadName)-10s) %(message)s',)
logging.config.fileConfig( "logger.conf" )
logger  =  logging.getLogger( "root" )
logger2  =  logging.getLogger( "file" )
queue  =  Queue.Queue()
 
Failed_List  =  []
 
class  Ahdts(threading.Thread):
     def  __init__( self , queue):
         super (Ahdts, self ).__init__()
         self .queue  =  queue
         self .workdir  =  '/data/init'
 
         #建立日志目录:
         log_path  =  'updatelog'
         today  =  datetime.date.today()
         self .log_path_today  =  '%s/%s'  %  (log_path,today)
         if  not  os.path.isdir( self .log_path_today):
             try :
                 os.makedirs( self .log_path_today)
             except  Exception,e:
                 print  e
                 sys.exit( 2 )
 
     def  run( self ):
         while  True :
             global  action
             global  sqlfile
 
             item  =  self .queue.get()
 
             value  =  item.strip().split( ',' )
             platform  =  value[ 0 ]
             id  =  value[ 1 ]
             ip  =  value[ 2 ]
             port  =  value[ 3 ]
             opentime  =  value[ 4 ]
 
             logging.debug( "%10s %6s %15s %15s %10s ThreadingStart!"  %  (platform, id ,ip,action,ver))
 
 
             if  action  = =  'rsync' :
                 cmd  =  ''' cd %s ; ./rsync '''  %  self .workdir
             elif  action  = =  'ntp' :
                 cmd  =  ''' cd %s ; ./TimeClient.py '''  %  self .workdir
             elif  action  in  [ 'updateDB' ,]:
                 cmd  =  '''  cd %s ; ./control.py -i %s -a %s -v %s -s %s '''  %  ( self .workdir,  id , action, ver, sqlfile)
             elif  action  = =  'platform' :
                 cmd  =  '''  cd %s ; ./control.py -p %s '''  %  ( self .workdir, platform)
             else :
                 cmd  =  '''  cd %s ; ./control.py -i %s -a %s -v %s '''  %  ( self .workdir,  id , action, ver)
             sshcmd  =  ''' ssh root@%s -n "%s" '''  %  (ip, cmd)
             with  open ( '%s/%s-%s-%s-%s.log'  %  ( self .log_path_today, platform,  id , ver, action),  'a' ) as logfile:
                 exitcode  =  subprocess.call(sshcmd,shell = True ,stdout = logfile, stderr = subprocess.STDOUT)
 
             if  exitcode  = =  0 :
                 logger2.debug( '%10s %6s %15s %15s %10s %s'  %  (platform,  id , ip, action, ver, cmd))
 
             rettxt  =  '%10s %6s %15s %15s %10s ThreadingEnd! ExitCode:%s'  %  (platform, id ,ip,action,ver,exitcode)
 
             if  exitcode:
                 Failed_List.append(rettxt)
 
             logging.debug(rettxt)
 
             self .queue.task_done()
 
 
if  __name__  = =  "__main__" :
     action_list  =  [ 'rsync' , 'create' , 'drop' , 'start' , 'stop' , 'clear' , 'updateconfig' , 'updategame' , 'updateDB' , 'onekey' ]
     gamever_list  =  [ 'test' , '37dev' , '37stable' ]
 
     usage  =  ''' usage: %prog --file <file.ini> --action <action>
     Forexample: %prog -f game-test.ini -a create
                 %prog -f game-test.ini -a onekey
                 %prog -f game-test.ini -a updateDB -s test.sql
     '''
     parser  =  optparse.OptionParser(
         usage    =  usage,
         version  =  "%prog 1.4"
     )
 
     parser.add_option( '-f' , '--file' ,dest = "file" , help = "IP文件列表" )
     parser.add_option( '-a' , '--action' ,dest = "action" , help = "执行动作" , type = "choice" ,choices = action_list)
     parser.add_option( '-v' , '--ver' , dest = 'ver' , help = "版本目录标识" , type = "choice" ,choices = gamever_list)
     parser.add_option( '-s' , '--sql' , dest = 'sql' , help = "待更新的SQL文件" )
     options, args  =  parser.parse_args()
 
     err_msg  =  '参数不对,请输--help查看详细说明!'
 
     if  options.action  and  options.ver  and  options. file :
         with  open (options. file ) as  file :
             content  =  file .readlines()
 
         action  =  options.action
         ver  =  options.ver
         sqlfile  =  options.sql
 
         maxThreadNum  =  200
         if  len (content) <  100 :
             maxThreadNum  =  len (content)
 
         for  in  range (maxThreadNum):
             =  Ahdts(queue)
             t.setDaemon( True )
             t.start()
 
         logging.debug( "%10s %6s %15s %15s %10s"  %  ( 'PlatForm' , 'ID' , 'IP' , 'Action' , 'Version' ))
 
         iplist  =  []
         for  in  content:
             ii  =  i.strip().split( ',' )
             ip  =  ii[ 2 ]
             if  action  in  [ 'rsync' , 'platform' and  ip  in  iplist:
                 continue
             queue.put(i)
             iplist.append(ip)
         queue.join()
 
         #打印执行失败列表:
         print  '='  *  20  +  '执行失败列表'  +  '='  *  20
         if  Failed_List:
             for  in  Failed_List:
                 print  i
         else :
             print  "None"
         print  '='  *  52
 
         logging.debug( "Done" )
     else :
         print  err_msg


批量维护脚本其实就是ssh远程过去游戏服执行control.py脚本,后面看能不能改成用socket的方式去连接,把socket的东西练练手,整套东西感觉还是比较简单。

本文转自运维笔记博客51CTO博客,原文链接http://blog.51cto.com/lihuipeng/1617958如需转载请自行联系原作者


lihuipeng

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2天前
|
运维 Oracle 容灾
Oracle dataguard 容灾技术实战(笔记),教你一种更清晰的Linux运维架构
Oracle dataguard 容灾技术实战(笔记),教你一种更清晰的Linux运维架构
|
4天前
|
敏捷开发 运维 监控
【专栏】微服务架构,以敏捷、灵活著称,通过拆分大型应用为小型自治服务,简化开发运维
【4月更文挑战第27天】微服务架构,以敏捷、灵活著称,通过拆分大型应用为小型自治服务,简化开发运维。本文探讨其基本概念、起源,核心优势(如敏捷开发、高可伸缩性)及挑战(系统复杂度、数据一致性),并分享实施策略(服务划分、技术选型、CI/CD)与实践案例(Netflix、Uber、Spotify),展示微服务如何重塑软件开发,并成为未来复杂应用系统的基础。
|
4天前
|
存储 缓存 负载均衡
从运维角度看中大型网站架构的演变之路
从运维角度看中大型网站架构的演变之路
|
4天前
|
运维 安全 数据处理
运维服务体系架构
【2月更文挑战第28天】构建数据中心的IT运维服务体系,需整合资源,规范行为,确保服务质量。该体系基于ITIL和ITSS标准,全面覆盖IT服务生命周期和业务类型,统筹规划并保持科学权威。体系由制度、流程、组织、队伍、技术平台和运维对象六部分组成,制度规定流程,组织和人员遵循制度执行标准化运维。重点包括运维服务制度与流程的制定、专业团队的建设和统一的工作流程,以及运用技术平台进行规范化管理。
|
9月前
|
运维 负载均衡 关系型数据库
【运维知识进阶篇】用Ansible Roles重构LNMP架构(Linux+Nginx+Mariadb+PHP),实现4个项目一键部署
【运维知识进阶篇】用Ansible Roles重构LNMP架构(Linux+Nginx+Mariadb+PHP),实现4个项目一键部署
116 0
|
4天前
|
运维 数据可视化
电子好书发您分享《可视化架构运维实践》
电子好书发您分享《可视化架构运维实践》
52 2
|
5月前
|
运维 关系型数据库 MySQL
阿里大牛的595页MySQL笔记,透彻即系数据库、架构与运维
数据库运维的变革,经历从手工造到脚本化、系统化、平台化、智能化的转变,逐步实现DBA对数据库的规范化、自动化、自助化、可视化、智能化、服务化管理,从而保障数据库的安全、稳定、高效运行。
|
7月前
|
存储 运维 关系型数据库
直播预告 | PolarDB-PG架构简介及日常运维浅析
本次分享将先从架构、特性、开源等三个维度解读PolarDB-PG的整体架构。在大家对架构有一定深入理解后,将继续从备份恢复、存储层、计算层扩容、只读节点提升、高可用等五个维度,对PolarDB-PG的日常运维进行深入浅出的介绍,为“唯手熟尔”的运维打好理论基础。
|
7月前
|
运维 Kubernetes Devops
基于k8s的devOps自动化运维平台架构设计(中英文版本)
基于k8s的devOps自动化运维平台架构设计(中英文版本)
|
9月前
|
人工智能 运维 负载均衡
云上运维架构
云上运维架构
云上运维架构