1. 前端图表如果处理大量数据该怎么办
浅谈一下Cognos处理大数据的思路,仅针对10.2.1以下的版本,对于10.2.1当中引入的hadloop等分布式数据仓库等不做介绍。我们主要从一个一般中等项目当中,用怎样的思路来优化我们的查询。
我们主要从3个思路来思考大数据的处理
一、数据库层次
现在主流的Cognos项目,主要的开发模式还是基于rolap的dmr报表建模。因此,数据库的优化就显得由为重要。主要通过以下几个方面优化我们的数据库:
(1)维度id,维度层次id等关键减缩字段建立索引建立、维护。
(2)根据数据量的大小,按时间等进行分区优化。
(3)高速缓冲表MQT的使用
(4)表空间、缓冲池设置等
(5)数据库性能优化
二、Cognos Server优化
Cognos优化包括对配置文件的优化,集群的搭建,服务和日志的开启等基于cognos 软件安装,配置的优化,主要包括以下几个方面:
2.1 apache 配置优化
Timeout(超时)/MaxKeepAliveRequests(最大的请求数)/KeepAliveTimeout(请求超时)的优化配置
2.2Cognos自带tomcat配置调优
(1)可修改TOMCAT配置文件CRN_ROOT\tomcat.\conf\server.xml。其参数集中在行:
可以对maxProcessors(最大进程数)/AcceptCount(最大连接数) ConnectionTimeout(连接超时)进行修改
(2)文件路径:CRN_ROOT\tomcat.\conf\web.xml
可以对session-timeout进行修改.
2.3Cognos sever配置文件优化
2.3.1 reportservice.xml优化
文件路径:CRN_ROOT\ webapps\p2pd\WEB-INF\services\ reportservice.xml
注:修改文件后,重启服务后配置生效。
包括以下参数 max_process(交互报表处理进程数,和cpu有关) inger_process(交互报表初始化进程数,和cpu优关)
max_non_affine_connections_per_process(交互报表所占线程数) idle_process_check_interval_ms(空闲检测时间)
queue_time_limit_ms(报表服务队列时间限制) async_wait_timeout_ms(Dispatcher请求等待同步时间)
2.3.2 batchreportservice.xml
文件路径:CRN_ROOT\ webapps\p2pd\WEB-INF\services\ batchreportservice.xml
注:修改文件后,重启服务后配置生效。
包括以下参数 max_process(服务批量报表处理所占进程数) linger_process(服务批量报表处理初始化进程数)
max_non_affine_connections_per_process(服务批量报表处理所占线程数) idle_process_check_interval_ms(空闲进程检测时间间隔)
idle_process_max_idle_ticks(空闲进程检测标记) queue_time_limit_ms(批量报表处理排队时间限制) async_wait_timeout_ms(Dispatcher请求等待同步时间)
2.3.3 CQEConfig.xml
主要是与数据库参数设置,文件路径:CRN_ROOT\configuration\ CQEConfig.xml.sample
注:将CQEConfig.xml.sample文件名修改为CQEConfig.xml后,重启服务后配置生效。
可以修改以下参数:Timeout(应用数据库连接超时设置) PoolSize(应用数据库连接池最大连接数设置) queryReuse(查询缓冲设置)
2013-07-08 0
分享
答案对人有帮助,有参考价值1
曾力 - Cognos讲师、Cognos独立顾问、数据仓库架构师 2013-07-08 回答
2.3.4 ppds_cfg.xml
主要进行缓存和日志参数设置,文件路径:\cognos\c8\configuration\ ppds_cfg.xml
注:重启服务后配置生效。
可以修改以下参数:ReadCacheSize(可减少用户访问时服务器的磁盘IO。提高访问速度。) pcQueryLogFile(建议生产环境关闭该日志的跟踪,一般默认也是关闭状态)
2.4 Cognos content store优化
2.4.1优化内容库连接服务
内容库最好外配为db2 oracle等数据库,不要用自带的derby.因为项目中的日志信息会非常多,严重影响内容库的效率。
Cognos Administration,在系统下选择选择对应的服务,选择ContentManagerService的属性,设置相应的连接参数信息。
2.4.2日志优化
适当开启各个cognos服务的日志级别,越高级的级别对应更详细,更明确的日志,但也会影响整个系统的效率。
这是一把双刃剑,需要适当调整。日志级别设置得越高,就越降低系统性能。通常情况下,您可以将级别设置为
“最小”或“基本”来收集错误,或设置为“请求”来收集错误和警告。
2.5提高访问数据库速度
Cognos和数据库间参数在cer\bin\cogdm.ini文件中,(根据版本不同是安装目录的数字,根据连接的数据库不同,是对应数据库名称的关键字)
以oracle数据库为例,参数在cogdmor.ini文件中,打开这个文件查找字符串Fetch Number of Rows=去掉这行前面的分号,将10改成2000;
这样这行就成了Fetch Number of Rows=2000,表示是每次从数据库取2000条数据。其他数据库基本上都有类似的配置。用以提高从数据库中提取数据的速度。
2.6加大缓存
cer\bin\Cer.ini(*根据版本不同是安装目录的数字):
SortMemory=5120
(这里 SortMemory 单位是 2kbytes,5120代表 2k x 5120 = 10M)(技巧:一般 SortMemory 取空闲内存的十分之一到八分之一大小)
2.7修改cognos configuration中的参数来优化
在cognos configuration中有很多参数可以优化来提高整体软件的运行效率,比如增加内存、增加查询缓存
2.8分布式部署
分布式部署可以大大提升Cognos服务器的负载能力,同时容错保护功能可以使服务器更为稳定的运行,很好的支持大用户量的并发使用。
2013-07-08 0
答案对人有帮助,有参考价值1
曾力 - Cognos讲师、Cognos独立顾问、数据仓库架构师 2013-07-08 回答
3.报表设计优化
Cognos报表作为一个工具,在非cube模式下,最终我们执行报表查询的时候,我们的报表发送到数据库进行查询的本质还是sql,所以,在我们制作一张报表的时候,我们要尽可能的利用fm,rs当中的功能,优化报表最终执行生成的SQL实现整个报表的优化。而CUBE模式下,我们更多要考虑配置、存放和数据库大小所造成的影响,下面我会细细说来。
2013-07-08 0
答案对人有帮助,有参考价值1
曾力 - Cognos讲师、Cognos独立顾问、数据仓库架构师 2013-07-08 回答
3.1 FM建模优化
3.1.1手写SQL定制查询主题
右键点击查询主题的菜单项Edit Definition…可以进入SQL语句编写框,调整查询主题的SQL语句。默认情况下,这里的SQL语句为Cognos SQL类型。如果需要编写应用数据库可以直接运行的本地SQL需要将这里的SQL类型进行设置。点击右上方的Options按钮,选择SQL Settings标签页,选择SQL Type为Native。这个时候,我们手写SQL就非常注重这个SQL的优化,尽量避免SELECT *,用EXISTS替代IN,多使用DECODE来进行判断,条件语句注意点等常用SQL优化策略,编写对应的SQL.
3.1.2尽量使用特定数据的数据库函数
在菜单项Actions中选择Specify Package Function List…指定报表定制中可以使用的数据库函数列表。将除应用数据库意外的其他数据库类型从Selected function sets中选到Available function sets中,尽量使用特定数据库的自带函数可以提高查询效率。
3.1.3表关联设定
在建立表关联尽量避免使用外关联关系(包括左外关联、右外关联、全外关联)。外关联的使用会使数据库的查询压力骤增,从而影响前端报表的生成。在星型结构、雪花型结构的数据仓库模型中,尽量按照一对一、一对多的关联关系设定维表与实事表之间的关联,Cognos Server会依照这里的关联关系自动优化提交给数据库的SQL语句。如果关联关系中出现了环状连接关系,可以通过别名表或是快捷键的方式解决环状连接问题.
3.1.4Edit Governors查询性能设置
在菜单项Project中选择Edit Governors,可以设置查询的查询性能
Report table limits 该属性设置报表中运行SQL所涉及的TABLE数量
Data retrieval limits 该属性设置报表中运行SQL返回结果的数量
Query execution time limits 该属性设置报表中运行SQL的执行时间
Large text items limit 该属性设置报表中运行SQL返回大文字块的字符数量限制
2013-07-08 0
答案对人有帮助,有参考价值1
曾力 - Cognos讲师、Cognos独立顾问、数据仓库架构师 2013-07-08 回答
3.2 RS报表调优
3.2.1报表函数的使用
在报表函数的使用上,尽可能使用应用数据库能够解析的本地数据库函数,函数列表中的通用函数,在处理时会将函数放在报表服务器进行运算,从而增大了报表服务器的性能开销。
3.2.2 观察查询的SQL
我们选择查询页面,GENERATE SQL/MDX观察这个报表生成的SQL并进行不断优化,
3.3.33.2 RS报表调优
3.2.1报表函数的使用
在报表函数的使用上,尽可能使用应用数据库能够解析的本地数据库函数,函数列表中的通用函数,在处理时会将函数放在报表服务器进行运算,从而增大了报表服务器的性能开销。
3.2.2 观察查询的SQL
我们选择查询页面,GENERATE SQL/MDX观察这个报表生成的SQL并进行不断优化,
3.3.3查询字段、查询表顺序调整
根据数据库的优化策略,可能需要将查询字段的顺序进行调整,可以在Data Items窗口中进行设置。查询SQL语句中,From关键字后面的表顺序是按照select关键字后出现的字段顺序进行设置的。在为表顺序进行设置时,属性为Identifier或Attribute的字段比属性为Fact的字段在为表排序时的优先级要高,即,先以Identifier、Attribute字段的出现顺序为表进行排序,如果没有上述两类字段,才以Fact字段的出现顺序为表进行排序。
3.3.4聚合前后设置过滤条件
将过滤条件的Application属性设置为After aggregation或Before aggregation可以调整过滤条件在聚合前或是聚合后生效。After aggregation生成过滤条件的SQL语句使用的是关键字having,而Before aggregation生成过滤条件的SQL语句使用的是关键字where。
3.3.5取消报表自动分组提高明细报表查询速度
如果报表要展现明细数据,不想使用任何汇总,我们可以到此报表对应的查询中将自动分组属性定义为否。修改地方:对象的属性Auto Group & Summarize可以设置当前SQL语句的查询中是否加入distinct、sum、group by这样的关键字。默认情况下,该属性设置为Yes,可以根据查询情况关掉此开关项,减少SQL语句的复杂度。
3.3.6自动排序设置
在Query的Auto-sort属性中可以为查询设置是否自动排序。如果选择是,则会在生成的SQL语句中自动加入Order By关键字,排序字段将自动根据数据项的属性进行设置(如果查询字段的usage属性为Attribute、Identifier则排序,如果为Fact则不排序);如果选择否、则不排序;如果选择最小,则根据数据项的排序属性进行排序设置。默认值为最小。
3.3.7报表Processing设置
在Query的Processing属性中可以为查询设置SQL的处理设置。Cognos Report Studio会将报表的所有设置首先转换为Cognos SQL提交给报表服务器,服务器在进行必要处理后,会将SQL语句转换为应用数据库本地执行的SQL语句,进行数据库处理。为提高报表的处理速度,要尽可能的将报表的处理运算放在数据库进行,以保证其运行速度。将该属性设置为Database only会将报表页面生成的Cognos SQL不经报表服务器处理全部转换为数据库能够执行的本地数据库SQL,如果将该属性设置为Limited Local,则将报表页面生成的Cognos SQL先进行必要的报表服务器运算,然后再将剩余的部分提交给数据库进行本地SQL的处理。默认值为Framework中为Datasource对象的设置的queryProcessing属性。
3.3.8使用With子句
在Query的Use SQL With Clause属性中可以为查询设置是否使用With子句。部分数据库例如Oracle支持With关键字,当查询中嵌套子查询时,可以通过With子句的使用,减轻报表服务器对Cognos SQL的处理,从而提升报表的运行性能。如果将该属性设置为Yes,则允许使用With关键字,查询中生成的Native SQL将出现With子句;如果将该属性设置为No,虽然拒绝使用With关键字。默认值为Framework中Edit Governors下的Use WITH clause when generating SQL属性设置。
3.3.9报表服务器本地缓存设置
在Query的Use Local Cache属性中可以为查询设置是否使用本地缓存。如果将该属性设置为Yes,则启用服务器的本地缓存,服务器将为查询结果保存在session中,当用户在浏览器内再次打开同一张报表时,查询结果将取自缓存,从而减轻了数据库的负载压力;如果将该属性设置为No,则禁用服务器的本地缓存,查询结果全部取自数据库的实时数据。默认值为Framework中Edit Governors下的Allow usage of local cache属性设置。
我用的是finereport,比这个方便
2. spring boot 怎么实现集群
Helloworld使用传统的springmvc,需要配置web.xml,applicationContext.xml,然后打包为war在tomcat中运行,而如果使用springboot,一切都变得简单起来了。下面使用Maven来创建springboot的webapp工程pom.xml4.0.0org.springframeworkgs-spring-boot0.1.0org.springframework.bootspring-boot-starter-parent1.3.3.RELEASEorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testtest1.8org.springframework.bootspring-boot-maven-;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@{@RequestMapping("/")publicStringindex(){return"GreetingsfromSpringBoot!";}}其中:@RestController表示使用springmvc来接收request请求@RequestMapping映射到主页当请求返回的时候,是纯文本,那是因为@RestController是由@Controller和@ResponseBody组成Application@{publicstaticvoidmain(String[]args){ApplicationContextctx=SpringApplication.run(Application.class,args);System.out.println("Let':");}}其中:@SpringBootApplication代表了其有四个注解组成:@Configuration,@EnableAutoConfiguration,@EnableWebMvc,@ComponentScan在SpringApplication.run中会去自动启动tomcatrun方法返回上下文,在这个上下文中可以拿到所有的bean没有一行配置代码、也没有web.xml。基于SpringBoot的应用在大多数情况下都不需要我们去显式地声明各类配置,而是将最常用的默认配置作为约定,在不声明的情况下也能适应大多数的开发场景。总体而言springboot是对javawebapp开发的简化单元测试@RunWith(SpringJUnit4ClassRunner.class)@(classes=MockServletContext.class)@{privateMockMvcmvc;@Beforepublicvoidbefore()throwsException{mvc=MockMvcBuilders.standaloneSetup(newHelloController()).build();}@Afterpublicvoidafter()throwsException{}/****Method:index()**/@TestpublicvoidtestIndex()throwsException{//TODO:Testgoesheremvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(content().string(equalTo("GreetingsfromSpringBoot!")));}}建立restfullweb服务器接上,使用srpingboot建立web服务器就非常简单了,首先建立一个pojo类publicclassGreeting{privatefinallongid;privatefinalStringcontent;}然后使用control来handlehttp请求@{="Hello,%s!";privatefinalAtomicLongcounter=newAtomicLong();@RequestMapping("/greeting")publicGreetinggreeting(@RequestParam(value="name",defaultValue="World")Stringname){returnnewGreeting(counter.incrementAndGet(),String.format(template,name));}}其中:@RequestParam表明了参数要求,如果要必填则设置required=true返回是一个对象,会被自动转换为json当我们访问:greeting时候返回{"id":1,"content":"Hello,World!"}greeting?name=User时候返回{"id":2,"content":"Hello,User!"}数据库访问另一个非常常用的问题。在传统开发中,我们需要配置:类路径上添加数据访问驱动实例化DataSource对象,指定url,username,password注入JdbcTemplate对象,如果使用Mybatis,还要配置框架信息下面一个例子讲述用用springboot来代替。数据访问层我们将使用SpringDataJPA和Hibernate(JPA的实现之一)。开始之前先介绍两个概念springdata为了简化程序与数据库交互的代码,spring提供了一个现成的层框架,spring家族提供的spring-data适用于关系型数据库和nosql数据库;例如SpringDataJPA,SpringDataHadoop,SpringDataMongoDB,SpringDataSolr等;具体的可以参考官网:.mysql.jdbc.Driverspring.datasource.password=xxx#SpecifytheDBMSspring.jpa.database=MYSQL#.jpa.show-sql=true#Hibernateddlauto(create,create-drop,update)spring.jpa.hibernate.ddl-auto=update#Namingstrategyspring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy#)spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect其中,hibernate的ddl-auto=update配置表名,数据库的表和列会自动创建写下实体类:@Entity@Table(name="student")publicclassStudent{@Id@GeneratedValue(strategy=GenerationType.AUTO)privatelongid;@NotNullprivateStringname;privateStringage;}@Entity,说明被这个注解修饰的类应该与一张数据库表相对应,表的名称可以由类名推断,当然了,也可以明确配置,只要加上@Table(name="books")即可。需要特别注意,每个Entity类都应该有一个protected访问级别的无参构造函数,用于给Hibernate提供初始化的入口。@Idand@GeneratedValue:@Id注解修饰的属性应该作为表中的主键处理、@GeneratedValue修饰的属性应该由数据库自动生成,而不需要明确指定。@ManyToOne,@ManyToMany表明具体的数据存放在其他表中,在这个例子里,书和作者是多对一的关系,书和出版社是多对一的关系,因此book表中的author和publisher相当于数据表中的外键;并且在Publisher中通过@OneToMany(mapped="publisher")定义一个反向关联(1——>n),表明book类中的publisher属性与这里的books形成对应关系。@Repository用来表示访问数据库并操作数据的接口,同时它修饰的接口也可以被componentscan机制探测到并注册为bean,这样就可以在其他模块中通过@Autowired织入。:@{ListfindByLastName(StringlastName);}详细的可以看springjpa的具体介绍。最后使用:@{@AutowiredprivateStudentDao;@RequestMapping("/get-student-counts")@(){Liststudents=(List).findAll();returnString.format("%d",students.size());}}主要一点是:我在CustomerRepository实现中每天添加方法:findByLastName,@Autowired就会一直报错。
3. 网站性能优化怎么办
一、前端优化
网站性能优化是一个很综合的话题,涉及到服务器的配置和网站前后端程序等各个方面,我只是从实际经历出发,分享一下自己所尝试过的网站性能优化方法。之所以在标题上挂一个web2.0,是因为本文更偏重于中小网站的性能优化,我所使用的系统也是典型web2.0的LAMP架构。
首先讲讲前端的优化,用户访问网页的等待时间,有80%是发生在浏览器前端,特别是页面和页面中各种元素(图片、CSS、Javascript、 flash…)的下载之上。因此在很多情况下,相对于把大量的时间花在艰苦而繁杂的程序改进上,前端的优化往往能起到事半功倍的作用。雅虎最近将内部使用的性能测试工具yslow向第三方公开,并发布了着名的网站性能优化的十三条规则,建议你下载并安装yslow,并作为测评网站优化效果的工具。下面我挑其中特别有价值的具体说明一下优化的方法:
对于第一次访问您网站,尚未在浏览器cache中缓存您网站内容的用户,我们可以做的事情包括:
1)减少一个页面访问所产生的http连接次数
对于第一次访问你网站的用户,页面所产生的http连接次数是影响性能的一个关键瓶颈。
对策:
- 尽量简洁的页面设计,最大程度减少图片的使用,通过放弃一些不必要的页面特效来减少javascript的使用。
- 使用一些优化技巧,比如利用图片的背景位移减少图片的个数;image map技术;使用Inline images将css图片捆绑到网页中。
- 尽量合并js和css文件,减少独立文件个数。
2) 使用gzip压缩网页内容
使用gzip来压缩网页中的静态内容,能够显着减少用户访问网页时的等待时间(据说可达到60%)。主流的web服务器都支持或提供gzip压缩,如果使用apache服务器,只需要在配置文件中开启 mod_gzip(apache1.x)或mod_deflate(apache2.x)即可。凡是静态的页面,使用gzip压缩都能够显着提高服务器效率并减少带宽支出,注意图片内容本身已经是压缩格式了,务必不要再进行压缩。
3)将CSS放在页面顶端,JS文件放在页面底端
CSS的引用要放在html的头部header中,JS文件引用尽量放在页面底端标签的后面,主要的思路是让核心的页面内容尽早显示出来。不过要注意,一些大量使用js的页面,可能有一些js文件放在底端会引起一些难以预料的问题,根据实际情况适当运用即可。
4)使JS文件内容最小化
具体来说就是使用一些javascript压缩工具对js脚本进行压缩,去除其中的空白字符、注释,最小化变量名等。在使用gzip压缩的基础上,对js内容的压缩能够将性能再提高5%。
5)尽量减少外部脚本的使用,减少DNS查询时间
不要在网页中引用太多的外部脚本,首先,一次dns的解析过程会消耗20-120毫秒的时间;其次,如果在页面中引用太多的外部文件(如各种广告、联盟等代码),可能会因为外部文件的响应速度而将你的网站拖得很慢。如果不得不用,那么就尽量将这些脚本放在页脚吧。不过有一点需要提及,就是浏览器一般只能并行处理同一域名下的两个请求,而对于不同子的域名则不受此限制,因此适当将本站静态内容(css,js)放在其他的子域名下(如 static.xxx.com)会有利于提高浏览器并行下载网页内容的能力。
对于您网站的经常性访问用户,主要的优化思路就是最大限度利用用户浏览器的cache来减少服务器的开销。
1)在header中添加过期时间(Expires Header)
在header中给静态内容添加一个较长的过期时间,这样可以使用户今后访问只读取缓存中的文件,而不会与服务器产生任何的交互。不过这样做也存在一些问题,当图片、CSS和js文件更新时,用户如果不刷新浏览器,就无法获得此更新。这样,我们在对图片、css和js文件修改时,必须要进行重命名,才能保证用户访问到最新的内容。这可能会给开发造成不小的麻烦,因为这些文件可能被站点中的许多文件所引用。flickr提出的解决办法是通过url rewrite使不同版本号的URL事实上指向同一个文件,这是一个聪明的办法,因为url级别的操作效率是很高的,可以给开发过程提供不少便利。
要理解为什么这样做,必须要了解浏览器访问url时的工作机制:
a. 第一次访问url时,用户从服务器段获取页面内容,并把相关的文件(images,css,js…)放在高速缓存中,也会把文件头中的expired time,last modified, ETags等相关信息也一同保留下来。
b. 用户重复访问url时,浏览器首先看高速缓存中是否有本站同名的文件,如果有,则检查文件的过期时间;如果尚未过期,则直接从缓存中读取文件,不再访问服务器。
c. 如果缓存中文件的过期时间不存在或已超出,则浏览器会访问服务器获取文件的头信息,检查last modifed和ETags等信息,如果发现本地缓存中的文件在上次访问后没被修改,则使用本地缓存中的文件;如果修改过,则从服务器上获取最新版本。
我的经验,如果可能,尽量遵循此原则给静态文件添加过期时间,这样可以大幅度减少用户对服务器资源的重复访问。
2)将css和js文件放在独立外部文件中引用
将css和js文件放在独立文件中,这样它们会被单独缓存起来,在访问其他页面时可以从浏览器的高速缓存中直接读取。一些网站的首页可能是例外的,这些首页的自身浏览可能并不大,但却是用户访问网站的第一印象以及导向到其他页面的起点,也可能这些页面本身使用了大量的ajax局部刷新及技术,这时可以将 css和js文件直接写在页面中。
3)去掉重复的脚本
在IE中,包含重复的js脚本会导致浏览器的缓存不被使用,仔细检查一下你的程序,去掉重复引用的脚本应该不是一件很难的事情。
4)避免重定向的发生
除了在header中人为的重定向之外,网页重定向常在不经意间发生,被重定向的内容将不会使用浏览器的缓存。比如用户在访问www.xxx.com,服务器会通过301转向到www.xxx.com/,在后面加了一个“/”。如果服务器的配置不好,这也会给服务器带来额外的负担。通过配置apache的 alias或使用mod_rewrite模块等方法,可以避免不必要的重定向。
还有一些,比如使用CDN分发机制、避免CSS表达式等、避免使用ETags等,因为不太常用,这里就不再赘述了。
做完了上述的优化,可以试着用yslow测试一下网页的性能评分,一般都可以达到70分以上了。
当然,除了浏览器前端和静态内容的优化之外,还有针对程序脚本、服务器、数据库、负载的优化,这些更深层次的优化方法对技术有更高的要求。本文的后半部分将重点探讨后端的优化。
二、后端优化
上次写完web2.0网站前端优化篇之后,一直想写写后端优化的方法,今天终于有时间将思路整理了出来。
前端优化可以避免我们造成无谓的服务器和带宽资源浪费,但随着网站访问量的增加,仅靠前端优化已经不能解决所有问题了,后端软件处理并行请求的能力、程序运 行的效率、硬件性能以及系统的可扩展性,将成为影响网站性能和稳定的关键瓶颈所在。优化系统和程序的性能可以从以下的方面来入手:
1)apache、mysql等软件的配置的优化
尽管apache和mysql等软件在安装后使用的默认设置足以使你的网站运行起来,但是通过调整mysql和apache的一些系统参数,还是可以追求更高的效率和稳定性。这个领域中有很多专业的文章和论坛(比如: http://www.mysqlperformanceblog.com/),要想掌握也需要进行深入的研究和实践,这里就不重点讨论了。
2)应用程序环境加速
这里仅以我最常应用的php开发环境为例,有一些工具软件可以通过优化PHP运行环境来达到提速的目的,其基本原理大致是将PHP代码预编译并缓存起来,而不需要改变任何代码,所以比较简单,可以将php的运行效率提升50%以上。比较常用的免费php加速工具有:APC( http: //pecl.php.net/package-info.php?package=APC)、Turck MMCache( http://turck-mmcache.sourceforge.net)、php accelebrator(www.php-accelerator.co.uk),还有收费的Zend Performance Suite
3)将静态内容和动态内容分开处理
apache是一个功能完善但比较庞大的web server,它的资源占用基本上和同时运行的进程数呈正比,对服务器内存的消耗比较大,处理并行任务的效率也一般。在一些情况下,我们可以用比较轻量级的web server来host静态的图片、样式表和javascript文件,这样可以大大提升静态文件的处理速度,还可以减少对内存占用。我使用的web server是来自俄罗斯的nginx,其他选择方案还包括lighttpd和thttpd等。
4)基于反向代理的前端访问负载均衡
当一台前端服务器不足以应付用户访问时,通过前端机实现web访问的负载均衡是最快速可行的方案。通过apache的mod_proxy可以实现基于反向代理的负载均衡,这里推荐使用nginx做代理服务器,处理速度较apache更快一些。
5)应用缓存技术提高数据库效能,文件缓存和分布式缓存
数据库访问处理并发访问的能力是很多网站应用的关键瓶颈,在想到使用主从结构和多farm的方式构建服务器集群之前,首先应该确保充分使用了数据库查询的缓存。一些数据库类型(如mysql的innoDB)自身内置对缓存的支持,此外,还可以利用程序方法将常用的查询通过文件或内存缓存起来。比如通过 php中的ob_start和文件读写函数可以很方便的实现文件形式的缓存,而如果你拥有多台服务器,可以通过memcache技术通过分布式共享内存来对数据库查询进行缓存,不仅效率高而且扩展性好,memcache技术在livejournal和Craigslist.org等知名网站应用中都得到了检验。
6)服务器运行状态的检测,找到影响性能的瓶颈所在
系统优化没有一劳永逸的方法,需要通过检测服务器的运行状态来及时发现影响性能的瓶颈,以及可能存在的潜在问题,因为网站的性能,永远取决于木桶中的短板。可以编写一些脚本来检测web服务的运行,也有一些开源的软件也提供了很好的功能
7)良好的扩展架构是稳定和性能的基础
一些技巧和窍门可以帮你度过眼前的难关,但要想使网站具备应付大规模访问的能力,则需要从系统架构上进行彻底的规划,好在很多前人无私的把他们架构
网站的经验分享给我们,使我们可以少走甚多弯路。我最近读到的两篇有启发的文章:
- 从LiveJournal后台发展看大规模网站性能优化方法
- Myspace的六次重构
最后不得不提到程序编码和数据库结构对性能的影响,一系列糟糕的循环语句,一个不合理的查询语句、一张设计不佳的数据表或索引表,都足以会使应用程序运行的速度成倍的降低。培养全局思考的能力,养成良好的编程习惯,并对数据库运行机制有所了解,是提高编程质量的基础。
4. 分布式数据库与数据库集群的区别到底是什么哪位高手帮忙解惑下~~~~~~~~~~跪求
(1)另外一位博主的观点(http://blog.csdn.net/bluishglc/article/details/5483162)
博主有对他的表述有作一点修改补充,方便各位猿友明了他的意思。
简单说,分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。
例如:
如果一个任务由10个子任务组成,每个子任务单独执行需1小时,则在一台服务器上执行改任务需10小时。
采用分布式方案,提供10台服务器,每台服务器只负责处理一个子任务,不考虑子任务间的依赖关系,执行完这个任务只需一个小时。(这种工作模式的一个典型代表就是Hadoop的Map/Rece分布式计算模型)
而采用集群方案,同样提供10台服务器,每台服务器都能独立处理这个任务。假设有10个任务同时到达,10个服务器将同时工作,10小后,10个任务同时完成,这样,整身来看,还是平均1小时完成一个任务!(注意这里的任务和子任务的区别)
(2)知乎(https://www.hu.com/question/20004877)
这个猿友描述得很简单明了:
分布式:一个业务分拆多个子业务,部署在不同的服务器上
集群:同一个业务,部署在多个服务器上
另外一位猿友从另外一个角度去表述:
集群是个物理形态,分布式是个工作方式。
这位猿友的描述也很简洁,但是比较抽象:
按照我的理解,集群是解决高可用的,而分布式是解决高性能、高并发的
(3)网络(http://ke..com/view/4804677.htm、http://ke..com/view/3022776.htm)
集群:
集群是一组相互独立的、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用时,集群像是一个独立的服务器。集群配置是用于提高可用性和可缩放性。
分布式:
一种基于网络的计算机处理技术,与集中式相对应。由于个人计算机的性能得到极大的提高及其使用的普及,使处理能力分布到网络上的所有计算机成为可能。分布式计算是和集中式计算相对立的概念,分布式计算的数据可以分布在很大区域。
看完这些是不是有种似懂非懂的感觉?博主也是一样!所以我们接下来继续了解。
上面博主有说过自己有接触过分布式服务框架Dubbo,那么我们看看它为什么说自己是分布式服务架构?(http://bbo.io/User+Guide-zh.htm#UserGuide-zh-%E8%83%8C%E6%99%AF)
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。
此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键。
偶然之间,有发现据说“Git就是分布式版本控制系统”,为什么它是分布式的呢?
Git就是分布式版本控制系统,对应的是集中式的版本控制如SVN。简单的说,分布式的版本控制就是每个人都可以创建一个独立的代码仓库用于管理,各种版本控制的操作都可以在本地完成。每个人修改的代码都可以推送合并到另外一个代码仓库中。而像SVN这样,只有一个中央控制,所有的开发人员都必须依赖于这个代码仓库。每次版本控制的操作也必须链接到服务器才能完成。很多公司喜欢用集中式的版本控制是为了更好的控制代码。如果个人开发,就可以选择Git这种分布式的。
从一般开发者的角度来看,git有以下功能:
1、从服务器上克隆完整的Git仓库(包括代码和版本信息)到单机上。
2、在自己的机器上根据不同的开发目的,创建分支,修改代码。
3、在单机上自己创建的分支上提交代码。
4、在单机上合并分支。
5、把服务器上最新版的代码fetch下来,然后跟自己的主分支合并。
6、生成补丁(patch),把补丁发送给主开发者。
7、看主开发者的反馈,如果主开发者发现两个一般开发者之间有冲突(他们之间可以合作解决的冲突),就会要求他们先解决冲突,然后再由其中一个人提交。如果主开发者可以自己解决,或者没有冲突,就通过。
8、一般开发者之间解决冲突的方法,开发者之间可以使用pull 命令解决冲突,解决完冲突之后再向主开发者提交补丁。
看了分布式服务框架Dubbo和分布式版本控制系统Git的这些描述后,细想一下,似乎和上面的“分布式:一个业务分拆多个子业务,部署在不同的服务器上,集群:同一个业务,部署在多个服务器上”的观点些相似。
Dubbo将核心业务抽取出来,作为独立的服务模块,各个模块之间只需要依赖接口,接口实现分离,那么开发人员可以各自完成自己负责的服务模块,最后完成一个完整的系统。他们的目标是完成一个系统,而各个子服务模块相当于子业务。Git也类似。
事实上,分布式很多时候都开不了集群的,在Dubbo、Hadoop、Elasticsearch都有体现。
现在分布式概念可能我们相对比较清晰了,集群概念可能还比较模糊。另外,集群是如何跟分布式配合的呢,接下来我们继续了解集群。
集群主要分成三大类 (高可用集群, 负载均衡集群,科学计算集群)
高可用集群( High Availability Cluster)
负载均衡集群(Load Balance Cluster)
科学计算集群(High Performance Computing Cluster)
1、高可用集群(High Availability Cluster)
常见的就是2个节点做成的HA集群,有很多通俗的不科学的名称,比如”双机热备”, “双机互备”, “双机”。
高可用集群解决的是保障用户的应用程序持续对外提供服务的能力。 (请注意高可用集群既不是用来保护业务数据的,保护的是用户的业务程序对外不间断提供服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度)。
2、负载均衡集群(Load Balance Cluster)
负载均衡系统:集群中所有的节点都处于活动状态,它们分摊系统的工作负载。一般Web服务器集群、数据库集群和应用服务器集群都属于这种类型。
负载均衡集群一般用于相应网络请求的网页服务器,数据库服务器。这种集群可以在接到请求时,检查接受请求较少,不繁忙的服务器,并把请求转到这些服务器上。从检查其他服务器状态这一点上看,负载均衡和容错集群很接近,不同之处是数量上更多。
3、科学计算集群(High Performance Computing Cluster)
高性能计算(High Perfermance Computing)集群,简称HPC集群。这类集群致力于提供单个计算机所不能提供的强大的计算能力。
高性能计算分类:
3.1、高吞吐计算(High-throughput Computing)
有一类高性能计算,可以把它分成若干可以并行的子任务,而且各个子任务彼此间没有什么关联。象在家搜寻外星人( SETI@HOME – Search for Extraterrestrial Intelligence at Home )就是这一类型应用。
这一项目是利用Internet上的闲置的计算资源来搜寻外星人。SETI项目的服务器将一组数据和数据模式发给Internet上参加SETI的计算节点,计算节点在给定的数据上用给定的模式进行搜索,然后将搜索的结果发给服务器。服务器负责将从各个计算节点返回的数据汇集成完整的 数据。因为这种类型应用的一个共同特征是在海量数据上搜索某些模式,所以把这类计算称为高吞吐计算。
所谓的Internet计算都属于这一类。按照 Flynn的分类,高吞吐计算属于SIMD(Single Instruction/Multiple Data)的范畴。
3.2、分布计算(Distributed Computing)
另一类计算刚好和高吞吐计算相反,它们虽然可以给分成若干并行的子任务,但是子任务间联系很紧密,需要大量的数据交换。按照Flynn的分类,分布式的高性能计算属于MIMD(Multiple Instruction/Multiple Data)的范畴。
下面说说这几种集群的应用场景:
高可用集群这里不多作说明。
想Dubbo是比较偏向于负载均衡集群,用过的猿友应该知道(不知道的可以自行了解一下),Dubbo同一个服务是可以有多个提供者的,当一个消费者过来,它要消费那个提供者,这里是有负载均衡机制在里面的。
搜索引擎Elasticsearch比较偏向于科学计算集群的分布计算。
而到这里,可能不少猿友都知道,集群的一些术语:集群容错、负载均衡。
我们以Dubbo为例:
集群容错(http://bbo.io/User+Guide-zh.htm#UserGuide-zh-%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%94%99)
Dubbo提供了这些容错策略:
集群容错模式:
可以自行扩展集群容错策略,参见:集群扩展
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。(缺省)
通常用于读操作,但重试会带来更长延迟。
可通过retries="2"来设置重试次数(不含第一次)。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。
通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。
通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。
通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过forks="2"来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
通常用于通知所有提供者更新缓存或日志等本地资源信息。
负载均衡(http://bbo.io/User+Guide-zh.htm#UserGuide-zh-%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1)
Dubbo提供了这些负载均衡策略:
Random LoadBalance
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
算法参见:http://en.wikipedia.org/wiki/Consistent_hashing。
缺省只对第一个参数Hash,如果要修改,请配置<bbo:parameter key="hash.arguments" value="0,1" />
缺省用160份虚拟节点,如果要修改,请配置<bbo:parameter key="hash.nodes" value="320" />
还有比较好奇它们是怎么通信的?
像早期版本的Elasticsearch的话,自动发现节点机制,ES是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。
而Dubbo是有个注册中心,它支持多个注册中心,但是推荐使用ZooKeeper。关于ZooKeeper可以自行了解,很多集群相关的框架都有使用到它。当然像Elasticsearch是自己有相应的机制实现的。
5. “分布式”与“集群”的区别是什么
简单说,分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。
例如:
如果一个任务由10个子任务组成,每个子任务单独执行需1小时,则在一台服务器上执行改任务需10小时。
采用分布式方案,提供10台服务器,每台服务器只负责处理一个子任务,不考虑子任务间的依赖关系,执行完这个任务只需一个小时。(这种工作模式的一个典型代表就是Hadoop的Map/Rece分布式计算模型)
而采用集群方案,同样提供10台服务器,每台服务器都能独立处理这个任务。假设有10个任务同时到达,10个服务器将同时工作,10小后,10个任务同时完成,这样,整身来看,还是1小时内完成一个任务!
以下是摘抄自网络文章:
一、集群概念
1. 两大关键特性
集群是一组协同工作的服务实体,用以提供比单一服务实体更具扩展性与可用性的服务平台。在客户端看来,一个集群就象是一个服务实体,但事实上集群由一组服务实体组成。与单一服务实体相比较,集群提供了以下两个关键特性:
· 可扩展性--集群的性能不限于单一的服务实体,新的服务实体可以动态地加入到集群,从而增强集群的性能。
· 高可用性--集群通过服务实体冗余使客户端免于轻易遇到out of service的警告。在集群中,同样的服务可以由多个服务实体提供。如果一个服务实体失败了,另一个服务实体会接管失败的服务实体。集群提供的从一个出 错的服务实体恢复到另一个服务实体的功能增强了应用的可用性。
2. 两大能力
为了具有可扩展性和高可用性特点,集群的必须具备以下两大能力:
· 负载均衡--负载均衡能把任务比较均衡地分布到集群环境下的计算和网络资源。
· 错误恢复--由于某种原因,执行某个任务的资源出现故障,另一服务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。
负载均衡和错误恢复都要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图(信息上下文)必须是一样的。
3. 两大技术
实现集群务必要有以下两大技术:
· 集群地址--集群由多个服务实体组成,集群客户端通过访问集群的集群地址获取集群内部各服务实体的功能。具有单一集群地址(也叫单一影像)是集群的一个基本特征。维护集群地址的设置被称为负载均衡器。负载均衡器内部负责管理各个服务实体的加入和退出,外部负责集群地址向内部服务实体地址的转换。有的负载均衡器实现真正的负载均衡算法,有的只支持任务的转换。只实现任务转换的负载均衡器适用于支持ACTIVE-STANDBY的集群环境,在那里,集群中只有一个服务实体工作,当正在工作的服务实体发生故障时,负载均衡器把后来的任务转向另外一个服务实体。
· 内部通信--为了能协同工作、实现负载均衡和错误恢复,集群各实体间必须时常通信,比如负载均衡器对服务实体心跳测试信息、服务实体间任务执行上下文信息的通信。
具有同一个集群地址使得客户端能访问集群提供的计算服务,一个集群地址下隐藏了各个服务实体的内部地址,使得客户要求的计算服务能在各个服务实体之间分布。内部通信是集群能正常运转的基础,它使得集群具有均衡负载和错误恢复的能力。
二、集群分类
Linux集群主要分成三大类(高可用集群, 负载均衡集群,科学计算集群)
高可用集群(High Availability Cluster)
负载均衡集群(Load Balance Cluster)
科学计算集群(High Performance Computing Cluster)
具体包括:
Linux High Availability 高可用集群
(普通两节点双机热备,多节点HA集群,RAC, shared, share-nothing集群等)
Linux Load Balance 负载均衡集群
(LVS等....)
Linux High Performance Computing 高性能科学计算集群
(Beowulf 类集群....)
三、详细介绍
1. 高可用集群(High Availability Cluster)
常见的就是2个节点做成的HA集群,有很多通俗的不科学的名称,比如"双机热备","双机互备","双机"。
高可用集群解决的是保障用户的应用程序持续对外提供服务的能力。 (请注意高可用集群既不是用来保护业务数据的,保护的是用户的业务程序对外不间断提供服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度)。
2. 负载均衡集群(Load Balance Cluster)
负载均衡系统:集群中所有的节点都处于活动状态,它们分摊系统的工作负载。一般Web服务器集群、数据库集群和应用服务器集群都属于这种类型。
负载均衡集群一般用于相应网络请求的网页服务器,数据库服务器。这种集群可以在接到请求时,检查接受请求较少,不繁忙的服务器,并把请求转到这些服务器上。从检查其他服务器状态这一点上看,负载均衡和容错集群很接近,不同之处是数量上更多。
3. 科学计算集群(High Performance Computing Cluster)
高性能计算(High Perfermance Computing)集群,简称HPC集群。这类集群致力于提供单个计算机所不能提供的强大的计算能力。
3.1 高性能计算分类
3.1.1 高吞吐计算(High-throughput Computing)
有一类高性能计算,可以把它分成若干可以并行的子任务,而且各个子任务彼此间没有什么关联。象在家搜寻外星人( SETI@HOME -- Search for Extraterrestrial Intelligence at Home )就是这一类型应用。这一项目是利用Internet上的闲置的计算资源来搜寻外星人。SETI项目的服务器将一组数据和数据模式发给Internet上参加SETI的计算节点,计算节点在给定的数据上用给定的模式进行搜索,然后将搜索的结果发给服务器。服务器负责将从各个计算节点返回的数据汇集成完整的 数据。因为这种类型应用的一个共同特征是在海量数据上搜索某些模式,所以把这类计算称为高吞吐计算。所谓的Internet计算都属于这一类。按照 Flynn的分类,高吞吐计算属于SIMD(Single Instruction/Multiple Data)的范畴。
3.1.2 分布计算(Distributed Computing)
另一类计算刚好和高吞吐计算相反,它们虽然可以给分成若干并行的子任务,但是子任务间联系很紧密,需要大量的数据交换。按照Flynn的分类,分布式的高性能计算属于MIMD(Multiple Instruction/Multiple Data)的范畴。
四、分布式(集群)与集群的联系与区别
分布式是指将不同的业务分布在不同的地方;而集群指的是将几台服务器集中在一起,实现同一业务。
分布式中的每一个节点,都可以做集群。 而集群并不一定就是分布式的。
举例:就比如新浪网,访问的人多了,他可以做一个群集,前面放一个响应服务器,后面几台服务器完成同一业务,如果有业务访问的时候,响应服务器看哪台服务器的负载不是很重,就将给哪一台去完成。
而分布式,从窄意上理解,也跟集群差不多, 但是它的组织比较松散,不像集群,有一个组织性,一台服务器垮了,其它的服务器可以顶上来。
分布式的每一个节点,都完成不同的业务,一个节点垮了,那这个业务就不可访问了。
6. 应用服务器,数据库服务器,前端数据对接服务器这三种服务器配置上是不是都是相同的只是说法不一样
配置不一样的,型号一样不一样我觉得没关系,主要配置要合适,本质其实都是普通服务器,现在也有云服务器,利用虚拟技术搞的,我也不是特别懂
应用服务器,一般部署应用代码,配置不用很高,也要看用的人和并发量,一般8-16G内存,4-8核CPU就够了,主要看代码里面多线程等代码复杂程度,一般多台机器集群
数据库服务器,这个部署数据库,一般配置会高,因为所有应用服务器一般都会链接数据库,CPU要多,内存要大。一般是个大集群,还要主库备库,各种优化
前端数据对接服务器不知道指的是什么,我个人理解是VIP,负载均衡,对接客户前端的,主要做分流,存一点小数据等,对接应用服务器,这个配置也不用很高,也是个集群
7. 前端框架
1.前端框架一般指用于简化网页设计的框架,比如,jquery,extjs,bootstrap等等,这些框架封装了一些功能,比如html文档操作,漂亮的各种控件(按钮,表单等等)。
2.使用前段框架可以降低界面开发周期和提高界面的美观性。
3.有些框架比较轻量,比如jquery,有些框架比较重量,比如extjs。一般来说重量的框架会封装更多的功能,比如extjs,封装的grid控件有很强的数据展示和操作功能。
1.对用户的价值:
大部分产品对用户的核心价值是功能和内容提供的,而不是由表现层和交互。譬如支付、电商、新闻、交友。
后端解决有还是无的问题,开天辟地。
前端解决有了以后好用的问题,锦上添花,在竞争激烈的领域确实至关重要。
2.技术广度和难度:
广度上后端工作在服务器领域,能控制的硬件基本没有极限,CPU、存储、网络、集群等等,因此技术领域极广。一个优秀的后端需要掌握或了解大量技术如:并发、业务架构、数据库、几打流行框架、性能调优、分布式计算、集群架构、容灾、安全、运维等等,一层知销和挖透了还有下一层。几十年计算机发展历史中大量的技术沉淀在服务器端。
Web前端一直工作在一个浏览器盒子里,先天不足,能承载的可能性太小,技术广度不足。
深度上,现代计算机领域的难题如大规模负载,海量数据处理,实时计算也是后端的,前端集中在表示层,这一层虽然也很复杂,但能称之为难题的技术几乎没有,也很容易复制。
前端要说深度也不是没有,但这一步需要跨到图形领域(如网页游戏),不是常见场景。
说到底前端代码能控制的硬件确实不如后端,因此在技术上,前端更容易。现在为什么说前端会比后端更值钱呢?那是因为前端对硬件的控制能力提升了(html5odejsmobile),而后端分化得比较厉害,有一批后端专门只写业务逻辑,框架是别人写的,系统架构是别人搭的,服务器跑在云里,连机器物理地址都不知道。世人眼里可能觉得这种写MVC代码的人才斗裤是后端,这种被限制在一个“虚拟盒子”里的后端确实不怎么难上手。
一般而言网上说的互联网行业的技术含量排名大概是这样:
产品经理<设计师<前端<后端<其他更高级职位,比如算法工程师等等。
在广大中小公司,很多产品经理都是不会代码,不会设计。很多技校学艺术设计的毕业生,当上了美工。这些都是真,所以能力低,干的人多,自然搭盯就低。然而,你问Google设计师挣多少了嘛?
门槛低不等于技术含量低。