金沙棋牌app手机下载

当前位置:金沙棋牌 > 金沙棋牌app手机下载 > 使用FriendFeed来提升MySQL性能的方法,课前单词

使用FriendFeed来提升MySQL性能的方法,课前单词

来源:http://www.logblo.com 作者:金沙棋牌 时间:2019-09-24 04:09

view   视图

随着数据的增长,我们也曾迭代地解决了随着如此迅猛的增长而带来的扩展性问题。我们的尝试很有代表性,例如使用只读mysql从节点和memcache来增加读取吞吐量,对数据库进行分片来提高写入吞吐量。然而,随着业务的增长,添加新功能比扩展既有功能以迎合更多的流量变得更加困难。

使用FriendFeed来提升MySQL性能的方法,friendfeedmysql

 背景

我们使用MySQL存储了FriendFeed的所有数据。数据库随着用户基数的增长而增长了很多。现在已经存储了超过2.5亿条记录与一堆涵盖了从评论和“喜欢”到好友列表的其他数据。

随着数据的增长,我们也曾迭代地解决了随着如此迅猛的增长而带来的扩展性问题。我们的尝试很有代表性,例如使用只读mysql从节点和memcache来增加读取吞吐量,对数据库进行分片来提高写入吞吐量。然而,随着业务的增长,添加新功能比扩展既有功能以迎合更多的流量变得更加困难。

特别的,对 schema 做改动或为超过 1000-2000 万行记录的数据库添加索引会将数据库锁住几个小时。删除旧索引也要占用这么多时间,但不删除它们会影响性能;因为数据库要持续地在每个INSERT上读写这些没用的区块,并将重要的区块挤出了内存。为避免这些问题需要采取一些复杂的措施(例如在从节点上设置新的索引,然后将从节点与主节点对调),但这些措施会引发错误并且实施起来比较困难,它们阻碍了需要改动 schema/索引才能实现的新功能。由于数据库的严重分散,MySQL 的关系特性(如join)对我们没用,所以我们决定脱离 RDBMS。

虽然已有许多用于解决灵活 schema 数据存储和运行时构建索引的问题(例如 CouchDB)的项目。但在大站点中却没有足够广泛地用到来说服人们使用。在我们看到和运行的测试中,这些项目要么不稳定,要么缺乏足够的测试(参见这个有点过时的关于 CouchDB 的文章)。MySQL 不错,它不会损坏数据;复制也没问题,我们已经了解了它的局限。我们喜欢将 MySQL 用于存储,仅仅是非关系型的存储。

几经思量,我们决定在 MySQL 上采用一种无模式的存储系统,而不是使用一个完全没接触过的存储系统。本文试图描述这个系统的高级细节。我们很好奇其他大型网站是如何处理这些问题的,另外也希望我们完成的某些设计会对其他开发者有所帮助。

综述

我们在数据库中存储的是无模式的属性集(例如JSON对象或python字典)。存储的记录只需一个名为id的16字节的UUID属性。对数据库而言实体的其他部分是不可见的。我们可以简单地存入新属性来改变schema(可以简单理解为数据表中只有两个字段:id,data;其中data存储的是实体的属性集)。

我们通过保存在不同表中的索引来检索数据。如果想检索每个实体中的三个属性,我们就需要三个数据表-每个表用于检索某一特定属性。如果不想再用某一索引了,我们要在代码中停止该索引对应表的写操作,并可选地删除那个表。如果想添加个新索引,只需要为该索引新建个MySQL表,并启动一个进程异步地为该表添加索引数据(不影响运行中的服务)。

