原创

Cell V2详解

: 本文之前已经在腾讯云tstack上发布过了https://cloud.tencent.com/developer/article/1473057,这里自己记录保存一份。

Cell V2 第一次出现是在 Ocata 版本,但当时仅仅只支持单个 Cell,对多个 Cell 的支持是在 Pike 版本中实现的。它的出现是为了解决单个 OpenStack 集群下计算节点过多,而导致数据库和消息队列压力过大,无法支持大规模部署的问题。

在 Pike 版本以前,一个 OpenStack 集群下,只有一个消息队列和一个数据库。由于计算节点需要定时进行资源上报,电源状态同步等任务,导致在计算节点数量过多时,通过消息队列上报的消息会非常巨大,甚至达到了消息队列和数据库的性能瓶颈,从而限制了整个 OpenStack 的集群规模。

本篇文章完全基于 OpenStack Pike 版本进行介绍,由于 Cell V2 是针对 Nova 组件的改动,因此全篇只会涉及到 Nova 组件。

概览

Cell V2出现之前的 Nova 组件架构如下所示,所有的 Nova Compute节点全部连接到同一个 MQ,在有大量定时任务通过 MQ 上报给 Nova Conductor服务的情况下,消息队列非常容易出现性能瓶颈,从而限制了整个集群的规模:

none-cellv2.png

使用 Cell V2 时的 Nova 组件架构如下,为了避免连线太多,这里将 Nova Compute, Nova Scheduler 服务和 Placement 服务之间的连线去掉了,同时还去掉了 Placement 服务和 API Cell DB之间的连线。

下图中的整个 Nova 服务由3部分组成,位于上层的 API Cell 和下层的 Cell01, Cell02。Cell01 和 Cell02 之间是平级关系,且相互无感知,我们还可以在下层继续增加新的 Cell,如 Cell03。在下文中,我们统一将下层的 Cell01, Cell02, Cell03 等称为 Cell,上层仍然称做 API Cell。

cellv2.png

API Cell 中主要包括了 Nova API, Nova Scheduler, Nova Conductor 这3个 Nova 服务,同时在 API Cell 中还需要 MQ 提供组件内的通信服务。API Cell 中的 DB 包含两个数据库,分别是 nova_api 和 nova_cell0 数据库,nova_api 数据库保存了全局数据,比如 flavor 信息。此外 nova_api 数据库中还有一部分表是用于 placement 服务的;而 nova_cell0 数据库则是用于保存创建失败且还没有确定位于哪个 cell 的虚机数据,比如当虚拟机调度失败时,该虚拟机数据就会被保存到 nova_cell0 数据库中。

在每个 Cell 中,都有自己独立使用的数据库、消息队列和 Nova Conductor 服务,当前 Cell 中的所有计算节点,全部将数据发送到当前 Cell 中的消息队列,由 Nova Conductor 服务获取后,保存至当前 Cell 的 Nova 数据库中。整个过程都不会涉及到 API Cell 中的消息队列。因此通过对计算节点进行 Cell 划分,可以有效降低 API Cell 中消息队列和数据库的压力。

假如一个 MQ 能支持200个计算节点,则在划分 Cell 以后,每个 Cell 都可以支持200个计算节点,有 N 个 Cell 就可以支持 N*200 个计算节点,因此可以极大提升单个 OpenStack 的集群管理规模。

Cell V2实现原理

在大致了解了 Cell V2 架构的基本组成后,接下来介绍一下在 Nova 组件中,究竟是如何实现 Cell 划分的。多 Cell 的实现涉及 nova_api 数据库中的3个表,分别是 cell_mappings, host_mappings, instance_mappings 表。这3个表之间的关系如下图所示,图中只列出了3个表中的主要字段信息:

db-rel.png

cell_mappings 表记录了每个 Cell 的名字和其消息队列连接地址与数据库连接地址,通过该表中记录的信息,API Cell 中的 Nova API 服务和 Nova Conductor 服务就知道该如何连接到 Cell 中的消息队列和数据库了,并进一步将消息发送到 Cell 中的消息队列,或者直接访问 Cell 中的 Nova 数据库。下图是 cell_mappings 表数据的简单示例,图中只列举了主要的几个字段:

