• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

OpenStack Swift源码初探--proxy下的server.py

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

          OpenStack Swift作为开源的云存储工具,被越来越多的公司使用。为了记录和巩固学习swift的开源源码,所以进行一系列的源码开源学习笔记,供初学者快速学习和理解swift的内部功能。

          proxy下面的server.py模块是所有对account,container,object等对象进行管理操作的在swift的proxy端的总入口。在swift系统在接收到url请求后,先是经过middleware处理链分别验证处理后,再进入到proxy下面的server模块,进入 _call_方法调用后,把对应的请求分发给不同的controller处理,controller再调用各自的nodeStroage服务程序进行处理,返回各自的resp结果到server模块,最后通过mimmdleware处理链再反方向返回最终的请求处理结果

 

     1.首先server.py的整个结构如下图:包括4部分:一堆import引用,一个required_filters的字典,一个名为“Application(object)”的class ,一个app_factory(global_conf, **local_conf) 方法

   

     2.主要介绍“Application(object)”的class,其中包含了所有主要的功能方法

   

 

 2.1 _init_ 方法,Application类的初始化方法,主要就是初始化一些对象,包括:conf配置文件参数 的初始化,log日志初始化,memcache对象初始化,account_ring,container_ring, object_ring对象初始化等

 

2.2  check_config(self) 方法,主要是检查配置文件proxy-server.conf中配置的“read_affinity” 和“sorting_method”属性值是否正确,该方法在 app_factory(global_conf, **local_conf):方法时调用  

   

2.3 get_controller(self, path)方法,主要是根据传入的 urlPath解析并返回对应的control类和一个字典对象,其中字典对象的值根据传入url格式的不同返回不同的值

 

[python] view plaincopy
  1. def get_controller(self, path):  
  2.         """ 
  3.         Get the controller to handle a request. 
  4.  
  5.         :param path: path from request 
  6.         :returns: tuple of (controller class, path dictionary) 
  7.  
  8.         :raises: ValueError (thrown by split_path) if given invalid path 
  9.         """  
  10.         if path == '/info':  #url是/info 则返回InfoController和包括version,expose_info,disallowed_sections,admin_key的字典  
  11.             d = dict(version=None,  
  12.                      expose_info=self.expose_info,  
  13.                      disallowed_sections=self.disallowed_sections,  
  14.                      admin_key=self.admin_key)  
  15.             return InfoController, d  
  16.   
  17.         version, account, container, obj = split_path(path, 14True)  #以/拆分url为数列,并取对应的1到4位的数据返回给对应的变量  
  18.         d = dict(version=version,  
  19.                  account_name=account,  
  20.                  container_name=container,  
  21.                  object_name=obj)  
  22.         if obj and container and account: #根据解析出的account值,congtainer和object值得有无,确定适用的Controller是那种  
  23.             return ObjectController, d  
  24.         elif container and account:  
  25.             return ContainerController, d  
  26.         elif account and not container and not obj:  
  27.             return AccountController, d  
  28.         return None, d  


 

 

2.4  __call__(self, env, start_response)方法,是server模块的实际对account、container、object等对象调用处理的功能入口。

 

[python] view plaincopy
  1. def __call__(self, env, start_response):  
  2.         """ 
  3.         WSGI entry point. 
  4.         Wraps env in swob.Request object and passes it down. 
  5.  
  6.         :param env: WSGI environment dictionary 
  7.         :param start_response: WSGI callable 
  8.         """  
  9.         try:  
  10.             if self.memcache is None#首先判断是否memcache值存在,不存在再去获取一次  
  11.                 self.memcache = cache_from_env(env)  
  12.             req = self.update_request(Request(env)) #判断header中是否有x-storage-token和x-auth-token  
  13.             return self.handle_request(req)(env, start_response) #调用handle_request方法并返回处理的结果resp对象  
  14.         except UnicodeError:  
  15.             err = HTTPPreconditionFailed(  
  16.                 request=req, body='Invalid UTF8 or contains NULL')  
  17.             return err(env, start_response)  
  18.         except (Exception, Timeout):  
  19.             start_response('500 Server Error',  
  20.                            [('Content-Type''text/plain')])  
  21.             return ['Internal server error.\n']  