最终,虽然我们的数据表增多了,但添加和删除索引却变得简单了。我们大力改善了添加索引数据的进程(我们称之为“清洁工")使其在快速添加索引的同时不会影响站点。我们可以在一天内完成新属性的保存和索引,并且我们不需要对调主从MySQL数据库,也不需要任何其他可怕的操作。

细节

MySQL 使用表保存我们的实体,一个表就像这样 :  

CREATE TABLE entities (
  added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  id BINARY(16) NOT NULL,
  updated TIMESTAMP NOT NULL,
  body MEDIUMBLOB,
  UNIQUE KEY (id),
  KEY (updated)
) ENGINE=InnoDB;

之所以使用 added_id 个字段是因为 InnoDB 按物理主键顺序存储数据,自增长主键确保新实例在磁盘上按顺序写到老实体之后,这样有助于分区读写(相对老的实体,新实体往往读操作更频繁,因为 FriendFeed 的 pages 是按时间逆序排列)。实体本身经 python 字典序列化后使用 zlib 压缩存储。

索引单独存在一张表里,如果要创建索引,我们创建一张新表存储我们想要索引的数据分片的所有属性。例如,一个 FriendFeed 实体通过看上去是这样的:  

{
  "id": "71f0c4d2291844cca2df6f486e96e37c",
  "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
  "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
  "title": "We just launched a new backend system for FriendFeed!",
  "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
  "published": 1235697046,
  "updated": 1235697046,
}

我们索引实体的属性 user_id,这样我们可以渲染一个页面,包含一个已提交用户的所有属性。我们的索引表看起来是这样的:

CREATE TABLE index_user_id (
  user_id BINARY(16) NOT NULL,
  entity_id BINARY(16) NOT NULL UNIQUE,
  PRIMARY KEY (user_id, entity_id)
) ENGINE=InnoDB;

我们的数据存储会自动为你维护索引,所以如果你要在我们存储上述结构实体的数据存储里开启一个实例,你可以写一段代码(用 python):  

user_id_index = friendfeed.datastore.Index(
  table="index_user_id", properties=["user_id"], shard_on="user_id")
datastore = friendfeed.datastore.DataStore(
  mysql_shards=["127.0.0.1:3306", "127.0.0.1:3307"],
  indexes=[user_id_index])

new_entity = {
  "id": binascii.a2b_hex("71f0c4d2291844cca2df6f486e96e37c"),
  "user_id": binascii.a2b_hex("f48b0440ca0c4f66991c4d5f6a078eaf"),
  "feed_id": binascii.a2b_hex("f48b0440ca0c4f66991c4d5f6a078eaf"),
  "title": u"We just launched a new backend system for FriendFeed!",
  "link": u"http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
  "published": 1235697046,
  "updated": 1235697046,
}
datastore.put(new_entity)
entity = datastore.get(binascii.a2b_hex("71f0c4d2291844cca2df6f486e96e37c"))
entity = user_id_index.get_all(datastore, user_id=binascii.a2b_hex("f48b0440ca0c4f66991c4d5f6a078eaf"))

上面的 Index 类在所有实体中查找 user_id,自动维护 index_user_id 表的索引。我们的数据库是切分的,参数 shard_on 是用来确定索引是存储在哪个分片上(这种情况下使用 entity["user_id"] % num_shards)。

你可以使用索引实例(见上面的 user_id_index.get_all)查询一个索引,使用 python 写的数据存储代码将表 index_user_id 和表 entities 合并。首先在所有数据库分片中查询表 index_user_id 获取实体 ID 列,然后在 entities 提出数据。

新建一个索引,比如,在属性 link 上,我们可以创建一个新表:  

CREATE TABLE index_link (
  link VARCHAR(735) NOT NULL,
  entity_id BINARY(16) NOT NULL UNIQUE,
  PRIMARY KEY (link, entity_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我们可以修改数据存储的初始化代码以包含我们的新索引:  

user_id_index = friendfeed.datastore.Index(
  table="index_user_id", properties=["user_id"], shard_on="user_id")
link_index = friendfeed.datastore.Index(
  table="index_link", properties=["link"], shard_on="link")
datastore = friendfeed.datastore.DataStore(
  mysql_shards=["127.0.0.1:3306", "127.0.0.1:3307"],
  indexes=[user_id_index, link_index])

我可以异步构建索引(特别是实时传输服务):  

./rundatastorecleaner.py --index=index_link

一致性与原子性

由于采用分区的数据库,实体的索引可能存储在与实体不同的分区中,这引起了一致性问题。如果进程在写入所有索引表前崩溃了会怎样?

许多有野心的 FriendFeed 工程师倾向于构建一个事务性协议,但我们希望尽可能地保持系统的简洁。我们决定放宽限制:

  •     保存在主实体表中的属性集是规范完整的
  •     索引不会对真实实体值产生影响

因此,往数据库中写入实体时我们采用如下步骤:

  •     使用 InnoDB 的 ACID 属性将实体写入 entities 表。
  •     将索引写入所有分区中的索引表。

我们要记住从索引表中取出的数据可能是不准确的(例如如果写操作没有完成步骤2可能会影响旧属性值)。为确保采用上面的限制能返回正确的实体,我们用索引表来决定要读取哪些实体,但不要相信索引的完整性,要使用查询条件对这些实体进行再过滤:

1.根据查询条件从索引表中取得 entity_id

2.根据 entity_id 从 entities 表中读取实体

3.根据实体的真实属性(用 Python)过滤掉不符合查询条件的实体

为保证索引的持久性和一致性,上文提到的“清洁工”进程要持续运行,写入丢失的索引,清理失效的旧索引。它优先清理最近更新的实体,所以实际上维护索引的一致性非常快(几秒钟).
 
性能

我们对新系统的主索引进行了优化,对结果也很满意。以下是上个月 FriendFeed 页面的加载延时统计图(我们在前几天启动了新的后端,你可以根据延时的显著回落找到那一天)。

图片 1

特别地,系统的延时现在也很稳定(哪怕是在午高峰期间)。如下是过去24小时FriendFeed页面加载延时图。

图片 2

与上周的某天相比较:

图片 3

系统到目前为止使用起来很方便。我们在部署之后也改动了几次索引,并且我们也开始将这种模式应用于 MySQL 中那些较大的表,这样我们在以后可以轻松地改动它们的结构。

背景 我们使用MySQL存储了FriendFeed的所有数据。数据库随着用户基数的增长而增长了很多。...

hibernate基础dao类,hibernate基础dao

功能:数据库的保存、更新、删除;sql、hql查询;分页查询;调用存储过程

基础dao类,BaseDaoImpl.class

图片 4 1 import java.io.Serializable; 2 import java.sql.CallableStatement; 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.text.MessageFormat; 7 import java.util.ArrayList; 8 import java.util.List; 9 import java.util.Map; 10 11 import org.hibernate.Criteria; 12 import org.hibernate.Query; 13 import org.hibernate.Session; 14 import org.hibernate.criterion.DetachedCriteria; 15 import org.hibernate.criterion.Projections; 16 import org.hibernate.jdbc.Work; 17 import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 18 19 public class BaseDaoImpl<T extends Serializable> extends HibernateDaoSupport implements BaseDao<T>{ 20 public BaseDaoImpl(){ 21 super(); 22 } 23 24 /** 25 * 返回数据库session对象 26 * @return 27 */ 28 protected Session getCurrentSession(){ 29 return getHibernateTemplate().getSessionFactory().getCurrentSession(); 30 } 31 32 /** 33 * 保存实体对象 34 * @param entity 实体对象 35 */ 36 @Override 37 public void save(T entity){ 38 Session session = getCurrentSession(); 39 session.save(entity); 40 session.flush(); 41 session.evict(entity); 42 } 43 44 /** 45 * 更新实体对象 46 * @param 实体对象 47 */ 48 @Override 49 public void update(T entity){ 50 Session session = getCurrentSession(); 51 session.update(entity); 52 session.flush(); 53 session.evict(entity); 54 } 55 56 /** 57 * 保存或更新实体对象 58 * @param entity 实体对象 59 */ 60 @Override 61 public void saveOrUpdate(T entity) { 62 Session session = getCurrentSession(); 63 session.saveOrUpdate(entity); 64 session.flush(); 65 session.evict(entity); 66 } 67 68 /** 69 * 删除实体对象 70 * @param entity 实体对象 71 */ 72 @Override 73 public void delete(T entity){ 74 Session session = getCurrentSession(); 75 session.delete(entity); 76 session.flush(); 77 session.evict(entity); 78 } 79 80 /** 81 * 查询hql语句,返回唯一结果 82 * @param hql 83 */ 84 @Override 85 public Object findUniqueResult(String hql){ 86 Query query = getCurrentSession().createQuery(hql); 87 return query.uniqueResult(); 88 } 89 90 /** 91 * 执行sql语句,更新数据库 92 * @param sql 93 */ 94 @Override 95 public void updateBySql(final String sql){ 96 getSession().doWork(new Work() { 97 @Override 98 public void execute(Connection connection) throws SQLException { 99 connection.prepareStatement(sql).executeUpdate(); 100 } 101 }); 102 } 103 104 /** 105 * 通过Criteria对象查询,返回实体对象结果集 106 * @param detachedCriteria 离线的Criteria对象 107 * @return 实体对象结果集 108 */ 109 @Override 110 public List findByCriteria(DetachedCriteria detachedCriteria){ 111 Criteria criteria = detachedCriteria.getExecutableCriteria(getCurrentSession()); 112 List records = criteria.list(); 113 return records; 114 } 115 116 /** 117 * 通过sql语句查询,返回map对象结果集 118 * @param sql 119 * @return map对象结果集 120 */ 121 @Override 122 public List<Map<String, Object>> findBySql(final String sql){ 123 final List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); 124 getSession().doWork(new Work() { 125 @Override 126 public void execute(Connection connection) throws SQLException { 127 ResultSet rs = connection.prepareStatement(sql).executeQuery(); 128 result.addAll(RsHelper.rSToList(rs)); 129 } 130 }); 131 return result; 132 } 133 134 /** 135 * 查询sql语句,返回唯一结果 136 * @param sql 137 */ 138 @Override 139 public Object findUniqueResultBySql(String sql) { 140 return getCurrentSession().createSQLQuery(sql.toString()).uniqueResult(); 141 } 142 143 /** 144 * 通过Criteria对象查询,返回结果集的记录数 145 * @param detachedCriteria 离线的Criteria对象 146 * @return 结果集的记录数 147 */ 148 @Override 149 public long getCount(DetachedCriteria detachedCriteria) { 150 Criteria criteria = detachedCriteria.getExecutableCriteria(getCurrentSession()); 151 Object object = criteria.setProjection(Projections.rowCount()).uniqueResult(); 152 criteria.setProjection(null); 153 Long totalRow = Long.valueOf(String.valueOf(object)); 154 return totalRow; 155 } 156 157 /** 158 * 通过Criteria对象进行分页查询,返回实体对象结果集 159 * @param pageNum 第几页 160 * @param pageSize 每页大小 161 * @param detachedCriteria 离线的Criteria对象 162 * @return 实体对象结果集 163 */ 164 @Override 165 public List<T> findPage(int pageNum, int pageSize, 166 DetachedCriteria detachedCriteria){ 167 Criteria criteria = detachedCriteria.getExecutableCriteria(getCurrentSession()); 168 List<T> records = criteria.setFirstResult((pageNum-1) * pageSize).setMaxResults(pageSize).list(); 169 return records; 170 } 171 172 /** 173 * 通过sql语句,进行分页查询,返回分页对象 174 * @param pageNum 第几页 175 * @param pageSize 每页大小 176 * @param sql 177 * @return 分页对象 178 */ 179 @Override 180 public Pagination findPage(final int pageNum, final int pageSize,final String sql){ 181 final Pagination page = new Pagination(); 182 getSession().doWork(new Work() { 183 @Override 184 public void execute(Connection connection) throws SQLException { 185 String countSql = MessageFormat.format("select count(*) from ({0}) page", sql); 186 ResultSet rs = connection.prepareStatement(countSql).executeQuery(); 187 page.setTotal(Long.valueOf(RsHelper.getUniqueResult(rs).toString())); 188 189 long firstResult = (pageNum - 1)*pageSize; 190 String selectSql = MessageFormat.format("select * from ({0}) page limit {1},{2}", sql, firstResult, firstResult+pageSize); 191 page.setRows(RsHelper.rSToList(connection.prepareStatement(selectSql).executeQuery())); 192 } 193 }); 194 195 return page; 196 } 197 198 /** 199 * 调用存储过程,返回单结果集 200 * @param proceName 存储过程名称 201 * @param params 输入参数集合 202 * @return map对象结果集 203 */ 204 public List<Map<String, Object>> callProcedure(String proceName, final List<Object> params){ 205 final List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); 206 final StringBuffer sql = new StringBuffer(); 207 sql.append("{call " + proceName + "("); 208 for(int i=0; params!=null && i<params.size(); i++){ 209 sql.append("?"); 210 if(i+1!=params.size()) 211 sql.append(","); 212 } 213 sql.append(")}"); 214 getSession().doWork(new Work() { 215 @Override 216 public void execute(Connection connection) throws SQLException { 217 CallableStatement statement = connection.prepareCall( 218 sql.toString()); 219 for(int i=0; i<params.size(); i++){ 220 statement.setObject(i+1, params.get(i));//设置参数 221 } 222 223 result.addAll(RsHelper.rSToList(statement.executeQuery())); 224 } 225 }); 226 227 return result; 228 } 229 230 } View Code

 

基础dao类接口,BaseDao.class

图片 5 1 import java.io.Serializable; 2 import java.util.List; 3 import java.util.Map; 4 5 import org.hibernate.criterion.DetachedCriteria; 6 7 /** 8 * 统一数据访问接口 9 */ 10 public interface BaseDao<T extends Serializable> { 11 12 /** 13 * 保存实体对象 14 * @param entity 实体对象 15 */ 16 public void save(T entity); 17 18 /** 19 * 更新实体对象 20 * @param 实体对象 21 */ 22 public void update(T entity); 23 24 /** 25 * 保存或更新实体对象 26 * @param entity 实体对象 27 */ 28 public void saveOrUpdate(T entity); 29 30 /** 31 * 删除实体对象 32 * @param entity 实体对象 33 */ 34 public void delete(T entity); 35 36 /** 37 * 查询hql语句,返回唯一结果 38 * @param hql 39 */ 40 public Object findUniqueResult(String hql); 41 42 /** 43 * 执行sql语句,更新数据库 44 * @param sql 45 */ 46 public void updateBySql(String sql); 47 48 /** 49 * 通过Criteria对象查询,返回实体对象结果集 50 * @param detachedCriteria 离线的Criteria对象 51 * @return 实体对象结果集 52 */ 53 public List findByCriteria(DetachedCriteria detachedCriteria); 54 55 /** 56 * 通过sql语句查询,返回map对象结果集 57 * @param sql 58 * @return map对象结果集 59 */ 60 public List<Map<String, Object>> findBySql(String sql); 61 62 /** 63 * 查询sql语句,返回唯一结果 64 * @param sql 65 */ 66 public Object findUniqueResultBySql(String sql); 67 68 /** 69 * 通过Criteria对象查询,返回结果集的记录数 70 * @param detachedCriteria 离线的Criteria对象 71 * @return 结果集的记录数 72 */ 73 public long getCount(DetachedCriteria detachedCriteria); 74 75 /** 76 * 通过Criteria对象进行分页查询,返回实体对象结果集 77 * @param pageNum 第几页 78 * @param pageSize 每页大小 79 * @param detachedCriteria 离线的Criteria对象 80 * @return 实体对象结果集 81 */ 82 public List<T> findPage(int pageNum, int pageSize, DetachedCriteria detachedCriteria); 83 84 /** 85 * 通过sql语句,进行分页查询,返回分页对象 86 * @param pageNum 第几页 87 * @param pageSize 每页大小 88 * @param sql 89 * @return 分页对象 90 */ 91 public Pagination findPage(int pageNum, int pageSize, String sql); // 查找分页对象列表 92 93 /** 94 * 调用存储过程,返回单结果集 95 * @param proceName 存储过程名称 96 * @param params 输入参数集合 97 * @return map对象结果集 98 */ 99 public List<Map<String, Object>> callProcedure(String proceName, final List<Object> params); 100 } View Code

 

数据库结果集帮助器,RsHelper.class  

图片 6 1 import java.sql.ResultSet; 2 import java.sql.ResultSetMetaData; 3 import java.sql.SQLException; 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 10 /** 11 * 数据库结果集帮助器 12 */ 13 public class RsHelper { 14 /** 15 * 返回结果集中的唯一结果,没有则返回null 16 * @param rs 结果集 17 * @return 18 * @throws SQLException 19 */ 20 public static Object getUniqueResult(ResultSet rs) throws SQLException{ 21 if(rs.next()) { 22 return rs.getObject(1); 23 } 24 return null; 25 } 26 27 /** 28 * 将实体结果集对象转换为map对象结果集 29 * @param rs 实体结果集对象 30 * @return map对象结果集 31 * @throws SQLException 32 */ 33 public static List<Map<String,Object>> rSToList(ResultSet rs) throws SQLException { 34 if (rs == null) 35 return Collections.EMPTY_LIST; 36 ResultSetMetaData md = rs.getMetaData(); //得到结果集(rs)的结构信息,比如字段数、字段名等 37 int columnCount = md.getColumnCount(); //返回此 ResultSet 对象中的列数 38 List<Map<String,Object>> list = new ArrayList<Map<String,Object>>(); 39 Map<String,Object> rowData = new HashMap<String,Object>(); 40 while (rs.next()) { 41 rowData = new HashMap<String,Object>(columnCount); 42 for (int i = 1; i <= columnCount; i++) { 43 rowData.put(md.getColumnName(i), rs.getObject(i)); 44 } 45 list.add(rowData); 46 } 47 return list; 48 } 49 } View Code

 

分页对象类,Pagination.class

图片 7 1 import java.util.ArrayList; 2 import java.util.List; 3 4 /** 5 * 分页对象,一般用于响应页面请求 6 */ 7 public class Pagination { 8 /** 9 * 总记录数 10 */ 11 private Long total = 0l; 12 13 /** 14 * 记录集合 15 */ 16 private List rows = new ArrayList(); 17 18 public Long getTotal() { 19 return total; 20 } 21 public void setTotal(Long total) { 22 this.total = total; 23 } 24 25 public List getRows() { 26 return rows; 27 } 28 public void setRows(List rows) { 29 this.rows = rows; 30 } 31 } View Code

 

功能:数据库的保存、更新、删除;sql、hql查询;分页查询;调用存储过程 基础dao类,BaseDaoImpl.class 1 im...

temporary 临时的

{
  "id": "71f0c4d2291844cca2df6f486e96e37c",
  "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
  "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf",
  "title": "We just launched a new backend system for FriendFeed!",
  "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
  "published": 1235697046,
  "updated": 1235697046,
}

guide  操纵、指导

1.根据查询条件从索引表中取得 entity_id

 

图片 8

 

图片 9

execute   执行

 背景

drop  删除

我们在数据库中存储的是无模式的属性集(例如JSON对象或python字典)。存储的记录只需一个名为id的16字节的UUID属性。对数据库而言实体的其他部分是不可见的。我们可以简单地存入新属性来改变schema(可以简单理解为数据表中只有两个字段:id,data;其中data存储的是实体的属性集)。

第六章

与上周的某天相比较:

statement   声明

我们使用MySQL存储了FriendFeed的所有数据。数据库随着用户基数的增长而增长了很多。现在已经存储了超过2.5亿条记录与一堆涵盖了从评论和“喜欢”到好友列表的其他数据。

variables  可变的、变量

上面的 Index 类在所有实体中查找 user_id,自动维护 index_user_id 表的索引。我们的数据库是切分的,参数 shard_on 是用来确定索引是存储在哪个分片上(这种情况下使用 entity["user_id"] % num_shards)。

district  区域

我可以异步构建索引(特别是实时传输服务):  

 

我们通过保存在不同表中的索引来检索数据。如果想检索每个实体中的三个属性,我们就需要三个数据表-每个表用于检索某一特定属性。如果不想再用某一索引了,我们要在代码中停止该索引对应表的写操作,并可选地删除那个表。如果想添加个新索引,只需要为该索引新建个MySQL表,并启动一个进程异步地为该表添加索引数据(不影响运行中的服务)。

rollback   回滚

  •     保存在主实体表中的属性集是规范完整的
  •     索引不会对真实实体值产生影响

foreign  对外的

./rundatastorecleaner.py --index=index_link

grant  授予、授权

user_id_index = friendfeed.datastore.Index(
  table="index_user_id", properties=["user_id"], shard_on="user_id")
datastore = friendfeed.datastore.DataStore(
  mysql_shards=["127.0.0.1:3306", "127.0.0.1:3307"],
  indexes=[user_id_index])

new_entity = {
  "id": binascii.a2b_hex("71f0c4d2291844cca2df6f486e96e37c"),
  "user_id": binascii.a2b_hex("f48b0440ca0c4f66991c4d5f6a078eaf"),
  "feed_id": binascii.a2b_hex("f48b0440ca0c4f66991c4d5f6a078eaf"),
  "title": u"We just launched a new backend system for FriendFeed!",
  "link": u"http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c",
  "published": 1235697046,
  "updated": 1235697046,
}
datastore.put(new_entity)
entity = datastore.get(binascii.a2b_hex("71f0c4d2291844cca2df6f486e96e37c"))
entity = user_id_index.get_all(datastore, user_id=binascii.a2b_hex("f48b0440ca0c4f66991c4d5f6a078eaf"))

promation 提升 推广

特别地,系统的延时现在也很稳定(哪怕是在午高峰期间)。如下是过去24小时FriendFeed页面加载延时图。

spatial  空间索引

因此,往数据库中写入实体时我们采用如下步骤:

第一章:

特别的,对 schema 做改动或为超过 1000-2000 万行记录的数据库添加索引会将数据库锁住几个小时。删除旧索引也要占用这么多时间,但不删除它们会影响性能;因为数据库要持续地在每个INSERT上读写这些没用的区块,并将重要的区块挤出了内存。为避免这些问题需要采取一些复杂的措施(例如在从节点上设置新的索引,然后将从节点与主节点对调),但这些措施会引发错误并且实施起来比较困难,它们阻碍了需要改动 schema/索引才能实现的新功能。由于数据库的严重分散,MySQL 的关系特性(如join)对我们没用,所以我们决定脱离 RDBMS。

trade  专业性的

几经思量,我们决定在 MySQL 上采用一种无模式的存储系统,而不是使用一个完全没接触过的存储系统。本文试图描述这个系统的高级细节。我们很好奇其他大型网站是如何处理这些问题的,另外也希望我们完成的某些设计会对其他开发者有所帮助。

model 模型

我们的数据存储会自动为你维护索引,所以如果你要在我们存储上述结构实体的数据存储里开启一个实例,你可以写一段代码(用 python):  

state  状态

我们可以修改数据存储的初始化代码以包含我们的新索引:  

character  字符

虽然已有许多用于解决灵活 schema 数据存储和运行时构建索引的问题(例如 CouchDB)的项目。但在大站点中却没有足够广泛地用到来说服人们使用。在我们看到和运行的测试中,这些项目要么不稳定,要么缺乏足够的测试(参见这个有点过时的关于 CouchDB 的文章)。MySQL 不错,它不会损坏数据;复制也没问题,我们已经了解了它的局限。我们喜欢将 MySQL 用于存储,仅仅是非关系型的存储。

atomicity  原子性

CREATE TABLE index_link (
  link VARCHAR(735) NOT NULL,
  entity_id BINARY(16) NOT NULL UNIQUE,
  PRIMARY KEY (link, entity_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

vehicle  车辆

由于采用分区的数据库,实体的索引可能存储在与实体不同的分区中,这引起了一致性问题。如果进程在写入所有索引表前崩溃了会怎样?

第四章

之所以使用 added_id 个字段是因为 InnoDB 按物理主键顺序存储数据,自增长主键确保新实例在磁盘上按顺序写到老实体之后,这样有助于分区读写(相对老的实体,新实体往往读操作更频繁,因为 FriendFeed 的 pages 是按时间逆序排列)。实体本身经 python 字典序列化后使用 zlib 压缩存储。

第七章

综述

formate  形式

我们索引实体的属性 user_id,这样我们可以渲染一个页面,包含一个已提交用户的所有属性。我们的索引表看起来是这样的:

hotel  旅馆

最终,虽然我们的数据表增多了,但添加和删除索引却变得简单了。我们大力改善了添加索引数据的进程(我们称之为“清洁工")使其在快速添加索引的同时不会影响站点。我们可以在一天内完成新属性的保存和索引,并且我们不需要对调主从MySQL数据库,也不需要任何其他可怕的操作。

invoice   发票

2.根据 entity_id 从 entities 表中读取实体

 

系统到目前为止使用起来很方便。我们在部署之后也改动了几次索引,并且我们也开始将这种模式应用于 MySQL 中那些较大的表,这样我们在以后可以轻松地改动它们的结构。

inner 内部的

一致性与原子性

第二章:

CREATE TABLE index_user_id (
  user_id BINARY(16) NOT NULL,
  entity_id BINARY(16) NOT NULL UNIQUE,
  PRIMARY KEY (user_id, entity_id)
) ENGINE=InnoDB;

networking 网络

我们要记住从索引表中取出的数据可能是不准确的(例如如果写操作没有完成步骤2可能会影响旧属性值)。为确保采用上面的限制能返回正确的实体,我们用索引表来决定要读取哪些实体,但不要相信索引的完整性,要使用查询条件对这些实体进行再过滤:

engine   引擎

图片 10

transaction  事务

您可能感兴趣的文章:

  • MySQL性能全面优化方法参考,从CPU,文件系统选择到mysql.cnf参数优化
  • MySQL性能优化的最佳20+条经验
  • mysql性能优化工具--tuner-primer使用介绍
  • 数据库Mysql性能优化详解
  • MySQL性能参数详解之Skip-External-Locking参数介绍
  • MySQL性能参数详解之Max_connect_errors 使用介绍
  • MySQL性能瓶颈排查定位实例详解
  • Mysql性能优化方案分享
  • Mysql性能优化案例 - 覆盖索引分享
  • Mysql性能优化案例研究-覆盖索引和SQL_NO_CACHE
  • mysql性能优化之索引优化
  • MySQL性能监控软件Nagios的安装及配置教程
  • 19个MySQL性能优化要点解析
  • 详解MySQL性能优化(二)
  • 详解MySQL性能优化(一)
  • 10个MySQL性能调优的方法
  • 浅谈InnoDB隔离模式的使用对MySQL性能造成的影响
  • my.cnf(my.ini)重要参数优化配置说明

subquery  子查询

我们对新系统的主索引进行了优化,对结果也很满意。以下是上个月 FriendFeed 页面的加载延时统计图(我们在前几天启动了新的后端,你可以根据延时的显著回落找到那一天)。

deposit  存款

user_id_index = friendfeed.datastore.Index(
  table="index_user_id", properties=["user_id"], shard_on="user_id")
link_index = friendfeed.datastore.Index(
  table="index_link", properties=["link"], shard_on="link")
datastore = friendfeed.datastore.DataStore(
  mysql_shards=["127.0.0.1:3306", "127.0.0.1:3307"],
  indexes=[user_id_index, link_index])

port   端口号

新建一个索引,比如,在属性 link 上,我们可以创建一个新表:  

第三章

你可以使用索引实例(见上面的 user_id_index.get_all)查询一个索引,使用 python 写的数据存储代码将表 index_user_id 和表 entities 合并。首先在所有数据库分片中查询表 index_user_id 获取实体 ID 列,然后在 entities 提出数据。

 

许多有野心的 FriendFeed 工程师倾向于构建一个事务性协议,但我们希望尽可能地保持系统的简洁。我们决定放宽限制:

query  查询

  •     使用 InnoDB 的 ACID 属性将实体写入 entities 表。
  •     将索引写入所有分区中的索引表。

append  拼接

3.根据实体的真实属性(用 Python)过滤掉不符合查询条件的实体

type  类型

CREATE TABLE entities (
  added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  id BINARY(16) NOT NULL,
  updated TIMESTAMP NOT NULL,
  body MEDIUMBLOB,
  UNIQUE KEY (id),
  KEY (updated)
) ENGINE=InnoDB;

第八章

MySQL 使用表保存我们的实体,一个表就像这样 :  

exists   存在

索引单独存在一张表里,如果要创建索引,我们创建一张新表存储我们想要索引的数据分片的所有属性。例如,一个 FriendFeed 实体通过看上去是这样的:  

 

为保证索引的持久性和一致性,上文提到的“清洁工”进程要持续运行,写入丢失的索引,清理失效的旧索引。它优先清理最近更新的实体,所以实际上维护索引的一致性非常快(几秒钟).
 
性能

JDBC  java数据库连接技术

细节

normal   规范的

constraint   约束

create  创建

access  存储

content  描述

connection  连接

references  参考

collation  校对

isolation 隔离性

 

indentified   被认可的

firewall  防火墙

 

第五章

result set   结果集

 

entity   实体

remark  备注

standard  标准

 

driver  manager   驱动管理器

object  对象

 

diagram  图表 

purchase    购买

guest  客人

temp  临时表

relationship  关系

consistency  一致性

 

index   索引

entity  实体

storage   存储

data   数据

machine  机构

durability  持久性

commit 提交

connectivity   连通性

join 加入、连接

option 选择的

comment  注释

本文由金沙棋牌发布于金沙棋牌app手机下载,转载请注明出处:使用FriendFeed来提升MySQL性能的方法,课前单词

关键词:

上一篇:没有了

下一篇:没有了