cellmappings.png

在 host_mappings 表记录了计算节点和 Cell 之间的对应关系,而instance_mappings 表则记录了 instance 和 Cell 之间的对应关系。通过这两个表的映射关系,API Cell 中的服务就可以轻易知道计算节点或者虚拟机所处的 Cell,并通过 cell_mappings 数据表中提供的链接对其进行操作。

Cell 部署

当集群中的 MQ 或数据库已经无法再支撑更多的计算节点时,就可以规划一个新的 Cell,并将新的服务器规划到新的 Cell 中。要进行多 Cell 的部署,要求 OpenStack 版本必须是 Pike 或以上版本。

1. 安装部署 Cell 控制节点:

在不考虑高可用的情况下,使用一台物理机或虚拟机即可完成控制节点的部署,假如当前规划的是 CellN,则可以将控制节点称为 CellN-Controller。Cell 控制节点仅需安装3个服务:Cell DB(通常是 MySQL 或 Mariadb), MQ(通常是 RabbitMQ), Nova Conductor。

Cell DB:
    仅需要创建 Nova 数据库;

Nova Conductor:
    /etc/nova/nova.conf 中的 [database]/connection 必须配置为 CellN-Controller 上的 Nova 数据库,[DEFAULT]/transport_url 必须配置为 CellN-Controller 上的 MQ 连接地址;
cell-controller.png

2. 计算节点配置:

计算节点在进行安装配置时,唯一不同于 OpenStack 社区文档的地方就是对 nova.conf 中的 DEFAULT/transport_url 配置。在社区安装部署文档中,计算节点的 transport_url 通常指向的都是集群控制节点上的 MQ;而多 Cell 部署时,该地址必须修改为 CellN-Controller 中的 MQ 连接地址,否则计算节点就不会属于 CellN。

cell-compute.png

3. Cell 挂载到 OpenStack 集群:

通过第1步和第2步的安装部署,一个新的 Cell 就已经部署好了,此时计算节点已经可以正常上报资源,但 OpenStack 集群还无法对新 Cell 中的计算节点进行操作,比如向新 Cell 中创建 instance。

在前面 Cell V2 的实现原理中,我们提到了 host_mappings 和 cell_mappings 这两个表。当 Nova Scheduler 选中某个计算节点用于创建虚拟机后,Nova Conductor 就需要向计算节点所在 Cell 的 MQ 发送创建虚机的消息,要完成这个过程,需要3个步骤:

1. 查询 host_mappings 表,找到计算节点所在的 Cell;
2. 查询 cell_mappings 表,找到目的 Cell 中 MQ 的连接地址;
3. Conductor 服务连接目的 Cell 中的 MQ,并发起 rpc 调用;

因此第3步需要完成的事情,就是将 Cell 中的 MQ 连接地址和 Nova DB 连接地址保存进 cell_mappings 表中,其次再将 host 和 Cell 的映射关系保存进 host_mappings 表中。

# 在 cell_mappings 中新增 cell 数据
nova-manage cell_v2 create_cell \
--verbose --name cellN \
--transport-url rabbit://USER:PASSWD@CellN-Controller:5672/ \
--database_connection mysql://USER:PASSWD@CellN-Controller/nova

# 添加 host 与 cell 映射关系
nova-manage cell_v2 discover_hosts --verbose

资源上报

这里的资源上报指的是计算节点上 Nova Compute 服务的定时资源上报。资源上报分为两个部分,一是将资源数据保存到 nova 数据库的 compute_nodes 表中,这部分数据保存的是计算节点的详细信息,比如 cpu_info 等;二是调用 Placement API 进行资源更新,数据保存在 API Cell 中的 nova_api 数据库中,这部分更新的数据在 Pike 版本中仅仅只有 cpu/ram/disk 这3个数据,在之后的版本中,还逐渐增加了像 GPU 这一类数据。

report.png

上图中只保留了和资源上报有关的组件,nova-compute-101 节点在调用 virt_driver 的 get_available_resource 方法获取到主机资源后,如果发现资源发生了改变,则通过rpc调用 cell01 中的 nova-conductor 服务,将数据刷新到 cell 中的 nova DB 中;之后会通过 http 调用 Placement API,更新 Placement 服务中保存的 cpu/ram/disk 数据。

def update_available_resource(self, context, nodename):
    # 调用virt driver的get_available_resource接口获取资源信息
    resources = self.driver.get_available_resource(nodename)
    #...
    # 计算剩余资源并上报
    self._update_available_resource(context, resources)

def _update_available_resource(self, context, resources):
    #...
    # 根据已有的instances计算剩余资源
    self._update_usage_from_instances(context, instances, nodename)
    #...
    # 上报数据,cn是计算节点对象,记录了计算节点的资源信息
    self._update(context, cn)

def _update(self, context, compute_node):
    if self._resource_change(compute_node):
        # 仅当资源改变时,才会保存到nova.compute_nodes表
        compute_node.save()
    # 调用Placement API进行资源更新
    try:
        #...
        self.scheduler_client.set_inventory_for_provider(
            compute_node.uuid,
            compute_node.hypervisor_hostname,
            inv_data,
        )
    except NotImplementedError:
        self.scheduler_client.update_compute_node(compute_node)

创建instance

创建虚拟机的简要流程可以描述为如下几个步骤:

1. nova-api 接收用户发起的虚拟机创建请求,处理后通过 rpc 调用 nova-conductor 服务;

2. nova-conductor 服务收到请求后,会构造一个虚机创建任务,之后通过 rpc 调用 nova-scheduler 服务,选取满足 flavor 要求的物理主机;

3. nova-scheduler 首先调用 Placement 服务获取满足 cpu/ram/disk 要求的主机列表,然后再获取列表中所有主机的详情(这里需要到 nova-scheduler 服务去各个 cell 数据库查询主机详情),通过详情对主机进行进一步过滤,比如过滤掉状态为down的物理主机。最终会返回一个最优的主机给 nova-conductor 服务;

4. nova-conductor 在收到 nova-scheduler 返回的主机后,就需要将请求通过 rpc 发送给相应主机上的 nova-compute 服务进行处理。(nova-conductor 需要查询 host_mappings 和 cell_mappings,找到指定计算节点的 MQ 和 DB 连接地址)

5. nova-compute 收到来自 nova-conductor 的rpc调用,最终在主机上创建出虚拟机。

从前面5个简要步骤中,可以看出和 Cell V2 有关的主要有2个。一是 nova-scheduler 服务在调度时去获取主机详情;二是 nova-conductor 服务对目的 cell 中的 DB 和 MQ 操作。下面的代码只列出了与 Cell V2 相关的流程。

nova-scheduler 在调度过程中获取主机详情:

# nova-scheduler 服务主机调度入口方法
def select_destinations(self, ctxt,
                        request_spec=None, filter_properties=None,
                        spec_obj=_sentinel, instance_uuids=None,
                        schedule_class=None):
    #...
    # 调用 Placement 服务获取满足 cpu/ram/disk 要求的主机列表
    resources = utils.resources_from_request_spec(spec_obj)
    is_rebuild = utils.request_is_rebuild(spec_obj)
    alloc_reqs_by_rp_uuid, provider_summaries = None, None
    if self.driver.USES_ALLOCATION_CANDIDATES and not is_rebuild:
        res = self.placement_client.get_allocation_candidates(resources)
        # Placement返回结果是一个元组,第一个元素是可用主机列表(字典表示,提供了
        # compute_node的uuid和资源总量);第二个元素是一个字典(key为compute_node的uuid,
        # value为节点已使用的资源和资源总量情况。)

        # 示例:
        #   ([
        #     {
        #       'allocations': [
        #         {
        #           'resource_provider': {'uuid': 'af55778d-7526-4c15-88fa-055c6ff933d8'},
        #           'resources': {'VCPU': 2, 'MEMORY_MB': 4096, 'DISK_GB': 10}
        #         }
        #       ]
        #     }
        #   ],
        #   {
        #     'af55778d-7526-4c15-88fa-055c6ff933d8': {
        #       'resources': {
        #         'VCPU': {'used': 4, 'capacity': 128},
        #         'MEMORY_MB': {'used': 8192, 'capacity': 520992},
        #         'DISK_GB': {'used': 20, 'capacity': 1448}
        #       }
        #     }
        #   })

        #...

    # 对前面获取到的满足要求的主机进行进一步过滤
    dests = self.driver.select_destinations(ctxt, spec_obj, instance_uuids,
        alloc_reqs_by_rp_uuid, provider_summaries)
    dest_dicts = [_host_state_obj_to_dict(d) for d in dests]
    return jsonutils.to_primitive(dest_dicts)


# select_destinations 方法在进行主机过滤之前,会调用到scheduler/host_manager.py
# 中的 get_host_states_by_uuids 方法获取compute nodes详情和service等信息。
def get_host_states_by_uuids(self, context, compute_uuids, spec_obj):
    #...
    # 获取compute_nodes详情和services
    compute_nodes, services = self._get_computes_for_cells(
        context, cells, compute_uuids=compute_uuids)
    return self._get_host_states(context, compute_nodes, services)


def _get_computes_for_cells(self, context, cells, compute_uuids=None):
    compute_nodes = collections.defaultdict(list)
    services = {}
    # 遍历所有的cell,建立与cell之间的数据库连接,并查询参数
    # compute_uuids提供的所有compute node详情
    for cell in cells:
        # 获取目标 cell 的transport_url和database_connection,
        # 保存到context对象中,并建立与cell DB的连接
        with context_module.target_cell(context, cell) as cctxt:
            if compute_uuids is None:
                compute_nodes[cell.uuid].extend(
                    objects.ComputeNodeList.get_all(cctxt))
            else:
                # get_all_by_uuids 方法执行查询操作,并将compute_node数据
                # 库记录创建为compute_node对象。
                compute_nodes[cell.uuid].extend(
                    objects.ComputeNodeList.get_all_by_uuids(
                        cctxt, compute_uuids))
            services.update(
                {service.host: service
                    for service in objects.ServiceList.get_by_binary(
                            cctxt, 'nova-compute',
                            include_disabled=True)})
    return compute_nodes, services

nova-conductor 对目的 cell 的 DB/MQ 操作:

# nova-conductor 服务中创建虚拟机的主要方法
def schedule_and_build_instances(self, context, build_requests, ...):
    # 调用 nova-scheduler 为所有的 instances 选取主机
    instance_uuids = [spec.instance_uuid for spec in request_specs]
    try:
        # 虚机调度过程涉及的cellv2代码已在前面部分描述过了
        hosts = self._schedule_instances(context, request_specs[0],
                                            instance_uuids)
    except Exception as exc:
        #...

    for (build_request, request_spec, host) in six.moves.zip(
            build_requests, request_specs, hosts):
        # 查询 host 对应的 cell
        if host['host'] not in host_mapping_cache:
            try:
                # 如果 host 没有在缓存中,则会查询 nova_api 中的 host_mappings 表
                host_mapping = objects.HostMapping.get_by_host(
                    context, host['host'])
                host_mapping_cache[host['host']] = host_mapping
            except exception.HostMappingNotFound as exc:
                #...
        else:
            host_mapping = host_mapping_cache[host['host']]

        cell = host_mapping.cell_mapping

        try:
            #...
        except exception.BuildRequestNotFound:
            #...
        else:
            #...
            # 建立与目标 cell 的连接,并在目标 cell 的 nova 数据库中创建一条虚拟机数据
            with obj_target_cell(instance, cell):
                instance.create()
                instances.append(instance)
                cell_mapping_cache[instance.uuid] = cell

    for (build_request, request_spec, host, instance) in six.moves.zip(
            build_requests, request_specs, hosts, instances):
        # 获取 instance 对应的 cell
        cell = cell_mapping_cache[instance.uuid]
        #...
        with obj_target_cell(instance, cell) as cctxt:
            # 在目标 cell 的 nova 数据库中创建一些数据
            #...

        # 将 instance 与 cell 的映射关系写入到 nova_api 数据库的 instance_mappings 表中
        # 便于以后对 instance 进行操作时,查询其所在 cell。
        inst_mapping = objects.InstanceMapping.get_by_instance_uuid(
            context, instance.uuid)
        inst_mapping.cell_mapping = cell
        inst_mapping.save()

        #...
        # 将 instance 创建请求发送到目的 cell 中的 MQ,cctxt中保存了与目的 cell 中 MQ 的连接
        with obj_target_cell(instance, cell) as cctxt:
            self.compute_rpcapi.build_and_run_instance(
                cctxt, instance=instance, image=image,
                ...)

查询instance详情

虚拟机的详细信息是保存在 Cell DB 的 nova 数据库中的。因此要查询某个虚拟机的详细信息,同样涉及到查询 instance 所在 cell 的 DB 连接地址,之后由 Nova API 服务与目的 Cell DB 建立连接,并进行数据查询。

前面在分析虚拟机创建流程时,我们看到了 Nova Conductor 服务在执行 schedule_and_build_instances 方法时,将 instance 和 cell 的映射关系写入到了 API Cell 的 nova_api.instance_mappings 表中。在虚拟机创建完成以后,对虚拟机的所有操作都会涉及到该表的查询。

#...
# 将 instance 与 cell 的映射关系写入到 nova_api 数据库的 instance_mappings 表中
# 便于以后对 instance 进行操作时,查询其所在 cell。
inst_mapping = objects.InstanceMapping.get_by_instance_uuid(
    context, instance.uuid)
inst_mapping.cell_mapping = cell
inst_mapping.save()
#...

下面只涉及到 instance 详情查询过程中与 Cell V2 有关的代码:

# 查询 instance_mappings 表获取 instance 对应的 cell
def _get_instance_map_or_none(self, context, instance_uuid):
    try:
      	# 查询
        inst_map = objects.InstanceMapping.get_by_instance_uuid(
                context, instance_uuid)
    except exception.InstanceMappingNotFound:
        inst_map = None
    return inst_map


def _get_instance(self, context, instance_uuid, expected_attrs):
    #...
    # 通过instance uuid查询instance_mappings表,拿到instance所在cell的信息。
    inst_map = self._get_instance_map_or_none(context, instance_uuid)
    if inst_map and (inst_map.cell_mapping is not None):
        # 建立与 Cell 中的 MQ/DB 之间的连接,并保存到 context 对象中
        nova_context.set_target_cell(context, inst_map.cell_mapping)
        # 进行数据查询操作,context 对象保存了与 Cell DB 的连接
        instance = objects.Instance.get_by_uuid(
            context, instance_uuid, expected_attrs=expected_attrs)
    elif inst_map and (inst_map.cell_mapping is None):
        #...
    else:
        raise exception.InstanceNotFound(instance_id=instance_uuid)

    return instance

Cell V2 现状

目前 Pike 版本中的多 Cell 架构仍然存在一些问题,比如虚拟机在失败时无法进行重新调度;亲和/反亲和特性在多 Cell 架构下无法得到保障,并发情况下,极大概率出现不满足亲和/反亲和性的情况;跨 Cell 无法迁移虚拟机等问题。其中虚拟机失败重调度问题,在之后的版本中虽然已经解决,但是解决的办法其实并不完美,只是减少了失败的可能性。

虚拟机失败重调度问题:

Nova Compute 服务在创建虚拟机过程中如果出现了失败,在之前的版本中,会由 Nova Compute 向 Nova Scheduler 服务器发起 rpc 调用,进行重新调度,并排除已经发生了失败的计算节点,Nova Scheduler 服务则会从剩下的所有计算节点中,为虚拟机选取新一个新的计算节点。

这就要求 Nova Compute 服务和 Nova Scheduler 服务是连接到同一个 MQ 上的,否则 Nova Compute 服务无法对 Nova Scheduler 发起 rpc 调用。但在多 Cell 架构下,Nova Scheduler 服务连接到的是 API Cell 中的 MQ,而所有的计算节点,都连接到的是各自所在 Cell 中的 MQ,Compute 和 Scheduler 之间是无法通信的,这就导致了 Nova Compute 服务无法通过 rpc 调用 Scheduler 进行虚拟机重新调度。

在之后的 Queens 版本中,社区通过返回备用主机的方式,解决了这个问题。Nova Scheduler 服务在为虚拟机选中最优主机后,会从最优主机所在 Cell (这里不能跨 Cell 选择备用主机,因为不同 Cell 之间无法通过 MQ 进行通信) 中再选择 max_attempts - 1 个备用主机 (max_attempts为nova.conf中配置的重新调度次数),如果创建虚拟机发生了异常,则会由 Cell 中的 Nova Conductor 服务从备用主机中选择新主机,进行重新创建,直到创建完成或所有主机都失败即会停止。

这个过程就不会再出现 Nova Compute 调用 Nova Scheduler 的情况了,这种修改方法可以极大减少虚拟机创建失败的情况,但是备用主机却不一定是整个 OpenStack 集群中最优的节点,同时还可能发生所有备用主机都无法满足要求的情况。

多 Cell 架构下的亲和/反亲和问题:

假设2个 instance 需要满足亲和特性(即要将2个 instance 部署到相同的物理主机上),在并发创建这2个 instance的时候,Nova Scheduler 服务有很大概率会将2个 instance 调度到不同的物理主机上。

在非多 Cell 架构下,Nova Compute 服务会对 instance 的亲和/反亲和关系进行检查,如果发现不满足要求,则会触发重调度,由 Nova Scheduler 重新为 instance 选择主机,这样就能够保证2个 instance 最终会被创建到同一个主机上。

但在多 Cell 架构下,如果这2个 instance 被调度到了不同的 Cell,则即使通过备用主机的方式实现了重调度功能,这两个虚拟机仍然是无法满足亲和/反亲和特性的。此外,就算是2个虚拟机被调度到了同一个 cell 中,如果最优主机和备用主机不同,重调度仍然无法解决问题。

跨 Cell 迁移虚拟机问题:

虚拟机的冷迁移和热迁移功能,需要两个计算节点之间相互进行 rpc 调用,如果源主机与目的主机在同一个 Cell 下(连接到相同的 MQ),则迁移功能是没有问题的;但如果源主机和目的主机在不同的 Cell,主机之间无法通过 MQ 进行通信,则迁移虚拟机会失败。因此多 Cell 环境下的虚拟机迁移,仅能在同一个 Cell 下进行。