2.5 update_request(self, req)方法,根据请求中header里面的x-storage-token有而x-auth-token没有的情况,把x-storage-token的值赋予x-auth-token

 


2.6 handle_request(self, req)方法,server模块实际处理request请求的方法,熟悉servlet的同学可以把它理解成servlet的作用

 

[python] view plaincopy
  1. def handle_request(self, req):  
  2.         """ 
  3.         Entry point for proxy server. 
  4.         Should return a WSGI-style callable (such as swob.Response). 
  5.  
  6.         :param req: swob.Request object 
  7.         """  
  8.         try:  
  9.             self.logger.set_statsd_prefix('proxy-server'#在日志的开头加上‘proxy-server’,方便跟踪分析  
  10.             if req.content_length and req.content_length < 0#检查header里面中的Content-Length是否有值,无值返回错误请求,并日志记录  
  11.                 self.logger.increment('errors')  
  12.                 return HTTPBadRequest(request=req,  
  13.                                       body='Invalid Content-Length')  
  14.   
  15.             try:  
  16.                 if not check_utf8(req.path_info): #检查Pathde的编码是否不满足utf8,不满足返回错误请求,并日志记录  
  17.                     self.logger.increment('errors')  
  18.                     return HTTPPreconditionFailed(  
  19.                         request=req, body='Invalid UTF8 or contains NULL')  
  20.             except UnicodeError:  
  21.                 self.logger.increment('errors')  
  22.                 return HTTPPreconditionFailed(  
  23.                     request=req, body='Invalid UTF8 or contains NULL')  
  24.   
  25.             try:  
  26.                 controller, path_parts = self.get_controller(req.path) #调用get_controller(self,path)方法返回正确的controller类和字典对象  
  27.                 p = req.path_info  
  28.                 if isinstance(p, unicode):  
  29.                     p = p.encode('utf-8'#path编码Unicode转换utf-8  
  30.             except ValueError:           #发生值异常,返回错误请求,并日志记录  
  31.                 self.logger.increment('errors')  
  32.                 return HTTPNotFound(request=req)  
  33.             if not controller:         #为找到对应处理的controller类时,返回错误请求,并日志记录  
  34.                 self.logger.increment('errors')  
  35.                 return HTTPPreconditionFailed(request=req, body='Bad URL')  
  36.             if self.deny_host_headers and \    #当proxy-server.conf中deny_host_headers有值,且请求的header中的host在deny_host_headers中,则返回错误请求,并日志记录  
  37.                     req.host.split(':')[0in self.deny_host_headers:  
  38.                 return HTTPForbidden(request=req, body='Invalid host header')  
  39.   
  40.             self.logger.set_statsd_prefix('proxy-server.' +  
  41.                                           controller.server_type.lower()) #在日志的开头加上‘proxy-server.controller类中的请求类型(eg:HEAD/GET/PUT)’,方便跟踪分析  
  42.             controller = controller(self, **path_parts)  #初始化实际的controller对象(AccountController、ContainerController、ObjectController、InfoController其中之一)  
  43.             if 'swift.trans_id' not in req.environ:    #如果没有trans_id在env中,则重新生成一个,有些类似于http请求中的seesionID的感觉,是一种UUID  
  44.                 # if this wasn't set by an earlier middleware, set it now  
  45.                 trans_id = generate_trans_id(self.trans_id_suffix)  
  46.                 req.environ['swift.trans_id'] = trans_id  
  47.                 self.logger.txn_id = trans_id  
  48.             req.headers['x-trans-id'] = req.environ['swift.trans_id']  
  49.             controller.trans_id = req.environ['swift.trans_id']  
  50.             self.logger.client_ip = get_remote_client(req)  #把请求中获取出请求端的IP信息,加入logger对象,方便后续日志查看分析  
  51.             try:  
  52.                 handler = getattr(controller, req.method) #根据req.method方法获取对应controller对象中的方法(可能是多个,有的有public标签,有的没有)  
  53.                 getattr(handler, 'publicly_accessible'#再根据public标签获取最终的处理方法。(在方法前面可以加 @public 和@delay_denial)  
  54.             except AttributeError:  
  55.                 allowed_methods = getattr(controller, 'allowed_methods', set())  
  56.                 return HTTPMethodNotAllowed(  
  57.                     request=req, headers={'Allow'', '.join(allowed_methods)})  
  58.             if 'swift.authorize' in req.environ: #做鉴权操作  
  59.                 # We call authorize before the handler, always. If authorized,  
  60.                 # we remove the swift.authorize hook so isn't ever called  
  61.                 # again. If not authorized, we return the denial unless the  
  62.                 # controller's method indicates it'd like to gather more  
  63.                 # information and try again later.  
  64.                 resp = req.environ['swift.authorize'](req)  
  65.                 if not resp:  
  66.                     # No resp means authorized, no delayed recheck required.  
  67.                     del req.environ['swift.authorize']  
  68.                 else:  
  69.                     # Response indicates denial, but we might delay the denial  
  70.                     # and recheck later. If not delayed, return the error now.  
  71.                     if not getattr(handler, 'delay_denial'None):  
  72.                         return resp  
  73.             # Save off original request method (GET, POST, etc.) in case it  
  74.             # gets mutated during handling.  This way logging can display the  
  75.             # method the client actually sent.  
  76.             req.environ['swift.orig_req_method'] = req.method  
  77.             return handler(req)    #调用最终的method方法,并返回resp结果  
  78.         except HTTPException as error_response:  
  79.             return error_response  
  80.         except (Exception, Timeout):  
  81.             self.logger.exception(_('ERROR Unhandled exception in request'))  
  82.             return HTTPServerError(request=req)  

 

2.7 sort_nodes(self, nodes)方法,对nodes对象进行排序处理,该方法在iter_nodes(self, ring, partition, node_iter=None)中调用

 

[python] view plaincopy
  1. def sort_nodes(self, nodes):  
  2.         ''''' 
  3.         Sorts nodes in-place (and returns the sorted list) according to 
  4.         the configured strategy. The default "sorting" is to randomly 
  5.         shuffle the nodes. If the "timing" strategy is chosen, the nodes 
  6.         are sorted according to the stored timing data. 
  7.         '''  
  8.         # In the case of timing sorting, shuffling ensures that close timings  
  9.         # (ie within the rounding resolution) won't prefer one over another.  
  10.         # Python's sort is stable (http://wiki.python.org/moin/HowTo/Sorting/)  
  11.         shuffle(nodes)  
  12.         if self.sorting_method == 'timing':  #配置文件中排序方法为timing时,以时间排序  
  13.             now = time()  
  14.   
  15.             def key_func(node):  
  16.                 timing, expires = self.node_timings.get(node['ip'], (-1.00))  
  17.                 return timing if expires > now else -1.0  
  18.             nodes.sort(key=key_func)  
  19.         elif self.sorting_method == 'affinity'#配置文件中排序方法为affinity时,以自定义的亲和力规则排序  
  20.             nodes.sort(key=self.read_affinity_sort_key)  
  21.         return nodes  

 

2.8 set_node_timing(self, node, timing)方法,提供给外部程序调用

 

2.9    error_limited(self, node)方法,该方法在iter_nodes(self, ring, partition, node_iter=None)中调用

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
窥探Swift编程之强大的Switch发布时间:2022-07-14
下一篇:
[Swift]LeetCode797.所有可能的路径|AllPathsFromSourcetoTarget发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap