December 2015

You are browsing the site archives for December 2015.

与上交李小勇老师的讨论主要集中在公有云环境中块设备存储解决方案,就技术细节深入探讨。 块设备主要应用在虚拟机,同时也可封装后应用在对象存储等其他场景中。块设备存储为上层应用虚拟机提供巨大的存储池:这个巨大不仅体现在存储容量上,更体现在存储带宽方面。 而虚拟机对块设备的主要访问特点:大量随机I/O。如何解决好这些随机IO导致的性能问题是头等大事。 我们接下来从影响IO性能的几个方面来探讨。 采用SSD+异步IO SSD在处理随机IO上有着纯天然优势,其抛弃了传统的磁盘寻道的复杂开销。作为对比,传统的磁盘随机IOPS约为50,而SSD的随机IOPS可达到50000。 存储上利用Linux的异步IO(AIO),绕过文件系统page cache,一方面可直接将数据写入磁盘,保证数据可靠性(AIO通过DIRECT_IO实现)。另外一方面,可避免在高并发写时可能引起的dirty page写回可能导致的性能抖动。 采用异步写另外一个比较大的好处是不会引起程序的阻塞,尤其是在高并发场景中,采用异步epoll编程模型时,如果采用同步写方案,会导致系统线程数量的不可控,同时整个处理流程不简单清晰。 去中心化设计 去中心化设计的目标是将文件的写入位置通过实时计算而非中心节点查表。好处是减少写入开销。简化交互流程,无论是对系统性能还是程序的可维护性带来较大收益。但缺点也比较明显:集群扩容是可能需要较大量的数据迁移。 针对扩容问题的解决方案。扩容方式的改进:不再通过单个服务器方式进行扩容,而是以新的集群方式扩容,整个大的存储系统底层是一系列的小集群,姑且称之为存储池。每个池的大小约几十台机器的规模。存储容量约几百~1000TB。扩容时按照存储池为单位进行。 关于一致性协议 采用多副本,客户端推送多副本或者实现主从式数据推送(glusterfs采用客户端推多副本,但据说一致性不好弄???) 如果采用强一致性协议(所有副本写成功才返回成功)势必带来性能下降。可以采用变种:一个副本写成功了就算成功,如果其他副本写失败了再进行数据修复。 关于数据修复 ??? 如何解决list问题 传统分布式文件系统如glusterfs沿用了命名空间:将所有文件组织成目录树结构,但是此种做法极大加剧了分布式存储系统的复杂度。 可以为存储系统创建容器(container),写入对象时可指定容器名。而且一个容器内对象位于同一个存储集群(存储池)。在list一个容器内所有对象时,master将请求下发至所有数据节点,然后master对收到的结果作过滤汇总,然后返回给客户端。 性能如何??对每个数据节点作list其实性能也不一定高?假如每个数据节点上文件数量非常多的时候。 但是对于块设备存储时好像没有必要去解决文件命名空间问题,只有将其作为传统文件系统来使用时方才需要考虑这些问题。如何解决? 关于系统设计 能用硬件解决的就不要加大软件设计复杂性 如nxfs小文件优化,使用ssd就完全可以解决这个问题 避免过度设计 不要“拿大炮打苍蝇”,比如nxfs的一致性设计方案 避免过早优化 在不确定问题之前,采用最简单,最笨的方案。保证代码的可读性,系统的可维护性,只有在明确发现性能问题时,可以考虑牺牲代码可读性来优化系统性能。 其他 调研glusterfs以及scaleio 看看epoll内核实现 重点看看在边缘触发模式下为什么没有写事件通知  

Continue reading  与李小勇老师讨论记录

说明:本文转载自:http://www.xuebuyuan.com/1573107.html 终于在《情景》& think hard地情况下,想明白了! 一 系统调用do_fork() 当前进程调用fork()创建子进程,进入kernel 当前进程分一半多时间片给子进程, 如果当前进程时间片剩余为0,设定当前进程need_sched=1, 从系统调用退出 到达ret_from_sys_call 到达ret_with_reschedule 发现当前进程要求调度,跳转到reschedule 调用schedule() schedule()处理当前进程的调度要求, 如果有其他进程可运行,将在schedule()内发生切换。 二 定时钟断do_timer() 当定时钟断发生时8235->irq0->do_timer_interrupt()->do_timer() ->update_process_times()递减当前进程的时间片, 如果当前进程时间片为0,设定当前进程need_sched=1, 从中断调用退出, 到达ret_from_intr 到达ret_with_reschedule , 发现当前进程要求调度,跳转到reschedule 调用schedule() schedule()处理当前进程的调度要求, 如果有其他进程可运行,将在schedule()内发生切换。 三 唤醒进程wake_up_process() 当前进程调用fork()创建子进程,进入kernel 当前进程调用了wake_up_process来唤醒进程x 使进程x状态为RUNNING,并加入runqueue队列, 调用reschedule_idle() 发现进程x比当前进程更有资格运行,设定当前进程need_sched=1, 从系统调用退出 到达ret_from_sys_call 到达ret_with_reschedule 发现当前进程要求调度,跳转到reschedule 调用schedule() schedule()处理当前进程的调度要求, 如果有其他进程可运行,将在schedule()内发生切换。这次大多数可能切换到进程x 四 改变进程的调度策略setscheduler() 进入系统调用setscheduler() 改变进程x的调度策略 提前进程x在runqueue队列的位置 设定当前进程need_sched=1, 从系统调用退出 到达ret_from_sys_call 到达ret_with_reschedule 发现当前进程要求调度,跳转到reschedule 调用schedule() schedule()处理当前进程的调度要求, …

Continue reading need_resched 是怎么使用的