参考资料

  1. https://docs.openstack.org/nova/rocky/user/cellsv2-layout.html
  2. https://docs.openstack.org/nova/latest/user/cells.html
  3. https://docs.openstack.org/nova/pike/install/controller-install-rdo.html
  4. https://specs.openstack.org/openstack/nova-specs/specs/queens/implemented/return-alternate-hosts.html

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 史上最全全全全的Cell V2干货详解在这!

    ? 本文作者 / 鹏飞师兄 专注于OpenStack计算、Python; 热爱大海、雪山。 Cell V2详解 ? Cell V2 第一次出现是在 Ocata...

    腾讯云TStack
  • 目标检测算法YOLO-V2详解

    今天,我们一起学习下YOLO-V2跟YOLO-V1比起来都做了哪些改进?从速度优化和精确度优化的角度来看,主要有以下内容:

    智能算法
  • 【个人整理】一文看尽YOLO V2的10个改进技巧(下篇)

    YOLO V1 问世已久,风头很快就被SSD盖过,原作者rbg(Ross Girshick)大神自然不甘心,于是又在yolo v1的基础之上提出了YOLO v2...

    小草AI
  • Seurat Weekly NO.11 ||预告2021 Single Cell Genomics Day

    还记得2019年上的第一门比较完整和前沿的课程是Suerat团队的Single Cell Genomics Day,当时的议题有:

    生信菜鸟团
  • 微信小程序实战开发一:在小程序中使用useExtendedLib方法引入官方UI

    之前直接使用官方代码中的CSS来制作界面,后来又发现了一种方法,使用 useExtendedLib 引入官方UI库。

    睿儿网络郝刚
  • 单细胞测序下的骨髓微环境

    当你的才华还撑不起你的野心时,请潜下心来,脚踏实地,跟着我们慢慢进步。不知不觉在单细胞转录组领域做知识分析也快两年了,通过文献速递这个栏目很幸运聚集了一些小伙伴...

    生信技能树jimmy
  • Excel工具类

    剑行者
  • 目标检测算法YOLO-V3结构详解

    YOLO-V3模型框架,我们主要从它的基础网络Darknet-53以及YOLO-V3的结构方面学习,首先看下Darknet-53结构。

    智能算法
  • 单细胞分析揭示葡萄膜黑色素瘤新的进化复杂性

    每个人的时间精力有限,必须优先阅读相关文献,开设这个栏目也是希望为大家推荐高质量的单细胞相关文献。如果大家对单细胞转录组感兴趣可以关注一下,哪怕每天只学一点点,...

    生信技能树jimmy
  • BRCA1和BRCA2基因敲除小鼠的单细胞转录组

    数据在 https://www.ncbi.nlm.nih.gov/bioproject/PRJNA632854 :

    生信技能树
  • 论文精读|5th|YOLO v3的新特性|目标检测|附下载

    YOLO(You Only Look Once)是当今最有效的快速目标检测算法之一。虽然它现如今已经不是最准确的识别算法了,但依然是进行实时物体检测...

    用户7623498
  • 使用cell ranger拆分10X单细胞转录组原始数据

    cell ranger是10X genomics公司提供的,专门用于分析10X 单细胞转录组数据的pipeline, 包含了原始数据拆分,表达定量,聚类分析等多...

    生信修炼手册
  • 首先了解一下circRNA背景知识

    虽然是一个ID,但是也是需要理解的,这里我们仍然是以 发表在Cancer Cell International,时间是 November 2019 ,标题是 A...

    生信技能树
  • YOLO V2的10个改进技巧(上篇)

    YOLO V2的原始论文是,《YOLO9000: Better, Faster, Stronger 》,新的YOLO版本论文全名叫“YOLO9000: Bett...

    小草AI
  • 10X的单细胞转录组原始数据也可以在EBI下载

    然后呢,我们《生信技能树》目前出NGS数据处理教程,通常是会建议大家在EBI下载,这样的话,速度有保障!

    生信技能树
  • Docker Registry v2 配置文件详解

    /etc/docker/registry/config.yml 详解。 你可以在 docker run 时通过 -e 参数设置环境变量来配置。为了避免命令的繁杂...

    康怀帅
  • 轻量化神经网络综述

    深度神经网络模型被广泛应用在图像分类、物体检测等机器视觉任务中,并取得了巨大成功。然而,由于存储空间和功耗的限制,神经网络模型在嵌入式设备上的存储与计算仍然是一...

    SIGAI学习与实践平台
  • 轻量化神经网络综述

    深度神经网络模型被广泛应用在图像分类、物体检测等机器视觉任务中,并取得了巨大成功。然而,由于存储空间和功耗的限制,神经网络模型在嵌入式设备上的存储与计算仍然是一...

    SIGAI学习与实践平台
  • R语言之可视化(31)扫地僧easystats(2)相关性分析

    相关性是一个专注于相关性分析的easystats软件包。 它轻巧,易于使用,并允许计算许多不同类型的相关性,例如偏相关性,贝叶斯相关性,多级相关性,或Shepe...

    用户1359560

扫码关注云+社区

领取腾讯云代金券